二進(jìn)制文件讀寫(xiě)(寫(xiě)給新手)FortranFortran
一).一般問(wèn)題 另外推薦一款使用較多的軟件,叫做 UltraEdit(以下簡(jiǎn)稱(chēng) UE)。是很不錯(cuò)的文本編輯器,也能做十六進(jìn)制編輯器使用。 為什么要用十六進(jìn)制編輯器?而不用 2 進(jìn)制呢?因?yàn)?nbsp;2 進(jìn)制實(shí)在太小,書(shū)寫(xiě)起來(lái)會(huì)很長(zhǎng),很不直觀。而我們的計(jì)算機(jī)把 8 位作為一個(gè)字節(jié)。剛好 2 ** 8 = 256 = 16 ** 2。用 8 位 2 進(jìn)制表達(dá)的數(shù),我們用 2 個(gè)十六進(jìn)制數(shù)據(jù)來(lái)表達(dá),更直觀和方便。 二).文件格式 所有文件,籠統(tǒng)意義上將可以區(qū)分為兩類(lèi),一類(lèi)是文本文件,一類(lèi)是二進(jìn)制文件 1).文本文件 文本文件用記事本等文本編輯器打開(kāi),我們可以看懂上面的信息。所以使用比較廣泛。通常一個(gè)文本文件分為很多很多行,作為數(shù)據(jù)儲(chǔ)存時(shí),還有列的概念。實(shí)際上,儲(chǔ)存在硬盤(pán)或其他介質(zhì)上,文件內(nèi)容是線一樣儲(chǔ)存的,列是用空格或 Tab 間隔,行是用回車(chē)和換行符間隔。 以 ANSI 編碼(使用較多)的文本文件來(lái)說(shuō),例如我們儲(chǔ)存如下信息: 10 11 12 因此,這個(gè)數(shù)據(jù)儲(chǔ)存是這樣的: 31 30 0D 0A (紅色為回車(chē)符和換行符) 31h 30h 就是 10,31h 31h 就是 11,31h 32h 就是 12。因此我們也可以認(rèn)為文本文件是特殊的二進(jìn)制文件 2).二進(jìn)制文件 二進(jìn)制文件 從數(shù)據(jù)類(lèi)型上來(lái)說(shuō),我們首先考慮整型。如果把 10 11 12 當(dāng)作 2 字長(zhǎng)的整型。則 10 表示為:0Ah 00h。因?yàn)?nbsp;0Ah 對(duì)應(yīng)十進(jìn)制 10。而后面的 00h 是空白位。2 字長(zhǎng)的整型如果不足 FFh,也就是不足 255,則需要一個(gè)空白位。類(lèi)似的:11 表示為 0Bh 00h,12 表示為 0Ch 00h。 當(dāng)整型數(shù)據(jù)超過(guò) 255 時(shí),我們需要 2 個(gè)字節(jié)來(lái)儲(chǔ)存。比如 2748(ABCh),則表示為:BCh 0Ah。要把低位寫(xiě)在前面(BCh),高位寫(xiě)在后面(0Ah)。 當(dāng)整型數(shù)據(jù)超過(guò) 65535 時(shí),我們就需要 4 個(gè)字節(jié)來(lái)儲(chǔ)存。比如 439041101(1A2B3C4Dh),則表示成:4Dh 3Ch 2Bh 1Ah。當(dāng)數(shù)據(jù)再大時(shí),我們就需要 8 字節(jié)儲(chǔ)存了。 二進(jìn)制文件 二進(jìn)制文件 三).使用二進(jìn)制文件 為什么要使用二進(jìn)制文件 第一是二進(jìn)制文件 第二個(gè)原因是,內(nèi)存中參加計(jì)算的數(shù)據(jù)都是用二進(jìn)制無(wú)格式儲(chǔ)存起來(lái)的,因此,使用二進(jìn)制儲(chǔ)存到文件就更快捷。如果儲(chǔ)存為文本文件,則需要一個(gè)轉(zhuǎn)換的過(guò)程。在數(shù)據(jù)量很大的時(shí)候,兩者就會(huì)有明顯的速度差別了。 第三,就是一些比較精確的數(shù)據(jù),使用二進(jìn)制儲(chǔ)存不會(huì)造成有效位的丟失。 四).二進(jìn)制文件 列舉一個(gè)二進(jìn)制文件 00000000h: 0F 01 00 00 0F 03 00 00 12 53 21 45 58 62 35 34 00000010h: 41 42 43 44 45 46 47 48 49 47 4B 4C 4D 4E 4F 50 這里列出的是在 UltraEdit(UE) 里看到的東西。其實(shí)只有紅色部分是文件內(nèi)容。前面的是 UE 加入的行號(hào)。后面的是 UE 嘗試解釋為字符型的參考。 這個(gè)文件一共有 32 字節(jié)長(zhǎng)。顯示為兩列,每列 16 個(gè)字節(jié)。實(shí)際上,這僅僅是 UE 的顯示而已。真實(shí)的文件并不分行。僅僅知道這個(gè)文件的內(nèi)容,如果我們沒(méi)有任何說(shuō)明的話,是不能看出任何有用信息的。 下面我規(guī)定一下說(shuō)明:我們認(rèn)為,前 4 個(gè)字節(jié)是一個(gè) 4 字節(jié)的整型數(shù)據(jù)(0F 01 00 00 十六進(jìn)制:10Fh 十進(jìn)制:271)。這 4 個(gè)字節(jié)之后的 4 個(gè)字節(jié)是另一個(gè) 4 字節(jié)的整型數(shù)據(jù)(0F 03 00 00 十六進(jìn)制:30Fh 十進(jìn)制:783)。其后的 4 個(gè)字節(jié)(12 53 21 45 )表示一個(gè) 4 字節(jié)的實(shí)型數(shù)據(jù):2.5811919E+3。再其后的 4 個(gè)字節(jié)(58 62 35 34)表示另一個(gè) 4 字節(jié)的實(shí)行數(shù)據(jù):1.6892716E-7。而只后的 16 個(gè)字節(jié)(41 42 43 44 45 46 47 48 49 47 4B 4C 4D 4E 4F 50)我們認(rèn)為是 16 個(gè)字節(jié)的字符串(ABCDEFGHIGKLMNOP) 實(shí)際上,二進(jìn)制文件 因此,面對(duì)一個(gè)二進(jìn)制文件 五).如何使用語(yǔ)句操作二進(jìn)制文件 我們將上面的那個(gè)二進(jìn)制文件 讀取和寫(xiě)入二進(jìn)制其實(shí)是兩個(gè)很類(lèi)似的操作,了解了其中之一,另一個(gè)也就不難了。 二進(jìn)制文件 Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 ) 上面的 Access 表示直接讀取方式,F(xiàn)orm 表示無(wú)格式儲(chǔ)存。比較重要的是 RecL 。我們讀取數(shù)據(jù)時(shí),是用記錄來(lái)描述單位的,每一次讀入或?qū)懭胧且粋€(gè)記錄。記錄的長(zhǎng)度在 Open 時(shí)就確定下來(lái),以后不能改變。如果需要改變,只能 Close 以后再此 Open。 記錄長(zhǎng)度在某些編譯器下表示讀取的 4 字節(jié)長(zhǎng)度的倍數(shù),規(guī)定為 4 表示記錄長(zhǎng)度為 16 字節(jié)。有些編譯器下就直接表示記錄的字節(jié)數(shù),規(guī)定為 4 則表示記錄長(zhǎng)度為 4 字節(jié)。這個(gè)問(wèn)題需要參考編譯器手冊(cè)。在 VF 系列里,這個(gè)值是前面一個(gè)含義。可以通過(guò)設(shè)置工程屬性的 Fortran 確定 RecL 大小是我們需要做的事情,一般來(lái)說(shuō),不適合太大,也不適合太小。還需要結(jié)合數(shù)據(jù)儲(chǔ)存方式來(lái)考慮。太小的話,我們需要執(zhí)行讀寫(xiě)的次數(shù)就多,太大的話,我們就不方便操作小范圍的數(shù)據(jù)。 有時(shí)候我們甚至?xí)侄啻蝸?lái)讀取數(shù)據(jù),每一次的 RecL 都不同。對(duì)于上面的 TestBin.Bin 文件來(lái)說(shuō),它比較簡(jiǎn)單,我以 16 字節(jié)長(zhǎng)度和 8 字節(jié)長(zhǎng)度兩種讀取方式來(lái)演示,你甚至可以一次 32 個(gè)字節(jié)長(zhǎng)度全部讀完: (1)RecL = 4 【記錄長(zhǎng)度 16 字節(jié)】 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(記錄長(zhǎng)度是 16 字節(jié))。 第一個(gè) Read 語(yǔ)句,直接讀取第二筆記錄(也就是第 17 字節(jié)到第 32 字節(jié))。讀取出的 cStr = "ABCDEFGHIGKLMNOP"。 第二個(gè) Read 語(yǔ)句,返回來(lái)讀取第一筆記錄(也就是前面 16 個(gè)字節(jié))。讀取出的數(shù)據(jù)分別放入 4 個(gè) 4 字節(jié)的變量。(其中前面兩個(gè)是整型,后面兩個(gè)是實(shí)型) 輸出結(jié)果為: ABCDEFGHIGKLMNOP 271 783 2581.192 1.6892716E-07 看到這個(gè)結(jié)果,就說(shuō)明我們成功了。 同時(shí)我們可以看到,第一個(gè)語(yǔ)句,我們直接跳到第二條記錄讀取,并沒(méi)有讀取第一條。這就是直接讀取數(shù)據(jù)的方便。有時(shí)候我們根本不需要某些數(shù)據(jù),這時(shí)候,我們可以直接跳到某一條記錄上。這個(gè)記錄甚至可以是我們實(shí)現(xiàn)算出來(lái)的變量。比如: iRec = ( a + b ) / C Read( 12 , Rec = iRec ) cStr 實(shí)現(xiàn)我們儲(chǔ)存了 100 天的數(shù)據(jù),我們只需要第 21 天的數(shù)據(jù),我們?cè)趺崔k?在順序讀取時(shí),我們可能會(huì)開(kāi)辟一個(gè) 100 元素的數(shù)組,或者循環(huán)執(zhí)行 20 次空白的讀取。但是在直接讀取時(shí),我們只需要執(zhí)行一句 Read( 12 , Rec = 21 )。這是多么的方便。(直接讀取和順序讀取雖然于文本文件和二進(jìn)制文件 (2)RecL = 2【記錄長(zhǎng)度為 8 字節(jié)】 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 這里設(shè)定的 RecL = 2 ,意思是一筆記錄 8 個(gè)字節(jié)。所以我們不能一次讀取 cStr 這個(gè) 16 字節(jié)的字符串。我們必須分兩次讀取。第一次讀取第 4 筆記錄,放入字符串后半段。第二次讀取第 3 筆記錄,放入字符串前半段。(可以調(diào)換位置)。然后讀取第一筆記錄的兩個(gè)整型變量和第二筆記錄的兩個(gè)實(shí)型變量。 輸出結(jié)果和(1)的方法一樣。 (3)寫(xiě)入二進(jìn)制文件 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 寫(xiě)入二進(jìn)制文件 二進(jìn)制文件 |
|
|
來(lái)自: 千里之外yh > 《我的圖書(shū)館》