C# datagrid tab分割的csv 编码格式 UTF-16格式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# datagrid tab分割的csv 编码格式 UTF-16格式相关的知识,希望对你有一定的参考价值。

C# datagrid tab分割的csv 编码格式 UTF-16格式,
如果单元格内容为空,用空格代替。
将datagrid 内容 导出 tab分割的csv 编码格式 UTF-16格式,

参考技术A StreamWriter sw = new StreamWriter(myStream, System.Text.Encoding.GetEncoding("utf-16"));
string strLine = "";
try

//Write in the headers of the columns.
for (int i = 0; i < dt.Columns.Count; i++)

if (i > 0)
strLine += "\t";
strLine += dt.Columns[i].Caption;

strLine.Remove(strLine.Length - 1);
sw.WriteLine(strLine);
strLine = "";
//Write in the content of the columns.
for (int j = 0; j < dt.Rows.Count; j++)

strLine = "";
for (int k = 0; k < dt.Columns.Count; k++)

if (k > 0)
strLine += "\t";
if (dt.Rows[j][k] == null)
strLine += " ";
else

string m = dt.Rows[j][k].ToString().Trim();
strLine += " ";


strLine.Remove(strLine.Length - 1);
sw.WriteLine(strLine);
//Update the Progess Bar.


sw.Close();
myStream.Close();本回答被提问者采纳

使用 C# 读取 CSV 文件

【中文标题】使用 C# 读取 CSV 文件【英文标题】:Reading CSV files using C# 【发布时间】:2011-03-31 06:24:08 【问题描述】:

我正在编写一个简单的导入应用程序,需要读取一个 CSV 文件,在 DataGrid 中显示结果,并在另一个网格中显示 CSV 文件的损坏行。例如,在另一个网格中显示短于 5 个值的行。我正在尝试这样做:

StreamReader sr = new StreamReader(FilePath);
importingData = new Account();
string line;
string[] row = new string [5];
while ((line = sr.ReadLine()) != null)

    row = line.Split(',');

    importingData.Add(new Transaction
    
        Date = DateTime.Parse(row[0]),
        Reference = row[1],
        Description = row[2],
        Amount = decimal.Parse(row[3]),
        Category = (Category)Enum.Parse(typeof(Category), row[4])
    );

但在这种情况下对数组进行操作非常困难。有没有更好的方法来拆分值?

【问题讨论】:

感谢您的解决方案。考虑将其作为回答帖子发布 - 将其包含在问题中并不能提高其可读性。 另见***.com/questions/1941392/… 【参考方案1】:

不要重新发明***。利用 .NET BCL 中已有的内容。

添加对 Microsoft.VisualBasic 的引用(是的,它显示为 VisualBasic,但它也可以在 C# 中工作 - 请记住,最后它只是 IL) 使用Microsoft.VisualBasic.FileIO.TextFieldParser类解析CSV文件

这里是示例代码:

using (TextFieldParser parser = new TextFieldParser(@"c:\temp\test.csv"))

    parser.TextFieldType = FieldType.Delimited;
    parser.SetDelimiters(",");
    while (!parser.EndOfData) 
    
        //Processing row
        string[] fields = parser.ReadFields();
        foreach (string field in fields) 
        
            //TODO: Process field
        
    

它在我的 C# 项目中非常适合我。

这里有更多链接/信息:

MSDN: Read From Comma-Delimited Text Files in Visual Basic MSDN: TextFieldParser Class

【讨论】:

我真的希望有一种不使用 VB 库的方法,但这非常有效!谢谢! +1:我刚刚在一个 53Mb 文件上破坏了 lumenworks Fast CSV 阅读器。看起来行缓存在 43,000 行后失败并扰乱了缓冲区。尝试了 VB TextFieldParser,它成功了。谢谢 +1 很好的答案,因为我发现很多人不知道这个课程的存在。未来观众需要注意的一件事是,如果您调用 parser.SetDelimiters(",");,则无需设置 parser.TextFieldType = FieldType.Delimited;,因为该方法会为您设置 TextFieldType 属性。 另请查看:dotnetperls.com/textfieldparser。 TextFieldParser 的性能比 String.Split 和 StreamReader 差。但是,string.Split 和 TextFieldParser 之间有很大的区别。 TextFieldParser 处理奇怪的情况,例如列中有逗号:您可以将列命名为"text with quote"", and comma",并且您可以获得正确的值text with quote", and comma,而不是错误分隔的值。因此,如果您的 csv 非常简单,您可能需要选择 String.Split。 请注意,您可能需要添加对 Microsoft.VisualBasic 的引用才能使用它。在 Visual Studio 中右键单击您的项目,然后选择“添加”>“引用”,然后选中 Microsoft.VisualBasic 复选框。【参考方案2】:

我推荐CsvHelper from Nuget。

PS:关于其他更受欢迎的答案,我很抱歉,但添加对 Microsoft.VisualBasic 的引用是:

丑 不是跨平台的,因为它在 .NETCore/.NET5 中不可用(而且 Mono 从来没有很好地支持 Visual Basic,所以它可能有问题)。

【讨论】:

它与 C# 一样跨平台。 错了,Linux中的Microsoft.VisualBasic.dll来自Mono源,与微软的实现不同,还有一些没有实现,例如:***.com/questions/6644165/… (另外,VB 语言在参与创建/开发 Mono 项目的公司中从未受到关注,因此与 C# 生态系统/工具相比,它在努力方面落后了很多。 ) 两者都玩过,我想补充一点,CsvHelper 带有一个内置的行到类映射器;它允许列标题的变化(如果存在),甚至列顺序的明显变化(尽管我自己没有测试过后者)。总而言之,感觉比TextFieldParser 更“高级”。 是的,Microsoft.VisualBasic 命名空间在 .NET Core 2.1 上不可用【参考方案3】:

我的经验是有许多不同的 csv 格式。特别是他们如何处理字段中引号和分隔符的转义。

这些是我遇到的变种:

引号被引用并加倍 (excel) 即 15" -> field1,"15""",field3 除非出于其他原因引用了该字段,否则引号不会更改。即 15" -> field1,15",fields3 引号用\转义。即 15" -> field1,"15\"",field3 引号根本没有改变(这并不总是可以正确解析) 分隔符被引用 (excel)。即 a,b -> field1,"a,b",field3 使用 \ 转义分隔符。即 a,b -> field1,a\,b,field3

我已经尝试了许多现有的 csv 解析器,但没有一个可以处理我遇到的变体。从文档中也很难找出解析器支持哪些转义变体。

在我的项目中,我现在使用 VB TextFieldParser 或自定义拆分器。

【讨论】:

喜欢你提供的测试用例的这个答案! 主要问题是大多数实现并不关心描述 CSV 格式以及应如何转义分隔符的 RFC 4180。 RFC-4180 来自 2005 年,现在看起来很旧,但请记住:.Net 框架于 2001 年首次推出。此外,RFC 并不总是官方标准,在这种情况下它不是t 具有与 ISO-8601 或 RFC-761 相同的重量。【参考方案4】:

当您不想重新发明***时,有时使用库很酷,但在这种情况下,与使用库相比,您可以用更少的代码行和更易于阅读来完成相同的工作。 这是一种我觉得很容易使用的不同方法。

    在本例中,我使用 StreamReader 读取文件 正则表达式检测每行的分隔符。 用于收集从索引 0 到 n 的列的数组

using (StreamReader reader = new StreamReader(fileName))
    
        string line; 

        while ((line = reader.ReadLine()) != null)
        
            //Define pattern
            Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");

            //Separating columns to array
            string[] X = CSVParser.Split(line);

            /* Do something with X */
        
    

【讨论】:

肯定有问题,数据本身包含新行? 现在 CSV 数据文件不知道在数据之间包含空行,但是如果你有一个这样做的源,在这种情况下,我只需简单地做一个简单的正则表达式测试来删除空格或不包含任何内容的行在运行阅读器之前。在此处查看不同的示例:***.com/questions/7647716/… 对于这类问题,基于字符的方法肯定比正则表达式更自然。根据引号的存在,行为应该是不同的。【参考方案5】:

CSV 可以快速真正变得复杂。 使用健壮且经过充分测试的东西: 文件助手: www.filehelpers.net

FileHelpers 是一个免费且易于使用的 .NET 库,用于从文件、字符串或流中的固定长度或分隔记录导入/导出数据。

【讨论】:

我认为 FileHelper 试图一口气做很多事情。解析文件是一个 2 步过程,您首先将行拆分为字段,然后将字段解析为数据。组合这些功能使得处理诸如主从细节和行过滤之类的事情变得困难。【参考方案6】:

此列表中的另一个,Cinchoo ETL - 一个用于读写 CSV 文件的开源库

对于下面的示例 CSV 文件

Id, Name
1, Tom
2, Mark

您可以使用以下库快速加载它们

using (var reader = new ChoCSVReader("test.csv").WithFirstLineHeader())

   foreach (dynamic item in reader)
   
      Console.WriteLine(item.Id);
      Console.WriteLine(item.Name);
   

如果您有与 CSV 文件匹配的 POCO 类

public class Employee

   public int Id  get; set; 
   public string Name  get; set; 

您可以使用它来加载 CSV 文件,如下所示

using (var reader = new ChoCSVReader<Employee>("test.csv").WithFirstLineHeader())

   foreach (var item in reader)
   
      Console.WriteLine(item.Id);
      Console.WriteLine(item.Name);
   

请查看CodeProject的文章了解如何使用它。

免责声明:我是这个库的作者

【讨论】:

您好,您可以将 csv 加载到 Sql 表中吗?我事先不知道 CSV 表中的标题。只需将 csv 中的内容镜像到 Sql 表 是的,你可以。请看这个链接***.com/questions/20759302/…【参考方案7】:

我在这里用这个:

http://www.codeproject.com/KB/database/GenericParser.aspx

上次我在寻找类似的东西时,我发现它是question的答案。

【讨论】:

【参考方案8】:
private static DataTable ConvertCSVtoDataTable(string strFilePath)
        
            DataTable dt = new DataTable();
            using (StreamReader sr = new StreamReader(strFilePath))
            
                string[] headers = sr.ReadLine().Split(',');
                foreach (string header in headers)
                
                    dt.Columns.Add(header);
                
                while (!sr.EndOfStream)
                
                    string[] rows = sr.ReadLine().Split(',');
                    DataRow dr = dt.NewRow();
                    for (int i = 0; i < headers.Length; i++)
                    
                        dr[i] = rows[i];
                    
                    dt.Rows.Add(dr);
                

            

            return dt;
        

        private static void WriteToDb(DataTable dt)
        
            string connectionString =
                "Data Source=localhost;" +
                "Initial Catalog=Northwind;" +
                "Integrated Security=SSPI;";

            using (SqlConnection con = new SqlConnection(connectionString))
                
                    using (SqlCommand cmd = new SqlCommand("spInsertTest", con))
                    
                        cmd.CommandType = CommandType.StoredProcedure;

                        cmd.Parameters.Add("@policyID", SqlDbType.Int).Value = 12;
                        cmd.Parameters.Add("@statecode", SqlDbType.VarChar).Value = "blagh2";
                        cmd.Parameters.Add("@county", SqlDbType.VarChar).Value = "blagh3";

                        con.Open();
                        cmd.ExecuteNonQuery();
                    
                

         

【讨论】:

你从哪里复制这个解决方案?【参考方案9】:

这是我今天编写的一个解决方案,用于在不依赖外部库的情况下解析 CSV。我没有测试大文件的性能,因为它与我的特定用例无关,但我希望它在大多数情况下都能表现得相当好。

        static List<List<string>> ParseCsv(string csv) 
            var parsedCsv = new List<List<string>>();
            var row = new List<string>();
            string field = "";
            bool inQuotedField = false;

            for (int i = 0; i < csv.Length; i++) 
                char current = csv[i];
                char next = i == csv.Length - 1 ? ' ' : csv[i + 1];

                // if current character is not a quote or comma or carriage return or newline (or not a quote and currently in an a quoted field), just add the character to the current field text
                if ((current != '"' && current != ',' && current != '\r' && current != '\n') || (current != '"' && inQuotedField)) 
                    field += current;
                 else if (current == ' ' || current == '\t') 
                    continue; // ignore whitespace outside a quoted field
                 else if (current == '"') 
                    if (inQuotedField && next == '"')  // quote is escaping a quote within a quoted field
                        i++; // skip escaping quote
                        field += current;
                     else if (inQuotedField)  // quote signifies the end of a quoted field
                        row.Add(field);
                        if (next == ',') 
                            i++; // skip the comma separator since we've already found the end of the field
                        
                        field = "";
                        inQuotedField = false;
                     else  // quote signifies the beginning of a quoted field
                        inQuotedField = true; 
                    
                 else if (current == ',')  //
                    row.Add(field);
                    field = "";
                 else if (current == '\n') 
                    row.Add(field);
                    parsedCsv.Add(new List<string>(row));
                    field = "";
                    row.Clear();
                
            

            return parsedCsv;
        

【讨论】:

【参考方案10】:

首先需要了解什么是CSV以及如何编写。

    每个下一个字符串 (/r/n) 都是下一个“表格”行。 “表格”单元格由一些分隔符分隔。最常用的符号是\t, 每个单元格都可能包含此分隔符(在这种情况下,单元格必须以引号符号开头并以此符号结尾) 每个单元格都可能包含/r/n 符号(在这种情况下,单元格必须以引号符号开头并以该符号结尾)

C#/Visual Basic 处理 CSV 文件的最简单方法是使用标准 Microsoft.VisualBasic 库。您只需要在您的类中添加所需的引用和以下字符串:

using Microsoft.VisualBasic.FileIO;

是的,你可以在 C# 中使用它,不用担心。该库可以读取相对较大的文件并支持所有需要的规则,因此您将能够处理所有 CSV 文件。

前段时间,我基于这个库写了一个简单的 CSV 读/写类。使用这个简单的类,您将能够像使用二维数组一样使用 CSV。 您可以通过以下链接找到我的课程: https://github.com/ukushu/DataExporter

简单的使用示例:

Csv csv = new Csv("\t");//delimiter symbol

csv.FileOpen("c:\\file1.csv");

var row1Cell6Value = csv.Rows[0][5];

csv.AddRow("asdf","asdffffff","5")

csv.FileSave("c:\\file2.csv");

【讨论】:

【参考方案11】:

要完成前面的答案,可能需要从他的 CSV 文件中收集一组对象,通过 TextFieldParserstring.Split 方法解析,然后通过反射将每一行转换为一个对象。您显然首先需要定义一个与 CSV 文件的行匹配的类。

我使用了来自 Michael Kropat 的简单 CSV 序列化器,在这里可以找到:Generic class to CSV (all properties) 并重用他的方法来获取希望类的字段和属性。

我使用以下方法反序列化我的 CSV 文件:

public static IEnumerable<T> ReadCsvFileTextFieldParser<T>(string fileFullPath, string delimiter = ";") where T : new()

    if (!File.Exists(fileFullPath))
    
        return null;
    

    var list = new List<T>();
    var csvFields = GetAllFieldOfClass<T>();
    var fieldDict = new Dictionary<int, MemberInfo>();

    using (TextFieldParser parser = new TextFieldParser(fileFullPath))
    
        parser.SetDelimiters(delimiter);

        bool headerParsed = false;

        while (!parser.EndOfData)
        
            //Processing row
            string[] rowFields = parser.ReadFields();
            if (!headerParsed)
            
                for (int i = 0; i < rowFields.Length; i++)
                
                    // First row shall be the header!
                    var csvField = csvFields.Where(f => f.Name == rowFields[i]).FirstOrDefault();
                    if (csvField != null)
                    
                        fieldDict.Add(i, csvField);
                    
                
                headerParsed = true;
            
            else
            
                T newObj = new T();
                for (int i = 0; i < rowFields.Length; i++)
                
                    var csvFied = fieldDict[i];
                    var record = rowFields[i];

                    if (csvFied is FieldInfo)
                    
                        ((FieldInfo)csvFied).SetValue(newObj, record);
                    
                    else if (csvFied is PropertyInfo)
                    
                        var pi = (PropertyInfo)csvFied;
                        pi.SetValue(newObj, Convert.ChangeType(record, pi.PropertyType), null);
                    
                    else
                    
                        throw new Exception("Unhandled case.");
                    
                
                if (newObj != null)
                
                    list.Add(newObj);
                
            
        
    
    return list;


public static IEnumerable<MemberInfo> GetAllFieldOfClass<T>()

    return
        from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
        where new[]  MemberTypes.Field, MemberTypes.Property .Contains(mi.MemberType)
        let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
        orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name
        select mi;            

【讨论】:

【参考方案12】:

我强烈建议使用 CsvHelper。

这是一个简单的例子:

public class csvExampleClass

    public string Id  get; set; 
    public string Firstname  get; set; 
    public string Lastname  get; set; 


var items = DeserializeCsvFile<List<csvExampleClass>>( csvText );

public static List<T> DeserializeCsvFile<T>(string text)

    CsvReader csv = new CsvReader( new StringReader( text ) );
    csv.Configuration.Delimiter = ",";
    csv.Configuration.HeaderValidated = null;
    csv.Configuration.MissingFieldFound = null;
    return (List<T>)csv.GetRecords<T>();

完整文档可在以下位置找到:https://joshclose.github.io/CsvHelper

【讨论】:

以上是关于C# datagrid tab分割的csv 编码格式 UTF-16格式的主要内容,如果未能解决你的问题,请参考以下文章

c# wpf的datagrid列标题间的分割线,我加background后变成一大块黑色的,怎么变成间隔的一块一块的,如图

C# wpf datagrid 动态加载数据后改变单元格颜色bug

c# wpf datagrid 模板列修改某个单元格,更新所选行另一个单元格的值,如何做到呢?

C# 自定义标准 读写CSV文件

C# 自定义标准 读写CSV文件

C# WPF DataGrid获取单元格并改变背景色