如何使用C#有效地合并巨大的文件

时间:2010-08-24 13:14:15

标签: c# file-io filesystems

我有超过125个TSV文件,每个我想要合并约100Mb。合并操作允许销毁125个文件,但不能销毁数据。什么事情是最后,我最终得到一个接一个的所有文件的内容的大文件(没有特定的顺序)。

有没有一种有效的方法呢?我想知道Windows是否提供了一个API来简单地创建所有这些文件的大“联盟”?否则,我将不得不阅读所有文件并写一个大文件。

谢谢!

5 个答案:

答案 0 :(得分:17)

所以“合并”实际上只是一个接一个地写文件?这非常简单 - 只需打开一个输出流,然后重复打开输入流,复制数据,关闭。例如:

static void ConcatenateFiles(string outputFile, params string[] inputFiles)
{
    using (Stream output = File.OpenWrite(outputFile))
    {
        foreach (string inputFile in inputFiles)
        {
            using (Stream input = File.OpenRead(inputFile))
            {
                input.CopyTo(output);
            }
        }
    }
}

那是使用.NET 4中新增的Stream.CopyTo方法。如果你不使用.NET 4,另一个帮助方法会派上用场:

private static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}

我所知道的没有什么比这更有效......但重要的是,这根本不会占用你系统的大量内存。这并不是说它反复将整个文件读入内存然后再写出来。

编辑:正如评论中所指出的,有些方法可以将文件选项摆弄到潜在的,使其在文件系统对数据的作用方面稍微提高效率。但从根本上说,无论哪种方式,你都会读取数据并一次写入缓冲区。

答案 1 :(得分:2)

从命令行执行此操作:

copy 1.txt+2.txt+3.txt combined.txt

copy *.txt combined.txt

答案 2 :(得分:2)

你的意思是 merge 你想用一些自定义逻辑决定哪些行去哪里?或者你的意思是你主要想把文件连成一个大文件?

对于后者,您可能根本不需要以编程方式执行此操作,只需生成一个批处理文件(/b表示二进制,如果不需要则删除):< / p>

copy /b "file 1.tsv" + "file 2.tsv" "destination file.tsv"

使用C#,我采取以下方法。编写一个复制两个流的简单函数:

void CopyStreamToStream(Stream dest, Stream src)
{
    int bytesRead;

    // experiment with the best buffer size, often 65536 is very performant
    byte[] buffer = new byte[GOOD_BUFFER_SIZE];

    // copy everything
    while((bytesRead = src.Read(buffer, 0, buffer.Length)) > 0)
    {
        dest.Write(buffer, 0, bytesRead);
    }
}

// then use as follows (do in a loop, don't forget to use using-blocks)
CopStreamtoStream(yourOutputStream, yourInputStream);

答案 3 :(得分:0)

你为什么要这样做?

一种方法可能是摆弄低级碎片,如果你让它工作就会很酷。

这是C#的包装器。

http://blogs.msdn.com/b/jeffrey_wall/archive/2004/09/13/229137.aspx

答案 4 :(得分:0)

使用一个100MB的文本文件文件夹,总计约12GB,我发现通过使用File.ReadAllBytes,然后将其写到流中,可以在可接受的答案上节省一些时间。

        [Test]
        public void RaceFileMerges()
        {
            var inputFilesPath = @"D:\InputFiles";
            var inputFiles = Directory.EnumerateFiles(inputFilesPath).ToArray();

            var sw = new Stopwatch();
            sw.Start();

            ConcatenateFilesUsingReadAllBytes(@"D:\ReadAllBytesResult", inputFiles);

            Console.WriteLine($"ReadAllBytes method in {sw.Elapsed}");

            sw.Reset();
            sw.Start();

            ConcatenateFiles(@"D:\CopyToResult", inputFiles);

            Console.WriteLine($"CopyTo method in {sw.Elapsed}");
        }

        private static void ConcatenateFiles(string outputFile, params string[] inputFiles)
        {
            using (var output = File.OpenWrite(outputFile))
            {
                foreach (var inputFile in inputFiles)
                {
                    using (var input = File.OpenRead(inputFile))
                    {
                        input.CopyTo(output);
                    }
                }
            }
        }

        private static void ConcatenateFilesUsingReadAllBytes(string outputFile, params string[] inputFiles)
        {
            using (var stream = File.OpenWrite(outputFile))
            {
                foreach (var inputFile in inputFiles)
                {
                    var currentBytes = File.ReadAllBytes(inputFile);
                    stream.Write(currentBytes, 0, currentBytes.Length);
                }
            }
        }
  

00:01:22.2753300中的ReadAllBytes方法

     

00:01:30.3122215中的CopyTo方法

我重复了多次,结果相似。