2014-11-02 3 views
1

Задача

У меня есть огромный файл (& approx; 20 ГБ), содержащий целые числа, и вы хотите прочитать их на C#.Чтение гигантского массива из двоичного файла

Простой подход

Чтение файла в память (в байт-массив) довольно быстро (с использованием SSD, весь файл помещается в памяти). Но когда я читаю эти байты с двоичным считывателем (через поток памяти), а метод ReadInt32 занимает значительно больше времени, чем чтение файла в память. Я ожидал, что диск-IO станет узким местом, но это конверсия!

Идея и вопрос

Есть ли способ, чтобы непосредственно бросить весь байт-массив в Инт-массив не конвертируя его один-на-один с ReadInt32-метода?

class Program 
{ 
    static int size = 256 * 1024 * 1024; 
    static string filename = @"E:\testfile"; 

    static void Main(string[] args) 
    { 
     Write(filename, size); 
     int[] result = Read(filename, size); 
     Console.WriteLine(result.Length); 
    } 

    static void Write(string filename, int size) 
    { 
     Stopwatch stopwatch = new Stopwatch(); 
     stopwatch.Start(); 
     BinaryWriter bw = new BinaryWriter(new FileStream(filename, FileMode.Create), Encoding.UTF8); 
     for (int i = 0; i < size; i++) 
     { 
      bw.Write(i); 
     } 
     bw.Close(); 
     stopwatch.Stop(); 
     Console.WriteLine(String.Format("File written in {0}ms", stopwatch.ElapsedMilliseconds)); 
    } 

    static int[] Read(string filename, int size) 
    { 
     Stopwatch stopwatch = new Stopwatch(); 
     stopwatch.Start(); 
     byte[] buffer = File.ReadAllBytes(filename); 
     BinaryReader br = new BinaryReader(new MemoryStream(buffer), Encoding.UTF8); 
     stopwatch.Stop(); 
     Console.WriteLine(String.Format("File read into memory in {0}ms", stopwatch.ElapsedMilliseconds)); 
     stopwatch.Reset(); 
     stopwatch.Start(); 

     int[] result = new int[size]; 

     for (int i = 0; i < size; i++) 
     { 
      result[i] = br.ReadInt32(); 
     } 
     br.Close(); 
     stopwatch.Stop(); 
     Console.WriteLine(String.Format("Byte-array casted to int-array in {0}ms", stopwatch.ElapsedMilliseconds)); 

     return result; 
    } 
} 
  • Файл написан в 5499ms
  • Файл считывается в память в 455ms
  • байт массива отлитого в Инт-массив в 3382ms
+3

Вам придется выполнить преобразование в конце концов. Можете ли вы просто прочитать массив в памяти и использовать BitConverter для получения значений из массива по мере необходимости? –

+0

Возможный дубликат http://stackoverflow.com/questions/3206391/directly-reading-large-binary-file-in-c-sharp-w-out-copying. –

+0

@PatrickHofman: Кажется, он уже знает, как читать файл в памяти. –

ответ

2

Можно выделить временный byte[] буфер с удобным размер и использовать метод Buffer.BlockCopy для постепенного копирования байтов в массив int[].

BinaryReader reader = ...; 
int[] hugeIntArray = ...; 

const int TempBufferSize = 4 * 1024 * 1024; 
byte[] tempBuffer = reader.ReadBytes(TempBufferSize); 
Buffer.BlockCopy(tempBuffer, 0, hugeIntArray, offset, TempBufferSize); 

offset Где это ток (для текущей итерации), начиная с индекса в массиве назначения hugeIntArray.

+0

ReadBytes, вероятно, постигнет ту же участь, хотя я не уверен в этом. –

+0

Сначала я прочитал весь файл в памяти с помощью ReadAllBytes. – user2033412

+0

Это значительно быстрее: файл считывается в память в 439ms, Байт-массив, выделенный для int-array в 105 мс – user2033412

Смежные вопросы