Обработка большого файлового потока (чтение + запись байтов) - PullRequest
0 голосов
/ 27 мая 2020

Следующий код выполняет:

  1. Прочитать все байты из входного файла
  2. Сохранить только часть файла в outbytes
  3. Записать извлеченные байты в выходной файл
byte[] outbytes = File.ReadAllBytes(sourcefile).Skip(offset).Take(size).ToArray();
File.WriteAllBytes(outfile, outbytes);

Но есть ограничение в ~ 2 ГБ данных для каждого шага.

Изменить: Извлеченные byte s размер также может быть больше, чем 2GB.

Как мне обрабатывать большой файл? Как лучше всего добиться хороших результатов, независимо от размера ?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 27 мая 2020

Пример FileStream для извлечения средних 3 ГБ из файла 5 ГБ:

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);
  }

}

Это не код производственного уровня; Чтение может не прочитать полный мегабайт, поэтому у вас будет меньше 3Гб - это больше для демонстрации концепции использования двух файловых потоков и многократного чтения из одного и многократной записи в другой. Я уверен, что вы можете изменить его так, чтобы он копировал точное количество байтов, отслеживая общее количество всех байтов, прочитанных в l oop и останавливая чтение, когда вы прочитали достаточно

1 голос
/ 27 мая 2020

Лучше передавать данные из одного файла в другой, загружая только небольшие части в память:

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 соответственно.

...