【问题标题】:Writing multiple CSV files programmatically以编程方式编写多个 CSV 文件
【发布时间】:2019-01-17 21:52:44
【问题描述】:

我正在编写一个将数据库表写入 CSV 文件的应用程序。由于许多表都有超过一百万条记录,因此我为用户提供了将大表写入每个 25,000 行的文件的选项。我希望用户在 SaveFileDialog 中指定初始文件名,然后为每个写入的新文件附加“-part1”、“-part2”等。在写入所有数据之前,如何以编程方式写入多个文件?下面列出了我要编写的 25,000 行文件的当前代码。

    public void ExportPartition(SaveFileDialog saveFile, DataTable table)
    {
        TextWriter writer = new StreamWriter(saveFile.FileName, true, System.Text.Encoding.ASCII, 1048576);

        for (int i = 0; i <= 25000; i++)
        {
            for (int j = 0; j < table.Columns.Count; j++)
            {
                writer.Write(table.Rows[i][j].ToString() + ",");
            }
            writer.Write("\r\n");
        }
        writer.Flush();
        DisposeObjects(saveFile, writer);
    }

【问题讨论】:

  • 您可能还需要考虑处理已包含逗号的字段,以便导入操作不会失败。
  • 每一行的末尾都应该有逗号吗?
  • 我只是写得很快,我没有注意到行尾的逗号。感谢那。字段中没有任何包含逗号的数据,但为了可重用性,我可能应该解决这个问题。

标签: c# visual-studio-2010 csv


【解决方案1】:
    bool ExportPartition(string fileName, DataTable table, int batchSize, int batchNum)
    {
        string fn = string.Format("{0}-{1}{2}",                                     
                                  Path.GetFileNameWithoutExtension(fileName),
                                  batchNum,
                                  Path.GetExtension(fileName));

        fn = Path.Combine(Path.GetDirectoryName(fileName), fn);

        using (TextWriter writer = new StreamWriter(fn))
        {
            int start = batchNum * batchSize;
            int end = start + batchSize;

            for (int i = start; i < end; i++)
            {
                if (i >= table.Rows.Count)
                    break;

                for (int j = 0; j < table.Columns.Count; j++)
                {
                    writer.Write(table.Rows[i][j] + ",");
                }
                writer.Write("\r\n");
            }

            return table.Rows.Count <= end;
        }
    }

用法:

    void WriteFiles(DataTable table, String fileName, int batchSize)
    {
        int batchNum = 0;          
        bool done = false;
        while (!done)
        {
            done = ExportPartition(fileName, table, batchSize, batchNum++);
        }
    }

    void Main()
    {
        DataTable dt = GetData();
        string fileName = GetFileNameWithSaveDialog(); 
        int batchSize = 25000;
        WriteFiles(dt, fileName, batchSize);
    }

【讨论】:

  • 我已经实现了这个,但是它在 TextWriter 构造函数上抛出了一个 IO 异常。这是错误消息:该进程无法访问文件“C:\Users\afannin1\Equipment\HBSSensorDataClient\HBSDataClient\HBSDataClient\bin\Debug\Partitions--0..csv”,因为它正被另一个进程使用。
  • 您是否在文件名 (..csv) 中看到两个点?扩展名可能包括点,我将更新格式字符串。正在使用的文件感觉很奇怪,您是否在另一个应用程序中打开它(例如文本编辑器,或程序的先前运行实例)?
  • 我能够解决这个问题和扩展问题。应用程序现在正在写入文件,但实现中使用的 while 循环并未终止。
  • @Andrew,我更新了语法和用例。首先,它将文件名作为字符串传递,而不是整个对话框(无论如何我们都不能在循环中处理它,所以我也将写入器更改为 using{})。文件名现在还使用输入文件名中的目录名(如果它是完整路径)。我在一些虚拟数据上编译并运行了这些方法。 (完整源代码pastebin.com/Y3tXUJgL
【解决方案2】:

另一种解决方案:

class Program
{
    static void Main(string[] args)
    {
        DataTable dt = new DataTable();
        dt.Columns.Add("Col1");
        dt.Columns.Add("Col2");
        for (int i = 0; i < 103; ++i)
        {
            var r = dt.NewRow();
            r[0] = Guid.NewGuid().ToString();
            r[1] = i.ToString();
            dt.Rows.Add(r);
        }
        WriteCsvFile(dt, 25, @"C:\temp\test.txt");
    }

    public static string[] ToStringArray(DataRow row)
    {
        var arr = new string[row.Table.Columns.Count];
        for (int j = 0; j < arr.Length; j++)
        {
            arr[j] = row[j].ToString();
            if((arr[j]??"").Contains(","))
                throw new Exception("This will end badly...");
        }
        return arr;
    }

    public static void WriteCsvFile(DataTable table, int maxCount, string fileName)
    {
        if (table.Rows.Count <= maxCount)
            WriteCsvFile(table, maxCount, fileName, 0);
        else
            for (int i = 0; i < (table.Rows.Count / maxCount + 1); ++i)
            {
                var partFileName = Path.Combine(Path.GetDirectoryName(fileName), string.Format("{0}-part{1}{2}", Path.GetFileNameWithoutExtension(fileName), i+1, Path.GetExtension(fileName)));
                WriteCsvFile(table, maxCount, partFileName, i * maxCount);
            }
    }

    public static void WriteCsvFile(DataTable table, int maxCount, string fileName, int startIndex)
    {
        using(var fs = File.Create(fileName))
        using(var w = new StreamWriter(fs, Encoding.ASCII))
        {
            for (int i = startIndex; i < Math.Min(table.Rows.Count, startIndex + maxCount); i++)
                w.WriteLine(String.Join(",", ToStringArray(table.Rows[i])));
            w.Flush();
        }
    }
}

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 2017-02-01
    • 2016-01-03
    相关资源
    最近更新 更多