CsvHelper、SqlBulkCopy、制作拙劣的 CSV 文件

如何解决CsvHelper、SqlBulkCopy、制作拙劣的 CSV 文件

重新表述之前的问题,因为它过于笼统。我正在尝试将 CsvHelper 与 sqlBulkcopy 和制作不良的 CSV 文件一起使用。

问题是如何将格式不佳的 Csv 文件(没有 col 标头、类型转换、引用删除等)读取到可以传递给 sqlBulkcopy 的数据表中?

  • 最初的尝试是使用 CsvDataReader。不幸的是一些 列(日期、日期时间)需要重新格式化。使用时 CsvDataReader 格式丢失。
  • 可以使用 GetRecord var record = csv.GetRecord<Foo>() 干净地解析文件,但由于 Csv 文件结构,从那里进入数据表一直具有挑战性。它还基本上让我映射文件布局 4 次(<Foo><FooMAP>、数据表创建,并在填充数据表行时再次映射(这是我努力处理返回的行)。立>

我喜欢类和类映射方法,但在我的使用中,列名真正重要的唯一地方是数据表和 sqlBulkcopy。我是否可以不只是构建具有正确结构的数据表,然后使用 GetField 之类的东西通过索引构建数据行列并进行任何必要的类型转换?我尝试了多次迭代,但编译只会进入 lala land。

我确信这可以更有效地完成,但我的 C# 技能有限,因此寻求有关执行此操作的最佳方法的一些建议。不是要求用勺子喂食,但确实需要一些细节(对不起和 tia)。

下面是一个数据文件的片段,并没有组织好代码示例。每天早上将收到多个文件,行数为 +50M(+10GB)。这将只需要每次调用处理 1 个文件。他们来自一个合作伙伴,不幸的是,在试图让他们重新格式化时,我的手被束缚了。

CSV 文件示例

A,STRINGER,THAT,ISN'T,A,HEADER,RECORD,OR,SAME,COLUMN,COUNT,"""ROW"" 1","20000101",1,"DCBDA","AC",20011213,+45821.41,23,"ROW" 2","DBDDA ","AC ","0002K5A9V8U8V357JK","AGDDA",20120117,-821.41," ","2016-12-21-08.53.05.857000"
"0002K5A9V8UAU499IO","20000102","ARDDA",-175000.00,"2016-12-21-08.53.06.024000"
"0002K5A9V8UCT5DBHS","20000103","RGDDA",+4821.41,"2016-12-21-08.53.06.030000"

Code Snip(有点粗糙但很容易在没有数据表的情况下工作)

        public class CSVReader
        // Read a CSV file returning a DataTable.
        // Primary intent is for use with sqlBulkcopy but can be used for more.
        {
            static void Main()
            {
                string rfile = @"C:\BAL-CsvReader2.txt";
                var fileType = @"BAL";            
    
                string connString = @"xx";
                var destTable = @"[DBO].[BAL1]";
                var batchSize = 5;
    
                List<string> ErrRecords = new();
                var isBadRecord = false;
                var goodCount = 0;
                var badCount = 0;
                var rconfig = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)
                {
                    BufferSize = 1024,Delimiter = ",",AllowComments = true,HasHeaderRecord = false,HeaderValidated = null,IgnoreBlankLines = true,MissingFieldFound = null,Comment = '#',Escape = '"',BadDataFound = x =>
                    {
                        isBadRecord = true;
                        ErrRecords.Add(x.RawRecord);
                        ++badCount;
                        isBadRecord = false;
                    }
                };
    
                var dt = new DataTable();
                using (var reader = new StreamReader(rfile))
                {
                    reader.ReadLine();  //Get past non-header header
                    using (var csv = new CsvReader(reader,rconfig))
                    {
                                csv.Context.RegisterClassMap<BALMap>();
                                var balRecords = new List<BAL>();
    
                                dt.Columns.Add(new DataColumn("BALID",typeof(string)));
                                dt.Columns.Add(new DataColumn("NUMBERA",typeof(string)));
                                dt.Columns.Add(new DataColumn("NUMBERB",typeof(int)));
                                dt.Columns.Add(new DataColumn("APPLICATIONCODE",typeof(string)));
                                dt.Columns.Add(new DataColumn("STATUS",typeof(string)));
                                dt.Columns.Add(new DataColumn("BALDATE",typeof(DateTime)));
                                dt.Columns.Add(new DataColumn("TRIALBALANCE",typeof(decimal)));
                                dt.Columns.Add(new DataColumn("PENDING",typeof(decimal)));
                                dt.Columns.Add(new DataColumn("CREDITS",typeof(decimal)));
                                dt.Columns.Add(new DataColumn("PENDCRED",typeof(decimal)));
                                dt.Columns.Add(new DataColumn("BATCH",typeof(int)));
                                dt.Columns.Add(new DataColumn("MCODE",typeof(string)));
                                dt.Columns.Add(new DataColumn("RECORDTIMESTAMP",typeof(DateTime)));
    
                                foreach (DataColumn col in dt.Columns)
                                {
                                    dt.Columns[col.ColumnName].Allowdbnull = true;
                                }
    
    // Data doesn't have headers.
    
    
                                var valueTypes = new Type[dt.Columns.Count];
                                for (int i = 0; i < valueTypes.Length; i++)
                                {
                                    var dc = dt.Columns[i];
                                    var type = dc.DataType;
                                    if (dc.Allowdbnull && type.IsValueType)
                                        type = typeof(Nullable<>).MakeGenericType(type);
                                    valueTypes[i] = type;
                                }
                                var valueBuffer = new object[valueTypes.Length];
                                dt.BeginLoadData();
                                while (csv.Read())
                                {
                                    var record = csv.GetRecord<BAL>();
                                    if (!isBadRecord)
                                    {
                                        
    
    // Using this doesn't work as it pulls from the CSV reader rather than record so it doesn't get the date/time formating which then causes it to fail. 
                                        for (int i = 0; i < valueBuffer.Length; i++)
                                        valueBuffer[i] = csv.GetField(valueTypes[i],i);
                                        dt.LoadDaTarow(valueBuffer,true);
    
    //                                    dt.Rows.Add(row);
    //                                    bulkcopy.WritetoServer(dt);
                                        balRecords.Add(record);
                                        ++goodCount;
    
                                    }
                                }
                                dt.EndLoadData();
                                isBadRecord = false;
                    }
                }
            }
        };
    
        public class BAL        // BAL SOURCE
        {
            [Index(0)]
            public string BALID { get; set; }
            [Index(1)]
            public string NUMBERA { get; set; }
            [Index(2)]
            public int? NUMBERB { get; set; }
            [Index(3)]
            public string APPLICATIONCODE { get; set; }
            [Index(4)]
            public string STATUS { get; set; }
            [Index(5)]
            public DateTime? BALDATE { get; set; }
            [Index(6)]
            public decimal? TRIALBALANCE { get; set; }
            [Index(7)]
            public decimal? PENDING { get; set; }
            [Index(8)]
            public decimal? CREDITS { get; set; }
            [Index(9)]
            public decimal? PENDCRED { get; set; }
            [Index(10)]
            public int? BATCH { get; set; }
            [Index(11)]
            public string MCODE { get; set; }
            [Index(12)]
            public DateTime? RECORDTIMESTAMP { get; set; }
        }
    
        public sealed class BALMap : ClassMap<BAL>
        {
            public BALMap()
            {
                // AutoMap(CultureInfo.InvariantCulture);
                Map(m => m.BALID).Index(0);
                Map(m => m.NUMBERA).Index(1);
                Map(m => m.NUMBERB).Index(2);
                Map(m => m.APPLICATIONCODE).Index(3);
                Map(m => m.STATUS).Index(4);
                Map(m => m.BALDATE).Index(5).TypeConverterOption.Format("yyyyMMdd");
                Map(m => m.TRIALBALANCE).Index(6);
                Map(m => m.PENDING).Index(7);
                Map(m => m.CREDITS).Index(8);
                Map(m => m.PENDCRED).Index(9);
                Map(m => m.BATCH).Index(10);
                Map(m => m.MCODE).Index(11);
                Map(m => m.RECORDTIMESTAMP).Index(12).TypeConverterOption.Format("yyyy-MM-dd-hh.mm.ss.ffffff");
            }
        }

更新:1 仍然没有想出如何使用 GetField 遍历行(我的愚蠢挑战 - 下面的第一个片段),但已经想出了如何使用类动态创建数据(下面的第二个片段)。

   while (csv.Read())
   {
       var row = dt.NewRow();
       object[] values = new object[props.Count];
       foreach (var item in props)
       {
           for (int i = 0; i < values.Length; i++)
           {
               **values[i] = csv.GetField<Foo>(i);**
           }
           dt.Rows.Add(row);
   PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(Foo));
   DataTable dt = new DataTable();
   for (int i = 0; i < props.Count; i++)
   {
       PropertyDescriptor prop = props[i];
       if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDeFinition() == typeof(Nullable<>))
           dt.Columns.Add(prop.Name,prop.PropertyType.GetGenericArguments()[0]);
       else
           dt.Columns.Add(prop.Name,prop.PropertyType);
   }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?