2016-11-14 4 views
0

У меня есть программа, которая считывает из очень большого двоичного файла (48 МБ), а затем передает данные в матрицу пользовательских структур по имени пикселей:Производительность чтения двоичных файлов

struct pixel { 
    int r; 
    int g; 
    int b; 
}; 

Открытие файла:

ifstream myFile(inputPath, ios::binary); 
pixel **matrixPixel; 

Считанные файла делается так:

int position = 0; 

for (int i = 0; i < HEIGHT; ++i) { 
     for (int j = 0; j < WIDTH; ++j) { 
      if (!myFile.eof()) { 
       myFile.seekg(position, ios::beg); 
       myFile.read((char *) &matrixPixel[i][j].r, 1); // red byte 
       myFile.seekg(position + HEIGHT * WIDTH, ios::beg); 
       myFile.read((char *) &matrixPixel[i][j].g, 1); // green byte 
       myFile.seekg(position + HEIGHT * WIDTH * 2, ios::beg); 
       myFile.read((char *) &matrixPixel[i][j].b, 1); // blue byte 
       ++position; 
      } 
     } 
    } 
myFile.close(); 

дело в том, что для большого файла, как один на бека Иннинг, требуется много времени (~ 7 минут), и он должен быть оптимизирован. Как я мог читать из файла за меньшее время?

+1

Как вы пришли к этому бизнесу 'seekg'? Неудивительно, что это медленно. –

+0

Пробовал просто бить, бить его, искать один за триблет rgb и читать все 3 в одном вводе. 3 int вероятно выровнен OK – pm100

+4

В любом случае, вам не нужно искать, как сказал @BaummitAugen.Это значительно облегчает доступ к файлу последовательно и прыгает вокруг вашего 'matrixPixel' вместо того, чтобы пытаться перескакивать через ваш файл. –

ответ

7

Таким образом, структура данных, которые вы хранящие в памяти выглядит следующим образом:

rgbrgbrgbrgbrgbrgbrgbrgbrgbrgb..............rgb 

Но структура файла, который вы читаете, выглядят следующим образом (при условии, логики вашего кода правильно):

rrrrrrrrrrrrrrrrrrrrrrrrrrr.... 
ggggggggggggggggggggggggggg.... 
bbbbbbbbbbbbbbbbbbbbbbbbbbb.... 

И в вашем коде вы переводите между ними. По сути, это будет медленным. Более того, вы решили прочитать файл, выполнив ручной поиск произвольных точек в файле. Это еще больше замедлит работу.

Первое, что вы можете сделать, это оптимизировать жесткий диск читает:

for(int channel = 0; channel < 3; channel++) { 
    for (int i = 0; i < HEIGHT; ++i) { 
     for (int j = 0; j < WIDTH; ++j) { 
      if (!myFile.eof()) { 
       switch(channel) { 
        case 0: myFile.read((char *) &matrixPixel[i][j].r, 1); break; 
        case 1: myFile.read((char *) &matrixPixel[i][j].g, 1); break; 
        case 2: myFile.read((char *) &matrixPixel[i][j].b, 1); break; 
       } 
      } 
     } 
    } 
} 

Это требует наименьшее количество изменений в коде, и ускорит ваш код, но код будет, вероятно, еще будет медленным.

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

std::vector<unsigned char> reds(WIDTH * HEIGHT); 
std::vector<unsigned char> greens(WIDTH * HEIGHT); 
std::vector<unsigned char> blues(WIDTH * HEIGHT); 

myFile.read(reds.data(), WIDTH * HEIGHT); //Stream can be checked for errors resulting from EOF or other issues. 
myFile.read(greens.data(), WIDTH * HEIGHT); 
myFile.read(blues.data(), WIDTH * HEIGHT); 

std::vector<pixel> pixels(WIDTH * HEIGHT); 

for(size_t index = 0; index < WIDTH * HEIGHT; index++) { 
    pixels[index].r = reds[index]; 
    pixels[index].g = greens[index]; 
    pixels[index].b = blues[index]; 
} 

Последний, лучший подход заключается в том, чтобы изменить способ форматирования двоичного файла, поскольку способ, по которому он форматируется, безумный (с точки зрения производительности). Если файл переформатирован в rgbrgbrgbrgbrgb стиле (который является гораздо более стандартом в отрасли), ваш код становится просто это:

struct pixel { 
    unsigned char red, green, blue; 
}; //You'll never read values above 255 when doing byte-length color values. 
std::vector<pixel> pixels(WIDTH * HEIGHT); 
myFile.read(reinterpret_cast<char*>(pixels.data()), WIDTH * HEIGHT * 3); 

Это очень короткий, и, вероятно, будет опережать все остальные методы. Но, конечно, это не может быть для вас вариантом.

Я не тестировал ни один из этих методов (и может быть опечатка или две), но все эти методы должны быть быстрее, чем то, что вы сейчас делаете.

+0

Формат является нормальным, если это (скажем) астрономическое изображение, сделанное через три фильтра, и полное изображение было сформировано путем объединения «красных», «зеленых» и «синих» изображений. –

+0

Первым делом, вероятно, будет сокращение времени на чтение до минимума. –

+0

@MartinBonner Чтение навалом, как и во втором и третьем примерах, значительно сократит скорость чтения. Чтение одного символа за раз, даже последовательно, происходит медленнее, чем чтение навалом. – Xirema

0

Более быстрый метод будет считывать растровое изображение в буфер:

uint8_t buffer[HEIGHT][WIDTH]; 
const unsigned int bitmap_size_in_bytes = sizeof(buffer); 
myFile.read(buffer, bitmap_size_in_bytes); 

Еще более быстрый метод, чтобы прочитать более одного растрового изображения в память.

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