不使用Windows文件缓存复制文件

6

有没有办法将文件从路径A复制到路径B并抑制Windows文件系统缓存?
典型用途是从USB驱动器或服务器复制大文件到本地计算机。如果文件非常大,例如2GiB,则Windows似乎会将所有内容都交换出去。 最好使用C#示例,但如果可能的话,我猜这将是一种Win32调用。


1
如果你真的想了解缓存与文件复制之间的机制,那么这篇文章是必读的。 - On Freund
6个回答

6

在C#中,我发现可以像这样工作,这可以更改为直接复制到目标文件:

    public static byte[] ReadAllBytesUnbuffered(string filePath)
    {
        const FileOptions FileFlagNoBuffering = (FileOptions)0x20000000;
        var fileInfo = new FileInfo(filePath);
        long fileLength = fileInfo.Length;
        int bufferSize = (int)Math.Min(fileLength, int.MaxValue / 2);
        bufferSize += ((bufferSize + 1023) & ~1023) - bufferSize;
        using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None,
                                           bufferSize, FileFlagNoBuffering | FileOptions.SequentialScan))
        {
            long length = stream.Length;
            if (length > 0x7fffffffL)
            {
                throw new IOException("File too long over 2GB");
            }
            int offset = 0;
            int count = (int)length;
            var buffer = new byte[count];
            while (count > 0)
            {
                int bytesRead = stream.Read(buffer, offset, count);
                if (bytesRead == 0)
                {
                    throw new EndOfStreamException("Read beyond end of file EOF");
                }
                offset += bytesRead;
                count -= bytesRead;
            }
            return buffer;
        }
    }

5

这个答案虽然正确,但并不是原问题的答案。有编辑权限的人能否重新措辞一下? - Allain Lalonde
你能告诉我在哪里看到问题和答案之间的差异吗?我很乐意重新措辞答案。 - gabr
4
@gabr:你的回复提到了另一个答案,但请不要这样做。让你的回答独立自成一体,就好像只有你一个人回答了这个问题。 - tzot

4

我不确定这是否有所帮助,但请查看使用FILE_FLAG_SEQUENTIAL_SCAN提高性能

摘要

CreateFile()有一个名为FILE_FLAG_SEQUENTIAL_SCAN的标志,它将指示缓存管理器按顺序访问文件。

任何使用顺序访问读取潜在大文件的人都可以指定此标志以提高性能。如果您正在读取“大多数”顺序文件,但偶尔跳过小字节范围,则此标志非常有用。


我使用这个标志来达到同样的目的,并且我可以证明 FILE_FLAG_SEQUENTIAL_SCAN 能够胜任。 - tzot

3
如果您不介意使用工具,ESEUTIL 对我非常有效。
您可以查看此 blog 条目,比较缓冲和非缓冲 IO 函数,并了解如何获取 ESEUTIL。
从 technet 博客复制一些文本:
因此,从上面缓冲I/O的定义来看,我们可以看到感知性能问题存在于文件系统缓存开销中。如果我们在复制大文件时不打算在复制完成后访问源文件,则首选未缓冲的I/O(或原始文件复制)。这将避免文件系统缓存开销,并防止大文件数据有效刷新文件系统缓存。许多应用程序通过调用CreateFile()创建一个空目标文件,然后使用ReadFile()和WriteFile()函数传输数据来实现此目的。
CreateFile() - CreateFile函数创建或打开文件、文件流、目录、物理磁盘、卷、控制台缓冲区、磁带驱动器、通信资源、邮槽或命名管道。该函数返回一个句柄,可用于访问对象。
ReadFile() - ReadFile函数从文件中读取数据,从文件指针指示的位置开始。您可以将此函数用于同步和异步操作。
WriteFile() - WriteFile函数将数据写入文件,位置由文件指针指定。此函数设计用于同步和异步操作。
对于在网络上传输非常大的文件,我的首选复制工具是ESEUTIL,它是Exchange提供的数据库实用程序之一。

0

我知道这个问题是11年前的,现在有一个名为robocopy的工具,可以替代xcopy。

你需要检查/J选项 /J :: 使用无缓存I/O进行复制(建议用于大文件)


0

Eseutil是一个正确的答案,自Win7 / 2008 R2以来,您可以在Xcopy中使用/j开关,其具有相同的效果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接