2011-04-13 275 views
1

我想將文件保存爲二進制文件,因爲我聽說它可能比普通文本文件小。將數據保存到二進制文件

現在我試圖用一些文本保存一個二進制文件,但問題是該文件只包含文本,並在末尾包含NULL。我期望在文件中只看到零和一個。

任何解釋或建議,高度讚賞。

這裏是我的代碼

#include <iostream> 
#include <stdio.h> 

int main() 
{ 
    /*Temporary data buffer*/ 
    char buffer[20]; 

    /*Data to be stored in file*/ 
    char temp[20]="Test"; 

    /*Opening file for writing in binary mode*/ 
    FILE *handleWrite=fopen("test.bin","wb"); 

    /*Writing data to file*/ 
    fwrite(temp, 1, 13, handleWrite); 

    /*Closing File*/ 
    fclose(handleWrite); 

    /*Opening file for reading*/ 
    FILE *handleRead=fopen("test.bin","rb"); 

    /*Reading data from file into temporary buffer*/ 
    fread(buffer,1,13,handleRead); 

    /*Displaying content of file on console*/ 
    printf("%s",buffer); 

    /*Closing File*/ 
    fclose(handleRead); 
    std::system("pause"); 

    return 0; 
} 
+0

這是C而不是C++,除了你的一個std ::系統調用 – 2011-04-13 11:29:03

+0

好吧,C然後。但爲什麼它不起作用? – Datoxalas 2011-04-13 11:30:44

回答

10

更換

FILE *handleWrite=fopen("test.bin","wb"); 
fwrite(temp, 1, 13, handleWrite); 

所有文件只包含1和0,二進制計算機這是所有有一起玩。

當您保存文本時,您將保存該文本的二進制表示,在給定的編碼中定義每個字母如何映射到位。

因此對於文本,文本文件或二進制文件幾乎沒有關係;您聽說過的空間節省通常會發揮其他數據類型的作用。

考慮一個浮點​​數,例如3.141592653589。如果保存爲文本,則每個數字需要一個字符(只需對它們進行計數),再加上句點。如果以二進制形式保存爲float位的副本,則在典型的32位系統上需要四個字符(四個字節或32位)。通過調用存儲諸如位的確切數目:

FILE *my_file = fopen("pi.bin", "wb"); 
float x = 3.1415; 
fwrite(&x, sizeof x, 1, my_file); 

CHAR_BIT * sizeof x,見<stdlib.h>CHAR_BIT

+0

感謝您的解釋。 – Datoxalas 2011-04-13 11:40:07

2

好,本地和二進制之間的差異線的末端處理方式。 如果您在二進制文件中編寫字符串,它將保留字符串。

如果你想縮小它,你必須以某種方式壓縮它(例如查找libz)。

更小的是:當想要保存二進制數據(如字節數組)時,將其保存爲二進制而不是將其保存爲字符串(以六進製表示或base64形式)較小。我希望這有幫助。

+0

你的意思是'zlib'還是'libz'? – Datoxalas 2011-04-13 11:50:20

+0

我在說zlib,對不起,快速打字:-) – Bruce 2011-04-13 12:21:17

+0

你能幫我一下嗎? http://stackoverflow.com/questions/5649030/working-with-zlib – Datoxalas 2011-04-13 12:30:23

1

我想你在這裏有點困惑。

將ASCII字符串「Test」寫入文件時(即使在二進制模式下)仍然是ASCII字符串。在寫入二進制文件時有意義的情況是用於除字符之外的其他類型(例如整數數組)。

0

嘗試

FILE *handleWrite=fopen("test.bin","w"); 
fprintf(handleWrite, "%s", temp); 
+0

我收到相同的結果。 – Datoxalas 2011-04-13 11:36:23

+0

查看其他編輯 – Franky 2011-04-13 11:39:15

+0

仍然獲得相同的結果。 – Datoxalas 2011-04-13 11:41:04

0

函數printf(「%s」,buffer);將緩衝區打印爲零結束字符串。

嘗試使用: char temp [20] =「Test \ n \ rTest」;

+0

我在這裏沒有問'printf()'的任何問題。 – Datoxalas 2011-04-13 11:48:33

12

您描述的問題是(很常見的很不常見的)的錯誤和誤解。讓我試着詳細描述正在發生的事情,希望您花時間閱讀所有的材料:它很長,但這些都是任何程序員都應該掌握的非常重要的基礎知識。請不要絕望,如果你不完全瞭解它的全部內容:只是試着玩弄它,回來一兩個星期,練習,看看會發生什麼:)

這些概念之間有一個至關重要的區別字符編碼和字符集合。除非你真的瞭解這種差異,否則你將永遠無法真正瞭解發生了什麼。 Joel Spolsky(Stackoverflow的創始人之一,想起它)寫了一篇文章,解釋了前一段時間的差異:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)。在繼續閱讀本書之前,在繼續編程之前,甚至閱讀它。老實說,閱讀它,理解它:標題是毫不誇張的。你必須絕對知道這個東西。

之後,讓我們繼續:

當C程序運行時,是應該的存儲空間來保存類型爲「字符」中包含的價值,就像任何其他的存儲位置,1的序列和零。一個變量的「類型」只對編譯器有意義,對正在運行的程序來說只是看到一個和零,並且不知道更多。換句話說:你通常認爲在某處存在一個「字母」(來自字符設置爲)的內容的實際存在位序列(來自字符編碼)的元素。

每個編譯器都可以自由使用他們希望在內存中表示字符的任何編碼。因此,它可以自由地在內部表示我們稱之爲「新行」的任何數字。例如,假設我編寫了一個編譯器,我可以同意我自己,每次我想在內部存儲一個「換行符」時,我將它存儲爲數字6(6),二進制文件只有0x6(或者二進制數爲110)。

  • 要寫入文件(fwrite()
  • 事實上在數據:

    寫入一個文件被告知操作系統四件事情在同一時間完成(第一個參數爲fwrite

  • 要寫入多少數據(第二個和第三個參數相乘)
  • 要寫入的文件(最後一個argume nt)

請注意,這與數據的「類型」無關:您的操作不知道,也不在乎。它不知道任何有關字符集的內容,它並不在乎:它只是看到一系列從零開始並將其複製到文件中的序列。

以「二進制」模式打開文件實際上是處理新手程序員期望的文件的正常直觀方式:將指定的內存位置一對一地複製到文件中。如果您編寫一個用於存放編譯器決定存儲爲類型「char」的變量的內存位置,則這些值將一對一地寫入該文件。除非你知道編譯器如何在內部存儲值(它與一個換行符關聯的值,以字母「a」,「b」等),這是無意義的。把這個和Joel的類似點比較一下,這個關於一個文本文件無用而不知道它的編碼是什麼的:同樣的事情。在「文本」模式下打開文件幾乎等於二進制模式,只有一個(且只有一個)差異:任何時候寫入的值都等於編譯器對換行符使用INTERNALLY的值(6,in我們的情況),它寫了一些與文件不同的東西:不是那個值,但是不管你所在的操作系統是否被認爲是換行符。在Windows上,這是兩個字節(在Windows上是13和10,或0x0d 0x0a)。再次注意,如果你不知道編譯器對其他字符的內部表示的選擇,這仍然是無意義的。

請注意,在文本模式下編寫除編譯器指定爲字符的數據之外的任何內容都非常明顯:在我們的例子中,6可能恰好在您的值之中正在寫作,在這種情況下,輸出的改變方式絕對不是我們的意思。 (Un)幸運的是,大多數(所有?)編譯器實際上對字符使用相同的內部表示形式:這種表示形式是US-ASCII,它是所有默認值的母親。這就是您可以在程序中爲某個文件編寫一些「字符」的原因,可以使用任意隨機編譯器進行編譯,然後使用文本編輯器打開它們:它們都使用/理解US-ASCII,並且它正常工作。

好的,現在將其連接到您的示例:爲什麼在編寫二進制模式和文本模式下的「測試」之間沒有區別? 因爲「測試」中沒有換行符,所以!

當你「打開文件」,然後「看到」字符是什麼意思?這意味着你用來檢查該文件中1和0序列的程序(因爲硬盤上的所有內容都是1和0)決定將其解釋爲US-ASCII,而這正好是你的編譯器決定編碼的內容它的內存中的字符串。加分:編寫一個從文件中讀入1和0的程序到存儲器並打印每個BIT(有多個位組成一個字節,提取它們,你需要知道'按位'操作符技巧,谷歌! )作爲「1」或「0」給用戶。請注意,「1」是字符1,即您選擇的字符集中的點,因此您的程序必須佔用一位(數字1或0)並將其轉換爲表示字符1或0所需的位序列編碼,終端模擬器使用你正在查看標準的程序哦,我的上帝。好消息是,通過假定US-ASCII處處可以採取很多捷徑。這個程序會告訴你你想要什麼:你的編譯器用來在內部表示「測試」的序列和零。

這對於新手來說真的很艱鉅,我知道花了很長時間才知道是字符集和編碼之間的區別,更不用說所有這些如何工作了。希望我沒有激勵你,如果我這樣做,只要記住你永遠不會失去你已有的知識,只有獲得它(好吧,不總是正確的:P)。在生活中,聲明提出的問題超出了它的回答,蘇格拉底知道這一點,他的智慧在2.4k年後無縫適用於現代技術。

祝你好運,不要猶豫,繼續問。對於其他讀者:如果您發現錯誤,歡迎您改進本文。

Hraban

是告訴你,「二進制保存文件可能是較小的」,例如人,大概嚴重誤解了這些基礎知識。除非他保存數據之前是指壓縮數據,在這種情況下,他只是使用一個混淆詞(「二進制」)來表示「壓縮」。

「告訴操作系統的東西」就是通常所說的系統調用。

相關問題