2016-11-14 145 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); 

甚至更​​快的方法是讀取一個以上的位圖到內存中。