2012-08-16 77 views
8

在許多項目中,我看到數據對象/結構以二進制模式寫入文件,然後再次以二進制模式從文件恢復。以二進制模式與文本模式運行文件 - 性能問題

我想知道他們爲什麼在二進制模式下做到這一點?文本和二進制模式之間的任何性能差異?如果不是,那麼何時使用二進制模式或文本模式?

+0

我懷疑這是http://stackoverflow.com/questions/229924/difference-between-files-writen-in-binary-and-text-mode的副本,但我不確定。 – jogojapan 2012-08-16 06:02:19

+0

@jogojapan,非常。但是這篇文章並沒有完全回答我的問題。 – Alcott 2012-08-16 06:06:32

回答

3

如果您在文本模式下讀取/寫入文件,那麼您正在操作文本。它可能是一個編碼錯誤和操作系統特定格式更改的主題,但有時它可能工作得很好。但在二進制模式下,您將不會遇到這些限制。此外,文本模式可能會使用\n字符做一些有趣的事情,例如用\n\r替換它們。

Fopen參考,例如,說:

在文本文件的情況下,根據不同的環境下, 應用程序運行時,可以在 輸入/輸出操作出現一些特殊的字符轉換,以適應他們到特定於系統的文本文件 格式。在許多環境中,例如大多數基於UNIX的系統,其 將文件打開爲文本文件或二進制文件沒有區別; 兩者的處理方式完全相同,但建議使用差異化爲 以實現更好的便攜性。

+0

由於代碼必須檢查每個單獨的字符,因此此替換會帶走一些性能。 – 2012-08-16 06:09:36

+0

@TobiasLangner,所以'\ n' /'\ r \ n'替換是一個性能問題? – Alcott 2012-08-16 06:13:14

6

如果您的程序是將要使用該文件的唯一程序,則可以使用二進制文件「按原樣」保存內部結構。

但是,如果你想與其他程序或通過互聯網交換文件,那麼二進制格式不是很好。想想大端與小端機器的問題。此外,文件或數據的接收者很可能無法訪問您的代碼和結構,因此基於文本的格式可能更容易解析並實現到自己的結構中。

關於性能,直接讀取和寫入內部結構的速度會更快,因爲您不必將它們(也稱爲編組)轉換爲另一種格式。

+0

+1。正如你指出的那樣,我是唯一使用這些數據對象/結構的人,並且我想將它們保存並從文件中取回。在這種情況下,我不認爲文本文件會對**文本文件**有所幫助,您的意思是我應該將每個數據對象/結構的值作爲**純文本**寫入文件,然後將這些文本讀回並將它們用作值來構造原始數據對象? – Alcott 2012-08-16 06:12:12

+0

@Alcott如果你是唯一一個讀寫這些文件的人,那麼你可以使用二進制格式,直接讀/寫結構。但是,要小心指針!編寫一個包含指針的結構寫入實際的指針值,而不是它指向的內容。稍後閱讀時,現在將指向一些未分配的內存區域。另外,在讀寫字符串時,應考慮終止的'\ 0'字符。 – 2012-08-16 06:16:12

+0

@Alcott如果以文本形式編寫,可以使用簡單的純文本,每行一個值或每行使用分隔符的多個值(例如CSV文件)。或者使用更復雜的格式,如XML或JSON。這完全取決於你。 :) – 2012-08-16 06:17:20

2

只有少數操作系統受到二進制和文本模式選擇的影響。沒有一個Unix或Linux系統對文本模式—做任何特殊處理,即文本與二進制文件相同。

Windows和VMS特別以文本模式轉換數據。在寫入文件時,Windows將\n轉換爲\r\n,而在讀取時轉換爲逆向。 VMS有一個文件記錄結構可供觀察,所以在默認模式下,它將\n轉換爲記錄分隔符。

不同之處在於,二進制更快。如果沒有區別,那就沒有區別。

+0

如果不同,性能差異是否會顯着? – Alcott 2012-08-16 06:16:49

+0

@Alcott:在一般情況下,我不希望在性能上有顯着差異。然而,只要大量使用'\ n'和其他所有東西,就可以輕鬆構建一個測試,其中存在顯着差異。最糟糕的情況是,Windows會使正在寫入的數據量增加一倍,而VMS會讓bonkers創建大量記錄。 – wallyk 2012-08-16 08:53:11

15

二進制更快。考慮以32位(4字節)存儲的整數,例如123456.如果要將其寫成二進制(它是如何在計算機中表示的),則需要4個字節(忽略項目之間的填充以在結構中對齊)。

要將數字寫入文本,必須將其轉換爲一串字符(用於轉換和存儲的一些開銷),然後將其寫出,至少需要6個字節,因爲需要6個字符重新編號。這不包括任何額外的填充,例如用於對齊的空格或用於讀取/分離數據的分隔符。

現在,如果您認爲它有數千個項目,則額外的時間可能會增加並且需要更多的空間,這會花費更長的時間來讀取,然後在您之後有更多時間轉換回二進制存儲已經將價值讀入記憶。

對文本的好處是,讀取人員更容易,而不是嘗試讀取二進制數據或十六進制數據轉儲。

+1

我發現你的答案更容易理解。 :-) – Alcott 2012-08-16 06:28:36

2

在二進制模式下,您可以使用字節大小(考慮256),在文本模式下它的數目不會超過100個字符。顯然你將獲得超過兩倍的存儲數據大小。
此外,有些情況下您必須遵守像IPv4這樣的網絡包的結構規範。

讓我們舉個例子

//No padding 
typedef struct abc 
{ 
int a:4 
char b; 
double c; 
} A[]={{.a=4,.b='a',.c=7.45},{.a=24,.b='z',.c=3.2}} ; 

是不是很難在文本存儲位字段mode.obviously你要寬鬆很多事情。

但是,您可以像使用MIME一樣以文本格式保存數據對象,但它需要額外的例程以二進制模式進行轉換;表演敲定了。

+0

+1代碼。在你的代碼中,你的意思是我最好使用文本模式將'A'寫入文件?如果是這樣,怎麼樣?只需將每個數據成員的值以純文本形式寫入文件,然後再讀取這些值以創建數據對象? – Alcott 2012-08-16 06:26:28

+0

:),這將是非常困難的,你可以在文本模式下使用XML之類的方法來編寫,如'<實例n =「0」type =「Text」> 4'但最後你將不得不轉換成正常運行的二進制文件。在普通的二進制文件中,只需要將結構的值轉儲到文件中。在讀操作中,如果目標結構符合規範,擔心如何閱讀。隨着光標前進,數組將繼續填充。 – perilbrain 2012-08-16 06:36:05

5

歷史上,二進制模式是提供或多或少透明的訪問 到基礎流;文本模式「標準化」爲標準文本 表示,其中行由單個'\n' 字符終止。另外,系統可以對二進制文件的大小 施加限制,例如通過要求它是128字節或 512字節的倍數。 (首先是CP/M的情況,這是DEC OS的許多 中的第二個)。文本文件沒有此限制,並且在OS被強加的情況下,庫通常會引入額外的端點 文本文件的文件字符。 (即使在今天,當以文本 模式讀取時,大多數Windows 庫都會識別文件的舊CP/M結尾0x1A。)由於這些考慮,文本模式僅在 上定義了一組有限的二進制值。 (但是,如果您將200字節寫入二進制文件 ,則在重新讀取時可能會返回256或512.從歷史上看, 二進制文件只能用於其他結構化的文本,因此 您可以識別邏輯結束,並忽略這些額外的 字節。)

另外,您可以在二進制文件 模式下打開的文件中任意搜索;您只能在文本模式下尋找到開始或已經記住的位置 。 (這是因爲該行結束 映射意味着有在文件中的位置 ,文本流中的位置之間不存在簡單的對應關係。)

注意,這是正交輸出是格式化的還是不: 如果使用<<(和使用>>輸入)輸出,則無論打開文件的模式如何,IO都格式化爲 。並且格式 是總是文本; iostreams被設計爲操縱文本的流,並且僅對非文本輸入和輸出提供有限的支持。

如今,情況已經有所改變:在很多情況下,我們期待什麼 我們寫的是從別的機器,它假設一個很好 定義的格式,可能無法在本機格式使用可讀。 (因此,對於 例如,互聯網期望兩個字節序列0x0D,0x0A作爲行 結束,這與Unix內部以及其他許多操作系統內部使用的內容不同)。如果可移植性是一個問題,則通常定義一個 格式,明確寫入,並使用二進制模式確保你寫的內容正是寫入的內容;同樣在輸入時,您使用二進制 格式,並手動處理約定。如果你只是給 寫了一個本地磁盤,但它不是共享的,但是,文本模式很好,並且有點工作。

再次,這兩個適用於文本。如果你想要一個二進制格式,你必須使用二進制模式,但這遠遠不夠。你必須 自己實現所有格式化的IO。在這種情況下,我一般 不使用std::istreamstd::ostream(其抽象爲文本), 而是定義自己的流類型,從std::ios_base (用於錯誤處理公約)推導和使用std::streambuf(用於 物理IO)。

最後,不要忽略這樣一個事實,即全部 IO被格式化爲一些 的方式。只需在文件中寫入一塊內存就意味着 格式是當前實現給你的任何內容(其中 通常是未記錄的,這意味着將來可能無法使用 進行讀取)。如果你正在做的只是溢出到磁盤上,那麼你將只能讀取它的相同程序,使用相同編譯器的 相同版本進行編譯,然後使用相同的編譯器選項,然後 您可以轉儲內存,前提是有問題的內存只有POD, 並且不包含指針。否則,您必須定義(並記錄)您使用的格式並實施它。在這種情況下,我建議使用現有的格式,如XDR,而不是自己發明: 很容易編寫「使用XDR格式」作爲文檔,而不是 描述所有的實際位和字節佈局不同的 類型。

+0

+1的詳細答案,但我不能說我完全理解,:-)。爲什麼我不能在文本模式下任意搜索?使用'seekg(pos)',我幾乎可以找到文件的每個位置,對吧? – Alcott 2012-08-16 13:04:33

+1

@Alcott因爲標準說它是未定義的行爲。如果'pos'是通過調用'tellg()'返回的值,或者如果'pos'爲'0',則沒有問題。否則,這是未定義的行爲。 (事實上​​,它可以在Unix下工作,並且讓你略微領先於Windows下的位置,在其他操作系統下?誰知道。)\ – 2012-08-16 13:42:22

0

二進制格式更準確地存儲數字,因爲它們存儲在確切的內部表示中。保存數據時沒有會話,因此保存速度更快。