1. 程式人生 > >Fortran之open,write,read,inquire,Namelist 使用

Fortran之open,write,read,inquire,Namelist 使用

1.檔案讀取的概念:
讀取:“順序讀取”和“直接讀取”。
儲存:“文字檔案”和“二進位制檔案”。
二進位制檔案:讀取快,因為儲存格式和資料在記憶體中的儲存方法一樣,同時也節省空間。
----------------------------------

2. 檔案的操作:
----------------------------------
open的使用:使用open命令開啟檔案之後,就可以對檔案來做輸入輸出。
example:
program ex0901
impicit none
open(unit=10, file='hello.txt')   ! 開啟hello.txt檔案, unit指定檔案程式碼,file指定檔名稱。

write(10, *) "hello"            !在程式碼為10的檔案中寫入hello
stop
end program ex0901

open中有很多引數可以使用,詳細如下:
OPEN(UNIT=number, FILE='filename', FORM='...', STATUS='...', ACCESS='...', RECL=length, ERR=label, IOSTAT=iostat, BLANK='...', POSITION='...', ACTION=action, PAD='...', DELIM='...')

UNIT='number':number必須是一個正整數,它可以使用變數或是常量來賦值。number最好避開1,2,5,6。因為2,6是預設的輸出位置,也就是螢幕。1,5則是預設的輸入位置,鍵盤。


FILE='filename': 指定要開啟的檔名稱,檔名要符合系統規定。windows下不區分大小寫,unix下則會區分大小寫,最好不要使用中文檔名。

FORM='FORMATTED' OR 'UNFORMATTED'
FORM欄位只有兩個值可以設定:
FORM='FORMATTED'      “文字檔案”格式來儲存
FORM='UNFORMATTED'   “二進位制檔案”格式儲存
這一欄不給定時候的預設值是: FORM='FORMATTED'

STATUS='NEW' or 'OLD' or 'SCRATCH' or 'UNKNOWN' 用來說明開啟一個新的檔案或已經存在的舊檔案。
STATUS='NEW'        開啟一個原本不存在的新檔案

STATUS='OLD'         開啟一個原來已經存在的檔案
STATUS='REPLACE'   若檔案已經存在則重新建立一次,原來的內容消失;若不存在則會建立新檔案。
STATUS='SCRATCH'   表示要開啟一個暫存文盤,這個時候可以不需要指定檔名稱,也就是FILE這個一欄可以忽略。因為程式本身會自動取一個檔名,至於檔名是啥也不重要,因為暫存檔會在程式結束後自動刪除。
STATUS='UNKNOWN' 由各編譯器自定義。通常會同REPLACE的效果。
!這一欄不給定時,預設為STATUS='UNKNOWN'。

ACCESS='SEQUENTIAL' or 'DIRECT'   設定讀寫檔案的方法:
ACCESS='SEQUENTIAL'    讀寫檔案的操作會以“順序”的方法來做讀寫,“順序讀取檔案”。
ACCESS='DIRET'          讀寫檔案的操作可以任意指定位置,“直接讀取檔案”。
!不賦值時候,預設為: ACCESS='SEQUENTIAL'。

RECL=length 在順序讀取檔案中,RECL欄位值用來設定一次可以讀取多大容量的資料。
開啟“直接讀取檔案”,RECL=length的length值是用來設定檔案中每一個模組單元的分割槽長度。
length的單位在文字根式下為1個字元,也就是1 byte。在二進位制格式下則由編譯器自行決定,一般可能為1 byte (G77) 或 4 byte (Visual Fortran)。

ERR=LABEL 這個欄位用來設定當檔案打開發生錯誤時,程式會跳躍到LABEL所指定的行程式碼處來繼續執行程式。

IOSTAT=var 這個欄位會設定一個整數值給後面的整型變數,這是用來說明檔案開啟的狀態,數值會有下面三種情況:
var>0     表示讀取操作錯誤
var=0     表示讀取操作正常
var<0     表示檔案終了

BLANK='NULL' or 'ZERO' 用來設定輸入數字時,當所設定的格式欄位中有空格存在時所代表的意義。
BLANK='NULL'時,空格代表沒有東西。BLANK='ZERO'時,空格部分會自動以0代入。

以下是Fortran 90新增的功能:
POSITION='ASIS' or 'REWIND' or 'APPEND'   設定檔案開啟時候的讀寫位置:
POSITION='ASIS'   表示檔案開啟時的讀取的位置不特別指定,通常就是在檔案的開頭。是預設值。
POSITION='REWIND'      表示檔案開啟時的讀取位置移到檔案的開頭。
POSITION='APPEND'     表示檔案開啟時的讀取位置移到檔案的結尾。

ACTION='READ' or 'WRITE' or 'READWRITE'   設定開啟檔案的讀寫許可權:
ACTION='READWRITE'    表示所開啟的檔案可以用來讀取及寫入,這是預設值。
ACTION='READ'          表示所開啟的檔案只能用來讀取資料。
ACTION='WRITE'         表示所開啟的檔案只能用來寫入資料。

PAD='YES' or 'NO'
PAD='YES'   在格式化輸入時,最前面的不足欄位會自動以空格填滿,預設值是PAD='YES'。
PAD='NO'    在格式化輸入時,不足的欄位不會自動以空格填滿。

DELIM='APOSTEROPHE' or 'QUOTE' or 'NONE'
DELIM='NONE'       純粹輸出字串內容
DELIM='QUOTE'      輸出字串內容會在前後加上雙引號
DELIM='APOSTEROPHE'   輸出字串內容會在前後加上單引號
-----------------------------------------

WRITE & READ的使用(詳細):
WRITE/READ(UNIT=number, FMT=format, NML=namelist, REC=record, IOSTAT=stat, ERR=errlabel, END=endlabel, ADVANCE=advance, SIZE=size)

UNIT=number    指定read/write所使用的輸入輸出的位置。
FMT=format    指定輸入輸出格式的使用。
NML=namelist   指定讀寫某個NAMELIST的內容(後續介紹)。
REC=record      在直接讀取檔案中,設定所要讀寫的檔案的模組位置。
IOSTAT=stat     會設定一個數值給在它後面的變數,用來說明檔案的讀寫狀態。
         stat>0    表示讀取操作發生錯誤。
         stat=0    表示讀取操作正常。
         stat<0    表示檔案終了。
ERR=errlabel     指定在讀寫過程中發生錯誤時,會轉移到某個行程式碼來繼續執行程式。
END=endlabel    指定在讀寫到檔案末尾時,要轉移到某個行程式碼來繼續執行程式。

以下是fortran 90新增功能:
ADVANCE='YES' or 'NO' 設定在文字格式下的順序檔案中,每一次的READ,WRITE命令完成後,
                         讀寫 位置會不會自動想下移動一行。
     ADVANCE='YES'   是預設的狀態,每讀寫一次會向下移動一行。
     ADVANCE='NO'    會暫停自動換行的操作。
     !使用這個欄位時候一定要設定輸出入格式,在螢幕輸出時可以使用這個設定來控制write命令是否會自動換行。
SIZE=count   在ADVANCE='NO'時,才可以使用這個欄位。它會把這一次輸出入的字元數目設定給後面的整型變數。
----------------------------------

查詢檔案的狀態INQUIRE:
在使用open開啟檔案的前後,都可以通過inquire命令來查詢檔案目前的情況,inquire命令中的各個欄位和第一小節中open的欄位很類似。
example: !檢查某個程式是否存在
program ex0903
implicit none
character(len=20) :: filename = "ex0903.f90"
logical alive

inquire(file=filename, exist=alive)
if(alive) then
    write (*, *) filename, " exist."
else
    write (*, *) filename, "doesn't exist."
end if
stop
edn program ex0903

詳細介紹inquire的使用方法:
INQUIRE(UNIT=number, FILE=filename, IOSTAT=stat, ERR=label, EXIST=exist, OPENED=opened, NUMBER=number, NAMED=named, ACCESS=access, SEQUENTIAL=sequential, DIRECT=direct, FORM=form, FORMATTED=formatted, UNFORMATTED=unformatted, RECL=recl)

UNIT=number   檔案代號
FILE=filename   檔名
IOSTAT=stat   查詢檔案讀取情況,會設定一個整數給後面的變數:
         stat>0    檔案讀取操作錯誤
         stat=0    檔案讀取操作正常
         stat<0    檔案終了
ERR=errlabel    發生錯誤時會轉移到複製的程式碼行繼續執行程式。
EXIST=exist    檢查檔案是否存在,返回布林變數,真表示存在,假值表示不存在。
OPEND=opened 檢查檔案是否用已經用open開啟,返回布林變數,真表示已經開啟,假表示尚未開啟。
NUMBER=number   用檔名來查詢這個檔案所給定的程式碼。
NAMED=named   查詢檔案是否取了名字,也就是檢查檔案是否為臨時儲存盤,返回值為邏輯數。
ACCESS=access   檢查檔案的讀取格式,返回一個字串,可以是:
      'SEQUENTIAL'   代表檔案使用順序讀取格式
      'DIRECT'        代表檔案使用直接讀取格式
      'UNDEFINED'    代表沒有定義
SEQUENTIAL=sequential   檢視檔案是否使用順序格式,會返回一個字串,可以是:
      'YES'   代表檔案是順序讀取檔案
      'NO'    代表檔案不是順序讀取檔案
      'UNKNOWN' 代表不知道
DIRECT=direct 檢視檔案是否使用直接格式,會返回一個字串,可以是:
      'YES'    檔案是直接讀取檔案
      'NO'     檔案是非直接讀取檔案
      'UNKNOWN'   代表不知道
FORM=form 檢視檔案的儲存方法,返回字串,可以是:
        'FORMATTED'        開啟的是文字檔案
        'UNFORMATTED'     開啟的是二進位制檔案
        'UNDEFINED'         沒有定義
FORMATTED=fmt 檢視檔案是否是文字檔案,返回字串,可以是:
        'YES'   本檔案是文字檔案
        'NO'    本檔案非文字檔案
        'UNDEFINED' 無法判斷
UNFORMATTED=fmt 檢視檔案是否是二進位制檔案,返回字串,可以是:
        'YES'   本檔案是二進位制檔案
        'NO'    本檔案非二進位制檔案
        'UNKNOWN'   無法判斷
RECL=length 返回open檔案時recl欄的設定值。
NEXTREC=nr     返回下一次檔案讀寫的位置。
BLANK=blank     返回值是字串,用來檢視open檔案時的blank引數所給定的字串值。
以下是fortran 90的新增功能:
POSITION=position             返回開啟檔案時position欄位所給定的字串, 可能是'REWIND',
'APPEND', 'ASIS', 'UNDEFINED'
ACTION=action        返回開啟檔案時action 欄位所賦值的字串,可能是'READ', 'WRITE',
                       'READWRITE'。
READ=read      返回字串,檢查檔案是否為只讀檔案:
                'YES' 檔案是隻讀的
                'NO'   檔案不是隻讀的
                'UNKNOWN' 無法判斷
WRITE=write    返回一個字串,檢查檔案是否可寫入:
                'YES'   檔案可以寫入
                'NO'    檔案不可以寫入
                'UNKNOWN'     無法判定
READWRITE=readwrite 返回一個字串,檢查檔案是否可以同時讀及寫:
'YES'   檔案可以同時讀寫
'NO'    檔案不可以同時讀寫
'UNKNOWN'      無法判定
DELIM=delim     返回開啟檔案時,DELIM欄位所設定的字串,返回值可以是:
                  'APOSTROPHE', 'QUOTE', 'NONE', 'UNDEFINED'
PAD=pad         返回開啟檔案時PAD欄位所設定的字串,返回值可以是:'YES', 'NO'。

其他檔案執行命令:
BACKSPACE(UNIT=number, ERR=errlabel, IOSTAT=iostat) 把檔案讀寫位置退回一步。
ENDFILE(UNNIT=number, ERR=errlabel, IOSTAT=iostat)使用這個命令會把目前檔案的讀寫位置變成檔案的結尾。
REWIND(UNIT=number, ERR=errlabel, IOSTAT=iostat)把檔案的讀寫位置倒回到檔案開頭。
CLOSE(UNIT=number, STATUS=string, ERR=errlabel, IOSTAT=) 把檔案關閉,不要進行讀寫操作。
       STAT='KEEP'     會在檔案關閉後,保留這個檔案。是預設狀態。
       STAT='DELETE' 在檔案關閉後,消除這個檔案。
-------------------------------------------
!程式結束時候會自動關閉檔案,不過最好要養成自己關閉檔案的習慣。
!在讀檔案的時候要懂得略掉一些沒有必要的資料,如檔案中的註釋行。
!自由格式的資料檔案讀取(可以先讀入前面的判斷字元,結合select case或其他方法判斷讀入的資料)
!在open,read,write時使用不同的unit值,就可以開啟多個檔案。最好不要同時開啟很多個檔案。



順序檔案(SEQUENTIAL):在讀寫時,不能任意賦值到檔案的某個位置讀寫資料,只能從開頭開始一步步向下進行。在改變檔案讀寫位置時,只能一步步地退,或是直接移回到檔案開頭。
直接訪問檔案:把檔案的空間,內容,事先分割槽成好幾個同樣大小的小模組,這些模組會自動安順序編號。讀寫檔案時,要先賦值檔案讀寫位置在第幾個模組,再進行讀寫的工作。直接訪問檔案可以任意到檔案的任何一個地方來讀寫。在使用直接訪問檔案時,要小心使用endfile命令,使用這個命令會把目前所在的檔案位置之後的資料都清除掉。
二進位制檔案的操作:使用二進位制檔案來做直接讀取時,open命令中的recl欄位所設定的整數n值所代表的大小會隨編譯器不同而改變。每個編譯器應該都可以經過設定來改變recl欄位的單位大小。二進位制檔案沒有必要在資料之間用區分符號來增加檔案的可讀性,因為二進位制檔案本身就沒有可讀性。二進位制檔案是直接把記憶體的二進位制資料寫入檔案,就沒有所謂的格式化輸入/出存在。存放“精確”及“大量”的資料時,使用二進位制檔案是比較好的選擇。二進位制檔案也可以使用順序格式來操作,順序格式下顯示來的二進位制檔案,每個資料的前後都會被編譯器補上一些額外的資訊,所生成的檔案不太容易被其他程式讀取。
關於以上檔案操作詳細見《fortran 95程式設計》9-3~9-5。


Internal File(內部檔案)
使用寫入檔案的方法,把資料寫到一個字串變數中。
example:
a=2
b=3
character (len=20) :: string
write (unit=string, fmt="(I2,'+',I2,'=',I2)") a, b, a+b !把字串變數當作輸出的目的。
write(*, *) string
結果: 2+ 3= 5
還可以經過read命令從字串讀入資料:
integer :: a
character (len=20) :: string="123"
read(string, *) a
write(*, *) a
在某些情況下需要使用內部檔案來設定資料:
使用read命令從鍵盤輸入資料時,如果使用者輸入錯誤的資料,會導致宕機。如需要輸入整數時卻輸入英文字母,就可能會宕機。比較好的處理辦法是,程式先暫時把資料當作字串讀入,檢查字串中是否含有不合理的字元,如果字串中都是0~9的數字字元,就把字串轉成整數,不然就請使用者在輸入一次。
內部檔案還可應用在動態改變輸出格式,輸出格式可以事先存放在字串中,程式進行時,動態改變字串內容就可以改變輸出格式。(見書P263)

NAMELIST:
NAMELIST是很特殊的輸入/輸出方法,收錄在f90標準當中,f90中有統一NAMELIST的格式。
NAMELIST可以把一組相關變數封裝在一起,輸入/出這一組變數時,只要在write/read中的NML欄位賦值使用哪一個NAMELIST就行了。
example:
program ex0918
   implicit none
   integer :: a = 1, b = 2, c= 3
   namelist /na/ a,b,c
   write(*,nml=na)
   stop
end program ex0918

&NA
A       =           1,
B       =           2,
C       =           3,
/
程式中把a,b,c這三個變數放在名字叫做na的namelist中。namelist也算是宣告的一部分,必須編寫在程式執行命令前面。
NAMELIST的語法很類似COMMON,不過使用namelist時一定要取名字:
namelist /nl_name/ var1, var2, ...        !後面的變數會放在nl_name這個namelist中。
封裝好namelist後,在write的NML欄位中指名要輸出哪一個namelist,就可以把namelist中的變數全部輸出。
write(*,nml=na) !輸出na這個namelist
輸出namelist時候不能賦值輸出格式,f90標準中規定輸出namelist時首先會輸出符號&,後面緊接著這個namelist的名字。接著會根據順序輸出變數的名稱,等號以及內容,變數之間用空格或逗號來做分隔,最後使用除號來作結束。
至於每個數值內容會使用何種格式輸出由編譯器自行決定。
NAMELIST也可以用來輸入資料,不過通常都會用來讀取檔案,不會用在鍵盤輸入。輸入格式需要按照前面的格式。&na ....../ 不需要按照變數順序輸入,程式會自動按照變數名稱來設定數值。變數甚至可以重複輸入,不過變數會得到最後一次設定的數值。
namelist通常使用在文字檔案的輸入/輸出中,使用read從檔案中讀取資料時,會自動從目前的位置向下尋找存放namelist的地方。
example:
program ex0920
implicit none
integer :: a(3)
namelist /na/ a

open(10, file="ex0920.txt")
read(10, nml=na)
write(*, "(3I2)") a
stop
end program
輸入檔案的內容如下:
happy birthday
&na a = 1,2,3/
程式開啟時,讀寫位置在檔案的開頭,read命令會自動向下尋找na這個namelist的存放位置來讀取資料,這邊可以看到namelist處理陣列的方法,它會在等號後面根據順序顯示陣列內容。