關於二進位制檔案與文字檔案
所謂的文字檔案其實就是資料格式為字元型,用記事本就能開啟的檔案,它儲存在計算機中以二進位制的方式儲存,當讀出來的時候需要解碼,單個字元逐個解碼,用UTF-8解碼還是unicode取決於使用者設定的文字編碼。
當資料型別為整型寫入檔案,用記事本開啟就是亂碼,因為記事本只能按照文字型(char)解析,這時要用先讀出二進位制,再轉成十進位制。
以下給出一段驗證的C語言程式碼:
//#include <stdlib.h> #include <stdio.h> #include <locale.h> #include <stddef.h> #include <wchar.h> #include "include/myheader.h" #define SIZE 1 #define LENGTH 1 int main(int argc, char *argv[]) { int buf[SIZE]={0}; FILE *fp; //wchar_t str=L'嚴'; buf[0]=2005; fp=fopen("/home/postgres/mytmp/pgfiles_test/copy","wb+"); if(fp!=NULL){ if(fwrite(buf,LENGTH,LENGTH,fp)>=0){ fflush(fp); puts("寫入檔案成功"); }else{ perror("寫入檔案失敗"); return 1; } }else{ perror("開啟檔案"); } if(fclose(fp)!=-1) puts("關閉檔案成功"); else perror("關閉檔案失敗"); //reading... fp=fopen("/home/postgres/mytmp/pgfiles_test/copy","rb+"); if(fp!=NULL){ if(fread(buf,LENGTH,LENGTH,fp)>=0) puts("讀取檔案成功"); else{ perror("讀取檔案失敗"); return 1; } }else{ perror("開啟檔案失敗"); } printf("the content:%d",buf[0]); fclose(fp); return 0; }
下面是是寫的比較好的一篇文章,看完就明。
出處: http://www.cnblogs.com/flying-roc/articles/1798817.html
一).一般問題
二進位制檔案與我們通常使用的文字檔案儲存方式有根本的不同。這樣的不同很難用言語表達,自己親自看一看,理解起來會容易得多。因此,我推薦學習二進位制檔案讀寫的朋友安裝一款十六進位制編輯器。這樣的編輯器有很多,在我們的 CVF 附帶的整合開發環境下就可以(將二進位制檔案拖動到 IDE 視窗後鬆開)。Visual Studio 2005 也是可以的。(不過需要在 File 選單下 Open,File)
另外推薦一款使用較多的軟體,叫做 UltraEdit(以下簡稱 UE)。是很不錯的文字編輯器,也能做十六進位制編輯器使用。
為什麼要用十六進位制編輯器?而不用 2 進位制呢?因為 2 進位制實在太小,書寫起來會很長,很不直觀。而我們的計算機把 8 位作為一個位元組。剛好 2 ** 8 = 256 = 16 ** 2。用 8 位 2 進製表達的數,我們用 2 個十六進位制資料來表達,更直觀和方便。
二).檔案格式
所有檔案,籠統意義上將可以區分為兩類,一類是文字檔案,一類是二進位制檔案。
1).文字檔案
文字檔案用記事本等文字編輯器開啟,我們可以看懂上面的資訊。所以使用比較廣泛。通常一個文字檔案分為很多很多行,作為資料儲存時,還有列的概念。實際上,儲存在硬碟或其他介質上,檔案內容是線一樣儲存的,列是用空格或 Tab 間隔,行是用回車和換行符間隔。
以 ANSI 編碼(使用較多)的文字檔案來說,例如我們儲存如下資訊:
引用: 10
11
12
需要的空間是:3 行 × 每行 2 個字元 + 2 個回車符 + 2 個換行符 = 10 位元組。文字檔案儲存資料是有格式,無資料型別的。比如 10 這個資料,並不指定是整型還是實型還是字串。它有長度,就是 2,兩個位元組。儲存時計算機儲存它的 ASCII 碼:31h,30h。(十六進位制表示)。回車符是:0Dh,換行符:0Ah。
因此,這個資料儲存是這樣的:
引用: 31 30 0D 0A 31 31 0D 0A 31 32
(紅色為回車符和換行符) 31h 30h 就是 10,31h 31h 就是 11,31h 32h 就是 12。因此我們也可以認為文字檔案是特殊的二進位制檔案。
2).二進位制檔案
二進位制檔案,是無格式有資料型別的。比如上面的 10 11 12 三個數。但二進位制檔案沒有行的概念。我們要緊湊地儲存他們。(當然也可以中間加入一些空白的位元組)
從資料型別上來說,我們首先考慮整型。如果把 10 11 12 當作 2 字長的整型。則 10 表示為:0Ah 00h。因為 0Ah 對應十進位制 10。而後面的 00h 是空白位。2 字長的整型如果不足 FFh,也就是不足 255,則需要一個空白位。類似的:11 表示為 0Bh 00h,12 表示為 0Ch 00h。
當整型資料超過 255 時,我們需要 2 個位元組來儲存。比如 2748(ABCh),則表示為:BCh 0Ah。要把低位寫在前面(BCh),高位寫在後面(0Ah)。
當整型資料超過 65535 時,我們就需要 4 個位元組來儲存。比如 439041101(1A2B3C4Dh),則表示成:4Dh 3Ch 2Bh 1Ah。當資料再大時,我們就需要 8 位元組儲存了。
二進位制檔案的實型資料也有位元組長度的區分,比如 4 字長,8 字長。但實型資料的長度並不僅僅代表它的表達的範圍,更多的代表精度。所以,8 字長的我們又稱為雙精度。關於實型資料如何儲存為 2 進位制。則有很多套規則。現在都廣泛使用的是 IEEE 標準浮點格式。關於這樣的規則,我還正在瞭解,比較麻煩。就不多說了。在這裡也沒有必要了解。
二進位制檔案也可以儲存字元型資料,儲存方法和文字檔案一樣。都是使用 ASCII 編碼儲存的。所以我們用記事本開啟某些二進位制檔案時,也能看到一些有意義的字串。(無意義的亂碼我們可以認為是整型或實型,不過記事本程式當作字元來解釋,因此造成了亂碼)
三).使用二進位制檔案的好處
為什麼要使用二進位制檔案。原因大概有三個:
第一是二進位制檔案比較節約空間,這兩者儲存字元型資料時並沒有差別。但是在儲存數字,特別是實型數字時,二進位制更節省空間,比如儲存 Real*4 的資料:3.1415927,文字檔案需要 9 個位元組,分別儲存:3 . 1 4 1 5 9 2 7 這 9 個 ASCII 值,而二進位制檔案只需要 4 個位元組(DB 0F 49 40)
第二個原因是,記憶體中參加計算的資料都是用二進位制無格式儲存起來的,因此,使用二進位制儲存到檔案就更快捷。如果儲存為文字檔案,則需要一個轉換的過程。在資料量很大的時候,兩者就會有明顯的速度差別了。
第三,就是一些比較精確的資料,使用二進位制儲存不會造成有效位的丟失。
四).二進位制檔案的儲存方式
列舉一個二進位制檔案如下:
引用: 00000000h: 0F 01 00 00 0F 03 00 00 12 53 21 45 58 62 35 34 ; .........S!EXb54
00000010h: 41 42 43 44 45 46 47 48 49 47 4B 4C 4D 4E 4F 50 ; ABCDEFGHIGKLMNOP
這裡列出的是在 UltraEdit(UE) 裡看到的東西。其實只有紅色部分是檔案內容。前面的是 UE 加入的行號。後面的是 UE 嘗試解釋為字元型的參考。
這個檔案一共有 32 位元組長。顯示為兩列,每列 16 個位元組。實際上,這僅僅是 UE 的顯示而已。真實的檔案並不分行。僅僅知道這個檔案的內容,如果我們沒有任何說明的話,是不能看出任何有用資訊的。
下面我規定一下說明:我們認為,前 4 個位元組是一個 4 位元組的整型資料(0F 01 00 00 十六進位制:10Fh 十進位制:271)。這 4 個位元組之後的 4 個位元組是另一個 4 位元組的整型資料(0F 03 00 00 十六進位制:30Fh 十進位制:783)。其後的 4 個位元組(12 53 21 45 )表示一個 4 位元組的實型資料:2.5811919E+3。再其後的 4 個位元組(58 62 35 34)表示另一個 4 位元組的實行資料:1.6892716E-7。而只後的 16 個位元組(41 42 43 44
45 46 47 48 49 47 4B 4C 4D 4E 4F 50)我們認為是 16 個位元組的字串(ABCDEFGHIGKLMNOP)
實際上,二進位制檔案只是儲存資料,並不寫明資料型別,比如上面的第 9 位元組到第 16 位元組(12 53 21 45 58 62 35 34),我們剛才認為是 2 個 4 位元組的實型,其實也可以認為是 8 個位元組的字元型( S!EXb54)。而後面的 16 個位元組的字串(ABCDEFGHIGKLMNOP),我們也可以認為是 2 個 8 位元組的整型,或者 4 個 4 位元組的整型,甚至 2 個 8 位元組的實型,4 個 4 位元組的實型,等等等等。
因此,面對一個二進位制檔案,我們不能準確地知道它的含義,我們需要他的資料儲存方式的說明。這個說明告訴我們第幾個位元組到第幾個位元組是什麼型別的資料,儲存的資料是什麼含義。否則的話,我們只能猜測,或者無能為力。
五).如何使用語句操作二進位制檔案
我們將上面的那個二進位制檔案儲存為:TestBin.Bin 來舉例。
讀取和寫入二進位制其實是兩個很類似的操作,瞭解了其中之一,另一個也就不難了。
二進位制檔案我們通常使用直接讀取方式,Open 語句可以寫為:
引用: Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 )
上面的 Access 表示直接讀取方式,Form 表示無格式儲存。比較重要的是 RecL 。我們讀取資料時,是用記錄來描述單位的,每一次讀入或寫入是一個記錄。記錄的長度在 Open 時就確定下來,以後不能改變。如果需要改變,只能 Close 以後再此 Open。
記錄長度在某些編譯器下表示讀取的 4 位元組長度的倍數,規定為 4 表示記錄長度為 16 位元組。有些編譯器下就直接表示記錄的位元組數,規定為 4 則表示記錄長度為 4 位元組。這個問題需要參考編譯器手冊。在 VF 系列裡,這個值是前面一個含義。可以通過設定工程屬性的 Fortran,Data,Use Bytes as RECL= Unit for Unformatted Files 來改變,使之成為後一個含義。在命令列模式下,則使用 /assume:byterecl 這個編譯選項。
確定 RecL 大小是我們需要做的事情,一般來說,不適合太大,也不適合太小。還需要結合資料儲存方式來考慮。太小的話,我們需要執行讀寫的次數就多,太大的話,我們就不方便操作小範圍的資料。
有時候我們甚至會分多次來讀取資料,每一次的 RecL 都不同。對於上面的 TestBin.Bin 檔案來說,它比較簡單,我以 16 位元組長度和 8 位元組長度兩種讀取方式來演示,你甚至可以一次 32 個位元組長度全部讀完:
(1)RecL = 4 【記錄長度 16 位元組】
引用: Program main
Implicit None
Integer*4 :: iVar1 , iVar2
Real*4 :: rVar1 , rVar2
Character(Len=16) :: cStr
Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 )
Read( 12 , Rec = 2 ) cStr
Read( 12 , Rec = 1 ) iVar1 , iVar2 , rVar1 , rVar2
Write( * , * ) cStr
Write( * , * ) iVar1 , iVar2 , rVar1 , rVar2
Close( 12 )
End Program main
這裡的 Open 裡指定了 RecL = 4(記錄長度是 16 位元組)。
第一個 Read 語句,直接讀取第二筆記錄(也就是第 17 位元組到第 32 位元組)。讀取出的 cStr = "ABCDEFGHIGKLMNOP"。
第二個 Read 語句,返回來讀取第一筆記錄(也就是前面 16 個位元組)。讀取出的資料分別放入 4 個 4 位元組的變數。(其中前面兩個是整型,後面兩個是實型)
輸出結果為:
ABCDEFGHIGKLMNOP
271 783 2581.192 1.6892716E-07
看到這個結果,就說明我們成功了。
同時我們可以看到,第一個語句,我們直接跳到第二條記錄讀取,並沒有讀取第一條。這就是直接讀取資料的方便。有時候我們根本不需要某些資料,這時候,我們可以直接跳到某一條記錄上。這個記錄甚至可以是我們實現算出來的變數。比如:
iRec = ( a + b ) / C
Read( 12 , Rec = iRec ) cStr
實現我們儲存了 100 天的資料,我們只需要第 21 天的資料,我們怎麼辦?在順序讀取時,我們可能會開闢一個 100 元素的陣列,或者迴圈執行 20 次空白的讀取。但是在直接讀取時,我們只需要執行一句 Read( 12 , Rec = 21 )。這是多麼的方便。(直接讀取和順序讀取雖然於文字檔案和二進位制檔案沒有直接的關聯,但是文字檔案通常用順序讀取,而二進位制檔案通常用直接讀取。這是他們的性質決定的。)
(2)RecL = 2【記錄長度為 8 位元組】
引用: Program main
Implicit None
Integer*4 :: iVar1 , iVar2
Real*4 :: rVar1 , rVar2
Character(Len=16) :: cStr
Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 2 )
Read( 12 , Rec = 4 ) cStr( 9 : 16 )
Read( 12 , Rec = 3 ) cStr( 1 : 8 )
Read( 12 , Rec = 1 ) iVar1 , iVar2
Read( 12 , Rec = 2 ) rVar1 , rVar2
Write( * , * ) cStr
Write( * , * ) iVar1 , iVar2 , rVar1 , rVar2
Close( 12 )
End Program main
這裡設定的 RecL = 2 ,意思是一筆記錄 8 個位元組。所以我們不能一次讀取 cStr 這個 16 位元組的字串。我們必須分兩次讀取。第一次讀取第 4 筆記錄,放入字串後半段。第二次讀取第 3 筆記錄,放入字串前半段。(可以調換位置)。然後讀取第一筆記錄的兩個整型變數和第二筆記錄的兩個實型變數。
輸出結果和(1)的方法一樣。
(3)寫入二進位制檔案
寫入二進位制檔案同樣需要考慮 RecL 的問題。我們這裡以 RecL = 4 來舉例。
引用: Program main
Implicit None
Open( 12 , File = 'TestBinW.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 )
Write( 12 , Rec = 1 ) 271 , 783 , 2581.192_4 , 1.6892716E-07
Write( 12 , Rec = 2 ) "ABCDEFGHIGKLMNOP"
Close( 12 )
End Program main
寫入二進位制檔案和讀取二進位制檔案是差不多的,我就不再解釋了。需要注意的是,如果直接寫入第 N 筆記錄,而檔案沒有隻有 M 筆記錄(M < N),那麼,第 M+1 到第 N-1 筆記錄會用 0 填充。也就是說,二進位制檔案不會出現斷裂。
二進位制檔案的讀寫是比較靈活的,實際應用中,我們使用哪種方式,我們應該根據自己的情況來設計。如何選擇合適的記錄長度 RecL,如何設計高效的儲存方式等。
相關推薦
二進位制檔案與文字檔案的區別
文字檔案和二進位制檔案的定義: 計算機在實體記憶體上面存放的都是二進位制,所以文字檔案和二進位制檔案的主要區別是在邏輯上的而不是物理上的。而從檔案的編碼方式來看,檔案可以分為文字檔案和二進位制檔案。
關於二進位制檔案與文字檔案
所謂的文字檔案其實就是資料格式為字元型,用記事本就能開啟的檔案,它儲存在計算機中以二進位制的方式儲存,當讀出來的時候需要解碼,單個字元逐個解碼,用UTF-8解碼還是unicode取決於使用者設定的文字編碼。 當資料型別為整型寫入檔案,用記事本開啟
二進位制檔案轉文字檔案的實現
/*說明:程式只能處理不帶回車/換行的二進位制檔案。 [bina.txt]內容如下:----------------------------------------------------------------------0100100100100000011001010
java中如何判斷一個檔案是二進位制檔案還是文字檔案?
現在的做法是把檔案讀進來,逐個解析每一個byte,如果有一個byte<0那麼斷定這個檔案是二進位制的,這在純英文的環境下可以工作,但是如果一個文字包含了中文字元,那麼這個檔案也會被判斷為二進位制檔案。 我在網上看看到有人也是逐個比較每一個byte,只不過是如果有一個b
判斷檔案是二進位制檔案還是文字檔案的函式
#include "sys/stat.h" bool IsTextFile(const char * strFileName) { if(strFileName==NULL) return false; struct stat f_stat; if(stat(strFi
二進位制檔案和文字檔案的區別和聯絡
將檔案看作是由一個一個位元組(byte) 組成的,那麼文字檔案中的每個位元組的最高位都是0,也就是說文字檔案使用了一個位元組中的七位來表示所有的資訊,而二進位制檔案則是將位元組中的所有位都用上了。這就是兩者的區別; 接著,第二個問題就是檔案按照文字方式或者二進位制方式
Spring MVC - MultipartFile實現檔案上傳(單檔案與多檔案上傳)
前提:引入jar包。 <dependency>
靜態檔案與模板檔案配置
STATIC_URL = '/static/' # 設定靜態檔案路徑,這裡改變的是使用者請求靜態檔案的網址路徑 #這是配置伺服器靜態檔案放置的位置 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'shop/static'),
【Python筆記】操作讀取Excel檔案、文字檔案
需求:讀取Excel檔案、替換文字檔案中得指定某個字串並生成新的檔案 原始碼: #encoding:utf-8 # -*- coding: utf-8 -*- #!/usr/bin/env python # -*- coding=utf-8 -*- #Using GPL v2 #Author:
php 解壓檔案與壓縮檔案
配置環境變數 然後cmd 輸入 php -m 檢視是否有zip 選項 沒有的話zip功能將無法使用 function zip_file(string $filename) { if (!is_file($filename)) { return false;
php 上傳檔案與下載檔案
上傳 /** * 單檔案上傳 * @param array $fileInfo 檔案資訊 是一個數組 * @param string $uploadPATH 檔案上傳預設路徑 * @param bool $imageFlag 是否檢測真實圖片 * @param arr
java讀取檔案與寫入檔案
1. Java按行讀取Resource目錄下的檔案 List<String> historyList = new ArrayList<>(); ClassPathResource classPathResource = new ClassPathResource("tes
檔案操作--文字檔案
1.FileStream 類: 1.1構造 FileStream物件表示在磁碟或網路路徑上指向檔案的流。這個類提供了在檔案中讀寫位元組的方法; 可以隨機檔案訪問(訪問檔案中間某點的資料)。其他Stream類可以讀寫字元資料,但不能隨機訪問檔案; FileStream aF
將字串寫入檔案與讀取檔案
一,讀取檔案內容 File file = new File(filePath); if(file.isFile() && file.exists()) {
java檔案,class檔案與dex檔案的轉化。(詳細教程)
筆者這兩天整理的關於安卓逆向的一些小知識:教你如何在這三種檔案中來去自如: .java檔案 Java原始檔 .class檔案 Java位元組碼檔案,是一種能夠被Java虛擬機器(JVM:Java Virtual Machine)識別,載入並且執行的檔案格式。 .
Java pcm檔案與wav檔案互轉
Java pcm檔案與wav檔案互轉 2018年05月15日 14:32:28 -過期罐頭 閱讀數:1432 版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/lys1220/article/details/80322562 程式碼所需要的
在ubuntu與qtcreator中,如何將.a檔案與.so檔案存放在工程目錄下並進行第三方庫的連結
目錄 背景: 執行環境: 3.連結庫 背景: 由於專案要在不同的計算機(Ubuntu系統)之間進行遷移,專案所依賴的第三方庫(包括動態連結庫以及靜態連結庫)在其他的計算機上並不一定存在,因此,打算將第三方庫放入專案的工程目錄下,在專案
mybatis全域性配置檔案與對映檔案詳解
一、全域性配置檔案 1、概述 (1)SqlMapConfig.xml的配置內容和順序如下(順序不能亂): Properties(屬性) Settings(全域性引數設定) typeAliases(類型別名) typeHandlers(型別處理器)
將jar檔案與dex檔案的轉換
一、dex檔案轉為jar檔案 1.第一篇 Android 反編譯資料整理 Made by 李文棟 [email protected] 2010-12-13 Monday 於北京 一、反編譯流程圖 二、工具使用方法(命令
【Eclipse】根據檔名查詢檔案與根據檔案中的字串查詢檔案
在大型專案開發中,你經常需要在Eclipse左方那龐大的檔案樹中尋找你需要的檔案。 此時,你直接使用Ctrl+Shift+R就可以喚出檔案查詢視窗。這是根據檔名來找檔案,如下圖,只要輸入你需要尋找的檔名,就能得到相應的尋找結果。 如果你需要根據檔案中的字串查詢檔案,那麼,