2016-11-14 110 views
0

我有一个程序,它从一个非常大的二进制文件(48 MB)读取信息,然后将数据传递到名为像素的自定义结构的矩阵:性能读取二进制文件

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

的事情是,对于一个大的文件,如一个在BEG这需要花费很多时间(〜7分钟),并且应该进行优化。我怎么能在更短的时间内从文件中读取?

+1

你是怎么想出这个'seekg'业务的?难怪这很慢。 –

+0

你是否尝试了一下,找到一个rgb三元组,并在一个IO中读取全部3个元素。 3 int可能对齐确定 – pm100

+4

无论如何,你不必看到kg,就像@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; 
       } 
      } 
     } 
    } 
} 

这需要改变,以最少的代码,并会加快你的代码,但是代码仍然可能会很慢。

一个更好的办法,这增加了CPU使用,但大大降低了硬盘使用(其中,在绝大多数的应用程序,将导致加速),将数据存储像这样:

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

甚至更​​快的方法是读取一个以上的位图到内存中。