【问题标题】:What would be the fastest way to concatenate three files in C#?在 C# 中连接三个文件的最快方法是什么?
【发布时间】:2010-10-01 10:53:04
【问题描述】:

我需要使用 C# 连接 3 个文件。头文件、内容和页脚文件,但我想尽其所能。

酷 = 非常小的代码或非常快(非汇编代码)。

【问题讨论】:

  • “酷”代码听起来很危险地接近“聪明”代码。这可能是一个有趣的新奇事物,但如果它更难阅读、维护、调试、测试等,从长远来看就不值得。
  • C#中没有汇编代码...
  • 可以,但您可以在 C# 程序中使用汇编代码
  • 代码不会成为瓶颈,而是你与磁盘的对话方式。不要写很酷的代码。编写易于阅读和维护的代码。这更酷!
  • “非常小的代码或非常快”——只有我认为这听起来不对吗?

标签: c# file


【解决方案1】:

我支持 Mehrdad Afshari,因为他的代码与 System.IO.Stream.CopyTo 中使用的代码完全相同。 我仍然想知道他为什么不使用相同的功能而不是重写它的实现。

string[] srcFileNames = { "file1.txt", "file2.txt", "file3.txt" };
string destFileName = "destFile.txt";

using (Stream destStream = File.OpenWrite(destFileName))
{
    foreach (string srcFileName in srcFileNames)
    {
        using (Stream srcStream = File.OpenRead(srcFileName))
        {
            srcStream.CopyTo(destStream);
        }
    }
}

根据反汇编程序 (ILSpy),默认缓冲区大小为 4096。CopyTo 函数有过载,如果您对 4096 字节不满意,您可以指定缓冲区大小。

【讨论】:

  • 很好的答案。这正是我所需要的。
  • 每个文件都需要关闭srcStream吗?
  • @rraallvv 不是当你使用using 时,OP 在他的回答中写道,然后它会被自动清理
【解决方案2】:
void CopyStream(Stream destination, Stream source) {
   int count;
   byte[] buffer = new byte[BUFFER_SIZE];
   while( (count = source.Read(buffer, 0, buffer.Length)) > 0)
       destination.Write(buffer, 0, count);
}


CopyStream(outputFileStream, fileStream1);
CopyStream(outputFileStream, fileStream2);
CopyStream(outputFileStream, fileStream3);

【讨论】:

  • 我不觉得这很聪明。什么是好的 BUFFER_SIZE?没人知道。与 File.ReadAllText(a) + File.ReadAllText(b) + File.ReadAllText(c) 相比,这对我来说似乎是过早的优化。
  • 取决于文件的大小。您不想使用 ReadAllText 方法连接几百兆字节。
  • 我同意。但是在这种情况下,我真的会把这样的任务留给编写库的专家,或者,就像我的想法一样,猫程序。我当然不会用公平的掷骰子给我的一些块大小来逐块阅读它。
  • 其实这是传统的复制流的方法。一个好的缓冲区大小取决于具体情况,但可能至少必须是块大小的倍数。请记住,文件大小很容易超过 32 位整数最大值;)
  • 顺便说一句,抛开性能不谈,除非您正在处理文本文件,否则ReadAllText 绝对不是要走的路。您可以在将文件读入字符串时破坏文件的内容。
【解决方案3】:

如果您的文件是文本且不大,那么对于非常简单、明显的代码,有话要说。我会使用以下内容。

File.ReadAllText("file1") + File.ReadAllText("file2") + File.ReadAllText("file3");

如果您的文件是大型文本文件并且您使用的是 Framework 4.0,则可以使用 File.ReadLines 来避免缓冲整个文件。

File.WriteAllLines("out", new[] { "file1", "file2", "file3" }.SelectMany(File.ReadLines));

如果您的文件是二进制文件,请参阅Mehrdad's answer

【讨论】:

  • 免责声明:不适用于大文件。请参阅 Mehrdad Afshari 的代码,了解接下来该做什么。
  • 这看起来需要大量内存来将所有三个文件作为字符串保存在内存中,更不用说通过添加前两个生成的中间字符串对象和通过添加最后。
  • 吉米,你用你自己的免责声明打败了我! :)
  • 1) 连接字符串不是好的做法。您应该使用字符串生成器。 2) 这不是二进制文件的好解决方案。
  • @TcKs: 1) 这里的内联连接由 string.concat(a,b,c) 在一次操作中完成,开销低于 stringbuilder 2) 我假设“页眉/内容/页脚”文件是文本。
【解决方案4】:

另一种方式......让操作系统为你做这件事怎么样?:

ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", 
        String.Format(@" /c copy {0} + {1} + {2} {3}", 
            file1, file2, file3, dest));
psi.UseShellExecute = false;
Process process = Process.Start(psi);
process.WaitForExit();

【讨论】:

  • 无论如何你都让操作系统来做,除非你在裸机上运行。但是,除非迫切需要,否则不应该这样做。
【解决方案5】:

你的意思是 3 个文本文件??结果是否需要再次成为文件?

比如:

string contents1 = File.ReadAllText(filename1);
string contents2 = File.ReadAllText(filename2);
string contents3 = File.ReadAllText(filename3);

File.WriteAllText(outputFileName, contents1 + contents2 + contents3);

当然,使用 StringBuilder 和一些额外的智能,您可以轻松扩展它以处理任意数量的输入文件 :-)

干杯

【讨论】:

  • 这将强制将所有文件的内容加载到内存中。如果您有大文件,这是非常低效的,因为您可能会将对象强制放入大对象堆中。使用缓冲区将避免垃圾收集的需要,并且几乎肯定会提高性能。
【解决方案6】:

如果您在Win32 环境中,最有效的解决方案可能是使用 Win32 API 函数“WriteFile”。 VB 6中有一个example,但是用C#重写它并不难。

【讨论】:

    猜你喜欢
    • 2014-03-19
    • 1970-01-01
    • 2014-01-20
    • 2021-02-17
    • 2011-07-01
    • 2011-11-15
    • 1970-01-01
    • 2016-08-11
    • 2015-05-29
    相关资源
    最近更新 更多