如何在C#中编写超快的文件流代码?

15 浏览
0 Comments

如何在C#中编写超快的文件流代码?

我需要将一个巨大的文件拆分成许多小文件。每个目标文件由偏移量和字节数长度来定义。我正在使用以下代码:

private void copy(string srcFile, string dstFile, int offset, int length)
{
    BinaryReader reader = new BinaryReader(File.OpenRead(srcFile));
    reader.BaseStream.Seek(offset, SeekOrigin.Begin);
    byte[] buffer = reader.ReadBytes(length);
    BinaryWriter writer = new BinaryWriter(File.OpenWrite(dstFile));
    writer.Write(buffer);
}

考虑到我需要调用这个函数大约10万次,它的速度非常慢。

2. 是否有办法使Writer直接连接到Reader?(也就是说,不实际将内容加载到内存中的缓冲区中)

0
0 Comments

问题的出现原因是:在C#中进行文件I/O操作时,使用Windows的ReadFile和WriteFile函数是最快的方法。

解决方法是:作者编写了一个C#类来封装这种能力,并编写了一个基准测试程序,包括对不同的I/O方法进行测试,包括BinaryReader和BinaryWriter。

以下是一篇关于如何在C#中编写超快速文件流代码的文章:

C#中写超快速文件流代码的方法

C#中执行文件输入/输出(I/O)操作的最快方法是使用Windows的ReadFile和WriteFile函数。为了方便使用这些函数,作者编写了一个C#类来封装这种能力,并开发了一个基准测试程序,用于比较不同的I/O方法,包括BinaryReader和BinaryWriter。

为了更好地理解这个问题,可以参考作者的博客文章链接:http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp/

在这篇文章中,作者提供了详细的博客信息,包括如何使用ReadFile和WriteFile函数进行文件I/O操作的示例代码。读者可以通过阅读这篇博客文章了解如何编写高效的文件流代码,并根据自己的需求选择最适合的I/O方法。

在C#中进行文件I/O操作时,使用Windows的ReadFile和WriteFile函数是最快的方法。作者通过编写一个C#类和一个基准测试程序,向读者展示了如何使用这些函数以及其他I/O方法,以提高文件流代码的执行效率。读者可以通过参考作者的博客文章,学习如何编写超快速的文件流代码,并根据自己的需求选择适合的I/O方法。

0
0 Comments

如何在C#中编写超快的文件流代码?

在.NET中没有任何内容可以允许在不将其缓存在内存中的情况下复制文件的一部分。然而,这种方法效率不高,因为它需要多次打开输入文件和搜索。如果你只是要分割文件,为什么不打开输入文件一次,然后只写如下内容:

public static void CopySection(Stream input, string targetFile, int length)
{
    byte[] buffer = new byte[8192];
    using (Stream output = File.OpenWrite(targetFile))
    {
        int bytesRead = 1;
        // 如果我们无法读取"length"字节,则这将静默结束。
        // 另一种选择是抛出异常
        while (length > 0 && bytesRead > 0)
        {
            bytesRead = input.Read(buffer, 0, Math.Min(length, buffer.Length));
            output.Write(buffer, 0, bytesRead);
            length -= bytesRead;
        }
    }
}

这种方法在每次调用时创建了一个缓冲区,这会导致一些效率上的损失,你可能希望只创建一次缓冲区并将其作为参数传递给方法:

public static void CopySection(Stream input, string targetFile,
                               int length, byte[] buffer)
{
    using (Stream output = File.OpenWrite(targetFile))
    {
        int bytesRead = 1;
        // 如果我们无法读取"length"字节,则这将静默结束。
        // 另一种选择是抛出异常
        while (length > 0 && bytesRead > 0)
        {
            bytesRead = input.Read(buffer, 0, Math.Min(length, buffer.Length));
            output.Write(buffer, 0, bytesRead);
            length -= bytesRead;
        }
    }
}

请注意,这也会关闭输出流(由于using语句),而你的原始代码没有关闭输出流。

重要的一点是,这种方法会更有效地使用操作系统的文件缓冲,因为你重复使用相同的输入流,而不是在开始时重新打开文件然后搜索。

我认为这种方法会显著提高速度,但显然你需要尝试一下来确认。

当然,这假设是连续的块。如果你需要跳过文件的某些部分,你可以在方法外部进行操作。此外,如果你要写入非常小的文件,你可能还希望针对这种情况进行优化 - 最简单的方法可能是在输入流上使用BufferedStream包装。

我知道这是一个两年前的帖子,只是想知道...这仍然是最快的方法吗?(即。是否有.NET中的新方法需要注意?)此外,执行Math.Min是否在进入循环之前会更快一些?或者更好的做法是删除长度参数,因为它可以通过缓冲区计算得出?对不起,我这么挑剔并且唤起了旧帖子!先谢谢。

:鉴于这是执行IO操作,Math.Min的调用在性能上肯定不相关。长度参数和缓冲区长度的目的是允许您重复使用可能超大的缓冲区。

明白了,谢谢你的回答。如果你想读取大量文件的前x个字节(为了从大量文件中获取XMP元数据),以上方法(稍作修改)仍然推荐吗?

:好吧,上面的代码是用于复制的。如果你只是想读取前x个字节,我仍然会循环读取,但是只需读入合适大小的缓冲区,并在每次迭代中适当地增加读取将写入缓冲区的索引。

是的,我对写入部分不太感兴趣,我只是想确认读取一个文件的最快方法也是读取多个文件的最快方法。我想象能够调用文件指针/偏移量并从那里扫描多个文件,使用相同/更少的流/缓冲区,这在我虚构的幻想世界中可能会更快,这对我想实现的目标可能更好(虽然不适用于OP)。如果我没有疯,最好我重新提一个新问题。如果我疯了,请告诉我,这样我就不会浪费更多人的时间了。:-)

:你现在真的有性能问题吗?你编写了最简单的可行代码,发现它太慢了吗?请记住,很多情况都取决于上下文 - 如果你正在并行读取,并行可能有所帮助,如果你使用固态硬盘,但对于普通硬盘来说并不适用。

SO建议我将这个问题放到聊天室中,我想我还是重新提一个新问题。到目前为止,谢谢你的帮助!

0
0 Comments

问题的出现原因:在文件流处理的过程中,使用了BinaryReader来读取和写入文件,但是在处理大文件时,使用BinaryReader会导致性能较差。

解决方法:可以改用Stream.Read和Stream.Write来替代BinaryReader,同时使用一个固定大小的缓冲区来提高性能。以下是一个示例代码:

private static void copy(string srcFile, string dstFile, int offset, int length, byte[] buffer)
{
    using (Stream inStream = File.OpenRead(srcFile))
    using (Stream outStream = File.OpenWrite(dstFile))
    {
        inStream.Seek(offset, SeekOrigin.Begin);
        int bufferLength = buffer.Length, bytesRead;
        while (length > bufferLength && (bytesRead = inStream.Read(buffer, 0, bufferLength)) > 0)
        {
            outStream.Write(buffer, 0, bytesRead);
            length -= bytesRead;
        }
        while (length > 0 && (bytesRead = inStream.Read(buffer, 0, length)) > 0)
        {
            outStream.Write(buffer, 0, bytesRead);
            length -= bytesRead;
        }
    }
}

同时,原代码中的Flush操作可以省略,因为在使用using语句块时,流会在离开using块时自动关闭并刷新。另外,在第一个循环中应该将读取的字节数从length中减去。

以上就是如何在C#中编写高效的文件流处理代码的解决方法。

0