繁体   English   中英

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

[英]How to merge efficiently gigantic files with C#

我有超过 125 个大约 100Mb 的 TSV 文件要合并。 允许合并操作破坏 125 个文件,但不能破坏数据。 关键是那一个结尾,我最后得到了一个大文件,所有文件的内容一个接一个(没有特定的顺序)。

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

谢谢!

那么“合并”真的只是一个接一个地写入文件吗? 这非常简单——只需打开一个输出流,然后重复打开一个输入流,复制数据,然后关闭。 例如:

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);
            }
        }
    }
}

这是使用Stream.CopyTo方法,它是 .NET 4 中的新方法。如果您不使用 .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);
    }
}

据我所知,没有什么比这更有效的了……但重要的是,这根本不会占用您系统上的太多内存。 它不像是反复将整个文件读入内存然后再次将其全部写出。

编辑:正如在评论中指出,有办法,你可以用文件选项捣鼓可能使它稍微在什么样的文件系统中的数据确实方面是高效。 但从根本上讲,无论哪种方式,您都将读取数据并写入数据,一次一个缓冲区。

从命令行执行:

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

或者

copy *.txt combined.txt

你的意思是合并你想用一些自定义逻辑来决定哪些行去哪里? 或者您的意思是您主要想将文件连接成一个大文件?

在后者的情况下,您可能根本不需要以编程方式执行此操作,只需使用此生成一个批处理文件( /b用于二进制文件,如果不需要,请删除):

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);

你为什么要这样做?

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

这是C#的包装器。

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

使用一个包含 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 方法

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM