.NET C# 读写CSV及转换DataTable

目录

  • [.NET C# 读写CSV及转换DataTable](# 读写CSV及转换DataTable)
    • [1. 依赖库](#1. 依赖库)
    • [2. CSVUtil](#2. CSVUtil)
      • [2.1 CSV 转 DataTable](#2.1 CSV 转 DataTable)
      • [2.2 DataTable 转 CSV 文本](#2.2 DataTable 转 CSV 文本)
      • [2.3 DataTable 转 CSV](#2.3 DataTable 转 CSV)
      • [2.4 私有方法](#2.4 私有方法)

.NET C# 读写CSV及转换DataTable

1. 依赖库

csharp 复制代码
using System.Data;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

2. CSVUtil

2.1 CSV 转 DataTable

csharp 复制代码
/// <summary>
/// CSV 转 DataTable
/// </summary>
/// <param name="csvFilePath">CSV文件路径</param>
/// <param name="separator">间隔符,默认为","</param>
/// <returns>结果DataTable</returns>
public static DataTable? FromCSV(string csvFilePath, string separator = ",")
{
    DataTable dt = new DataTable();
    string separatorTemp = Guid.NewGuid().ToString().Replace("-", "");
    List<string[]?> lineArrayList = ReadCsvLines(csvFilePath, separator, separatorTemp);
    if (lineArrayList.Count < 1)
    {
        return null;
    }

    int maxColumnCount = 0;
    lineArrayList.ForEach(l =>
    {
        if(l != null && l.Length > maxColumnCount)
        {
            maxColumnCount = l.Length;
        }
    });

    string[]? headerLineArray = lineArrayList[0];
    for (int columnIdx = 0; columnIdx < maxColumnCount; columnIdx++)
    {
        string? columnName = null;
        if (headerLineArray != null && headerLineArray.Length > columnIdx)
        {
            columnName = headerLineArray[columnIdx]?.Trim('"')?.Replace(separatorTemp, separator);
        }
        if (string.IsNullOrEmpty(columnName))
        {
            columnName = $"column_{columnIdx + 1}";
        }
        string columnNameTemp = columnName;
        int tag = 0;
        while (dt.Columns.Contains(columnNameTemp))
        {
            columnNameTemp = $"{columnName}_{++tag}";
        }
        dt.Columns.Add(columnNameTemp);
    }
    for (int rowIdx = 1; rowIdx < lineArrayList.Count; rowIdx++)
    {
        string[]? lineArray = lineArrayList[rowIdx];
        DataRow dataRow = dt.NewRow();
        for (int columnIdx = 0; columnIdx < maxColumnCount; columnIdx++)
        {
            if (lineArray != null && lineArray.Length > columnIdx)
            {
                dataRow[columnIdx] = lineArray[columnIdx]?.Trim('\"')?.Replace(separatorTemp, separator);
            }
        }
        dt.Rows.Add(dataRow);
    }
    return dt;
}

2.2 DataTable 转 CSV 文本

csharp 复制代码
/// <summary>
/// DataTable 转 CSV 文本
/// </summary>
/// <param name="dt">DataTable实例</param>
/// <param name="separator">间隔符,默认为","</param>
/// <returns>CSV 文本</returns>
public static string ToCsvText(DataTable dt, string separator = ",")
{
    string csvText = string.Empty;
    string currentLine = string.Empty;
    for (int columnIdx = 0; columnIdx < dt.Columns.Count; columnIdx++)
    {
        currentLine += $"\"{dt.Columns[columnIdx].ColumnName}\"{separator}";
    }
    currentLine = currentLine[..^separator.Length];
    csvText += currentLine;

    for (int rowIdx = 0; rowIdx < dt.Rows.Count; rowIdx++)
    {
        currentLine = string.Empty;
        for (int columnIdx = 0; columnIdx < dt.Columns.Count; columnIdx++)
        {
            currentLine += $"\"{dt.Rows[rowIdx][columnIdx]}\"{separator}";
        }
        currentLine = currentLine[..^separator.Length];
        csvText += Environment.NewLine + currentLine;
    }
    return csvText;
}

2.3 DataTable 转 CSV

csharp 复制代码
/// <summary>
/// DataTable 转 CSV
/// </summary>
/// <param name="dt">DataTable实例</param>
/// <param name="csvFilePath">CSV文件路径</param>
/// <param name="separator">间隔符,默认为","</param>
/// <param name="cover">覆盖CSV文件,默认为True,若仅追加,则传False</param>
public static void ToCSV(DataTable dt, string csvFilePath, string separator = ",", bool cover = true)
{
    FileStream? fs = null;
    StreamWriter? sw = null;
    string csvText = ToCsvText(dt, separator);
    try
    {
        if (!File.Exists(csvFilePath) || cover)
        {
            fs = new FileStream(csvFilePath, FileMode.Create, FileAccess.Write);
            sw = new StreamWriter(fs, Encoding.UTF8);
        }
        else
        {
            fs = new FileStream(csvFilePath, FileMode.Append, FileAccess.Write);
            sw = new StreamWriter(fs, Encoding.UTF8);
            sw.WriteLine();
        }
        sw.Write(csvText);
    }
    catch (Exception ex)
    {
        // 异常处理...
    }
    finally
    {
        try { sw?.Close(); } catch { }
        try { fs?.Close(); } catch { }
    }
}

2.4 私有方法

csharp 复制代码
private static List<string[]?> ReadCsvLines(string csvFilePath, string separator, string separatorTemp)
{
    FileStream? fs = null;
    StreamReader? sr = null;
    List<string[]?> lineArrayList = new List<string[]?>();
    try
    {
        fs = new FileStream(csvFilePath, FileMode.Open, FileAccess.Read);
        sr = new StreamReader(fs, Encoding.UTF8);
        string? currentLine = string.Empty;
        string[]? lineArray = null;
        while (!string.IsNullOrEmpty(currentLine = sr.ReadLine()))
        {
            currentLine = currentLine.Trim();
            if (currentLine.Contains('"'))
            {
                Regex regex = new Regex("\"(.*?)\"");
                MatchCollection matches = regex.Matches(currentLine);
                int offset = 0;
                foreach (Match match in matches.Cast<Match>())
                {
                    Group group = match.Groups[1];
                    if (group.Value.Contains(separator))
                    {
                        string replaceText = group.Value.Replace(separator, separatorTemp);
                        currentLine = currentLine.Remove(group.Index + offset, group.Length);
                        currentLine = currentLine.Insert(group.Index + offset, replaceText);
                        offset = offset + replaceText.Length - group.Length;
                    }
                }
            }
            lineArray = currentLine.Split(separator);
            lineArrayList.Add(lineArray);
        }
    }
    catch (Exception ex)
    {
        // 异常处理...
    }
    finally
    {
        try { sr?.Close(); } catch { }
        try { fs?.Close(); } catch { }
    }
    return lineArrayList;
}
相关推荐
浅陌sss21 分钟前
设计模式 --- 装饰器模式
设计模式·c#
du fei43 分钟前
C# 单例模式
java·单例模式·c#
爱吃巧克力的程序媛1 小时前
C# 的 字符串插值($) 和 逐字字符串(@) 功能
c#
爱编程的鱼2 小时前
C# 封装教程
开发语言·c#
tiegenZ4 小时前
C#接口开发异常:System.Web.HttpRequestValidationException
服务器·安全·c#
冒泡P5 小时前
C#常用LINQ
开发语言·c#·linq
佟格湾7 小时前
聊透多线程编程-线程互斥与同步-12. C# Monitor类实现线程互斥
c#·多线程
时光追逐者9 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 35 期(2025年4.14-4.20)
c#·.net·.netcore
@蓝莓果粒茶10 小时前
LeetCode第158题_用Read4读取N个字符 II
前端·c++·python·算法·leetcode·职场和发展·c#
码观天工11 小时前
.NET 原生驾驭 AI 新基建实战系列(四):Qdrant ── 实时高效的向量搜索利器
c#·.net·向量数据库·qdrant