有人知道将文件从路径 A 复制到路径 B 并抑制 Windows 文件系统缓存的方法吗?
典型用途是将大文件从 USB 驱动器或服务器复制到本地计算机。如果文件非常大,例如 2GiB,Windows 似乎会交换所有内容。更喜欢 C# 中的示例,但我猜如果可能的话,这将是某种 Win32 调用。
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;
}
}
更重要的是,还有 FILE_FLAG_WRITE_THROUGH 和 FILE_FLAG_NO_BUFFERING。
MSDN 对它们都有一篇很好的文章:http: //support.microsoft.com/kb/99794
我不确定这是否有帮助,但请看一下使用 FILE_FLAG_SEQUENTIAL_SCAN 提高性能。
概括
CreateFile() 有一个名为 FILE_FLAG_SEQUENTIAL_SCAN 的标志,它将指示缓存管理器按顺序访问文件。
任何通过顺序访问读取潜在大文件的人都可以指定此标志以提高性能。如果您正在读取“大部分”顺序的文件,但您偶尔会跳过小范围的字节,则此标志很有用。
如果您不介意使用工具,ESEUTIL 对我来说非常有用。
您可以查看此博客条目,比较缓冲和非缓冲 IO 函数以及从何处获取 ESEUTIL。
从 technet 博客复制一些文本:
所以看看上面缓冲 I/O 的定义,我们可以看到感知到的性能问题在哪里——文件系统缓存开销。当我们不打算在复制完成后访问源文件时,尝试将大文件从一个位置复制到另一个位置时,首选无缓冲 I/O(或原始文件副本)。这将避免文件系统缓存开销,并防止文件系统缓存被大文件数据有效刷新。许多应用程序通过调用 CreateFile() 来创建一个空的目标文件,然后使用 ReadFile() 和 WriteFile() 函数来传输数据来实现这一点。CreateFile() - CreateFile 函数创建或打开文件、文件流、目录、物理磁盘、卷、控制台缓冲区、磁带驱动器、通信资源、邮槽或命名管道。该函数返回可用于访问对象的句柄。ReadFile() - ReadFile 函数从文件中读取数据,并从文件指针指示的位置开始。您可以将此函数用于同步和异步操作。WriteFile() - WriteFile 函数将数据写入文件指针指定位置的文件。此函数设计用于同步和异步操作。对于在网络上复制非常大的文件,我选择的复制实用程序是 ESEUTIL,它是 Exchange 提供的数据库实用程序之一。WriteFile() - WriteFile 函数将数据写入文件指针指定位置的文件。此函数设计用于同步和异步操作。对于在网络上复制非常大的文件,我选择的复制实用程序是 ESEUTIL,它是 Exchange 提供的数据库实用程序之一。WriteFile() - WriteFile 函数将数据写入文件指针指定位置的文件。此函数设计用于同步和异步操作。对于在网络上复制非常大的文件,我选择的复制实用程序是 ESEUTIL,它是 Exchange 提供的数据库实用程序之一。
Eseutil 是正确答案,同样从 Win7 / 2008 R2 开始,您可以使用 Xcopy 中的 /j 开关,效果相同。
我知道这个问题是 11 年前的问题,现在有 robocopy 可以替代 xcopy。
你需要检查 /J 选项
/J :: copy using unbuffered I/O (recommended for large files)