处理大文件流(读+写字节)
Handling big file stream (read+write bytes)
执行以下代码:
- 从输入文件读取所有字节
- 只保留文件的一部分 outbytes
- 将提取的字节写入输出文件
byte[] outbytes = File.ReadAllBytes(sourcefile).Skip(offset).Take(size).ToArray();
File.WriteAllBytes(outfile, outbytes);
但是每一步有 ~2GB 数据的限制。
编辑:提取出来的byte
s大小也可以大于2GB
.
我如何处理大文件?无论大小如何,进行良好性能的最佳方法是什么?
谢谢!
FileStream 从 5 Gb 文件中取出中间 3 Gb 的示例:
byte[] buffer = new byte{1024*1024];
using(var readFS = File.Open(pathToBigFile))
using(var writeFS = File.OpenWrite(pathToNewFile))
{
readFS.Seek(1024*1024*1024); //seek to 1gb in
for(int i=0; i < 3000; i++){ //3000 times of one megabyte = 3gb
int bytesRead = readFS.Read(buffer, 0, buffer.Length);
writeFS.Write(buffer, 0, bytesRead);
}
}
这不是生产级代码; Read 可能无法读取完整的 MB,因此您最终会得到不到 3Gb - 它更多地是为了演示使用两个文件流并从一个文件流重复读取并重复写入另一个文件流的概念。我确定您可以修改它,以便它通过跟踪循环中所有 bytesRead 的总数并在阅读足够时停止读取来复制准确数量的字节
最好将数据从一个文件流式传输到另一个文件,只将其中的一小部分加载到内存中:
public static void CopyFileSection(string inFile, string outFile, long startPosition, long size)
{
// Open the files as streams
using (var inStream = File.OpenRead(inFile))
using (var outStream = File.OpenWrite(outFile))
{
// seek to the start position
inStream.Seek(startPosition, SeekOrigin.Begin);
// Create a variable to track how much more to copy
// and a buffer to temporarily store a section of the file
long remaining = size;
byte[] buffer = new byte[81920];
do
{
// Read the smaller of 81920 or remaining and break out of the loop if we've already reached the end of the file
int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(buffer.Length, remaining));
if (bytesRead == 0) { break; }
// Write the buffered bytes to the output file
outStream.Write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
while (remaining > 0);
}
}
用法:
CopyFileSection(sourcefile, outfile, offset, size);
这应该具有与您当前方法相同的功能,而无需将整个文件(无论其大小)读入内存的开销。
注意:如果您在使用 async/await 的代码中执行此操作,则应将 CopyFileSection
更改为 public static async Task CopyFileSection
并更改 inStream.Read
和 outStream.Write
分别为 await inStream.ReadAsync
和 await outStream.WriteAsync
。
执行以下代码:
- 从输入文件读取所有字节
- 只保留文件的一部分 outbytes
- 将提取的字节写入输出文件
byte[] outbytes = File.ReadAllBytes(sourcefile).Skip(offset).Take(size).ToArray();
File.WriteAllBytes(outfile, outbytes);
但是每一步有 ~2GB 数据的限制。
编辑:提取出来的byte
s大小也可以大于2GB
.
我如何处理大文件?无论大小如何,进行良好性能的最佳方法是什么?
谢谢!
FileStream 从 5 Gb 文件中取出中间 3 Gb 的示例:
byte[] buffer = new byte{1024*1024];
using(var readFS = File.Open(pathToBigFile))
using(var writeFS = File.OpenWrite(pathToNewFile))
{
readFS.Seek(1024*1024*1024); //seek to 1gb in
for(int i=0; i < 3000; i++){ //3000 times of one megabyte = 3gb
int bytesRead = readFS.Read(buffer, 0, buffer.Length);
writeFS.Write(buffer, 0, bytesRead);
}
}
这不是生产级代码; Read 可能无法读取完整的 MB,因此您最终会得到不到 3Gb - 它更多地是为了演示使用两个文件流并从一个文件流重复读取并重复写入另一个文件流的概念。我确定您可以修改它,以便它通过跟踪循环中所有 bytesRead 的总数并在阅读足够时停止读取来复制准确数量的字节
最好将数据从一个文件流式传输到另一个文件,只将其中的一小部分加载到内存中:
public static void CopyFileSection(string inFile, string outFile, long startPosition, long size)
{
// Open the files as streams
using (var inStream = File.OpenRead(inFile))
using (var outStream = File.OpenWrite(outFile))
{
// seek to the start position
inStream.Seek(startPosition, SeekOrigin.Begin);
// Create a variable to track how much more to copy
// and a buffer to temporarily store a section of the file
long remaining = size;
byte[] buffer = new byte[81920];
do
{
// Read the smaller of 81920 or remaining and break out of the loop if we've already reached the end of the file
int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(buffer.Length, remaining));
if (bytesRead == 0) { break; }
// Write the buffered bytes to the output file
outStream.Write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
while (remaining > 0);
}
}
用法:
CopyFileSection(sourcefile, outfile, offset, size);
这应该具有与您当前方法相同的功能,而无需将整个文件(无论其大小)读入内存的开销。
注意:如果您在使用 async/await 的代码中执行此操作,则应将 CopyFileSection
更改为 public static async Task CopyFileSection
并更改 inStream.Read
和 outStream.Write
分别为 await inStream.ReadAsync
和 await outStream.WriteAsync
。