2011-11-28 66 views
4

我使用unsigned short類型的向量在RAM中分配了一大塊連續字節。保存大量的數字向量到硬盤驅動器

vector<unsigned short> testDump(204800000); 

for(int k = 0; k<204800000; k++) 
    testDump[k] = 9; \\ This is different in my real program 

現在我想將此矢量保存到我的硬盤驅動器。如何以及什麼是最快的方式來做到這一點?數據的大小相當大(〜1/2   GB)。我試過如下:

ofstream outfile("allMyNumbers.txt", ios::out | ios::binary); 
outfile.write(&testDump[0], testDump.size()); 

但我發現了以下錯誤:

cannot convert parameter 1 from 'unsigned short *' to 'const char *' 

什麼來完成我的任務,是用最快的方法來保存矢量文件的最快方法?

*的平臺是Windows 7

+0

這肯定要取決於您定位的平臺。 –

+0

內存映射文件可能適用於此,具體取決於平臺。 – OSH

+0

我的平臺是Windows 7.編輯 –

回答

3

一個獨立於平臺的技術是使用一個ostream_iterator您的矢量級持有的類型。由於您的矢量包含的類型已經爲operator<<對於ostream類類型過載,所以對於矢量類型,您不應該爲ostream_iterator類實例化模板。然後,您將結合ostream_iterator和STL中的copy算法遍歷您的向量,並將原始字節序列化到文件中。使用operator<<將使用比使用ofstream::write更多的數據,該數據將原始二進制數據寫入磁盤,但具有序列化數據的優點,使其可在任何平臺上獨立讀取。

因此,例如:

vector<unsigned short> testDump(2048000000); 
//...fill in your vector 

ofstream outfile("allMyNumbers.txt", ios::out | ios::binary); 

//tab-delinate the data 
ostream_iterator<unsigned short> o_iter(outfile, "\t"); 
copy(testDump.begin(), testDump.end(), o_iter); 
+2

也許值之間的分隔符是有序的。當然,提問者並未指定將來可以讀取數據,但我認爲這是可以假設的。 –

+0

絕對是一個好主意......雖然對於二進制文件,它必須是某種類型的「魔術」數字,而不是簡單的字符分隔符,除非該字符不會成爲實際輸出本身的一部分開始用。典型地,二進制文件將具有指向原始數據部分的指針的頭部以及關於每個可讀數據部分的大小的規範,以避免分隔符模糊。 – Jason

+0

感謝您的建議。如果我可能會問,我該怎麼做(它不需要保持二進制,我可以使用十進制)。順便說一句,它是永恆的完成。它仍然沒有完成(到目前爲止3分鐘) –

3

可以只投的指針。

outfile.write(reinterpret_cast<char*>(&testDump[0]), testDump.size() * sizeof(unsigned short)); 

注意,生成的文件在某種程度上這是特定於您的特定平臺/執行格式化。所以你不一定在不兼容的機器上以明顯的方式閱讀它。

在Windows上,這將爲您提供一個400MB-ish文件,每個204800000對字節代表一個小端無符號短整型。

這應該是相當快的。我發現很難相信你的任務真的是「使用最快的方法」來保存數據。怎麼會有人知道你的代碼真的是最優的,沒有其他代碼可以使它的速度提高一納秒?還有什麼額外的努力來削減納秒?等等。

當然,使用快速流式壓縮算法來減少所需的磁盤空間可能會更快,因爲操作可能受磁盤I/O限制。但是代碼會更加複雜,並且它的幫助與否取決於數據的可壓縮性。

+0

我認爲OP只有大約400MB的數據。 –

+0

@Kerrek:你說得對,這個問題已經被編輯過。我相信示例代碼中的數字,而不是文本。 –

+0

@SteveJessop:你的方法超快(少於一秒)。但是,當我打開輸出文件時,出現奇怪的符號。你有什麼建議嗎?我還想在數據點之間添加分隔符,是否有一種簡單的方法可以實現這一點? –

1

一個串行化的交叉平臺方式是將注意力集中在little endian表達式上並轉儲所有短褲。這將避免Jason解決方案中的ASCII數據膨脹,同時也是跨平臺的。

所以,我只想做

ofstream outfile("allMyNumbers.data", ios::out | ios::binary); 
for(int k = 0; k < testDump.size(); k++) 
{ 
    unsigned short leData = htole16(testDump[k]);  
    outfile.write(&leData, sizeof(leData)); 
} 

htole16(主機爲16個整數小端)的實現如下:

對於x86,x64系統:

unsigned short htole16(unsigned short x) 
{ 
    return x; 
} 

對於像Sparc/PowerPC這樣的大型機器(儘管沒有一個會運行Windows 7)

unsigned short htole16(unsigned short x) 
{ 
    return _byteswap_ushort(x); 
} 
+0

這只是「跨平臺」,因爲您已經預先定義了二進制數據將如何格式化......如果讀者不知道數據的商定格式是什麼,那麼它不是「跨平臺」 」。 – Jason

+0

閱讀器(程序)在嘗試讀取數據之前,還需要知道數據使用ASCII製表符分隔符號。此外,在網絡協議中使用使用大端格式的類似技術來實現跨平臺數據表示。字節順序被稱爲「網絡字節順序」,通常使用的C函數是htons()和ntohs()。以上是這種(流行)技術的變體。 – ritesh

+0

我意識到您正在使用網絡字節順序標準化爲多字節數據塊的大端表示形式的網絡技術的變體。我會給你一個+1,否則我們只會在圈子裏說話,因爲它的標準比其他標準更「標準化」:-) – Jason