fopen ()- 開啟檔案
格式
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);語言層次
ANSI
安全執行緒
是
說明
fopen() 函數會開啟由 檔名指定的檔案。 mode 參數是一個字串,指定針對檔案所要求的存取類型。 mode 變數包含一個位置參數,後面接著選用關鍵字參數。
fopen() 會在整合檔案系統中建立檔案,並將檔案的讀取、寫入及執行權限授與檔案的擁有者、擁有者群組及公用。- 模式
- 說明
- r
- 開啟文字檔以進行讀取。 檔案必須存在。
- w
- 建立要寫入的文字檔。 如果給定檔案存在,則除非它是邏輯檔案,否則會毀損其內容。
- A
- 以附加模式開啟文字檔,以在檔案結尾寫入。 如果檔案不存在且不是邏輯檔案,則
fopen()函數會建立該檔案。 - r +
- 開啟文字檔以進行讀取及寫入。 檔案必須存在。
- w +
- 建立用於讀取及寫入的文字檔。 如果給定的檔案存在,則除非它是邏輯檔案,否則會清除其內容。
- a +
- 以附加模式開啟文字檔,以在檔案結尾讀取或更新。 如果檔案不存在,
fopen()函數會建立該檔案。 - RB
- 開啟二進位檔以進行讀取。 檔案必須存在。
- WB
- 建立空的二進位檔來寫入。 如果檔案存在,則除非它是邏輯檔案,否則會清除其內容。
- AB
- 以附加模式開啟二進位檔,以便在檔案結尾寫入。 fopen 函數會建立檔案 (如果不存在)。
- r + b 或 rb +
- 開啟二進位檔以進行讀取及寫入。 檔案必須存在。
- w + b 或 wb +
- 建立空白二進位檔來讀取和寫入。 如果檔案存在,則除非它是邏輯檔案,否則會清除其內容。
- a + b 或 ab +
- 以附加模式開啟二進位檔,以便在檔案結尾寫入。 如果檔案不存在,
fopen()函數會建立該檔案。
- 使用屬性 type=record 及 ab +、rb +、 或 wb + 開啟的檔案不支援
fopen()函數。 - 請小心使用 w、 w +、 wb、 w + b及 wb + 參數; 同名現有檔案中的資料將會遺失。
fopen() 功能模式 "a" 和 "a +" 無法用於 QSYS.LIB 檔案系統。 使用 QSYS.LIB 檔案系統,適用於所有模式中的文字檔。 如果要使用以文字模式開啟的串流,則無法依賴在檔案開始之後進行探查。fopen() 在 QSYS.LIB 檔案系統,指定檔案庫名稱 *LIBL 或空白會導致在 QTEMP 檔案庫中建立檔案。如果文字檔不存在,您可以使用下列指令來建立一個:
CRTSRCPF FILE(MYLIB/MYFILE) RCDLEN(LRECL)
MBR(MYMBR) SYSTEM(*FILETYPE)
fopen() 函數時,資料庫檔案必須存在,才能動態建立成員。如需整合檔案系統的現行檔案系統限制,請參閱「資訊中心」內「整合檔案系統」主題中的 大型檔案支援 。 對於整合檔案系統中大於 2 GB 的檔案,您需要容許應用程式存取 64 位元 C 執行時期功能。 您可以使用下列方法來容許您的程式存取:
- 在編譯指令上指定 SYSIFCOPT (*IFS64IO) ,這會導致原生 C 編譯器定義 _IFS64_IO_。 這會導致定義巨集 _LARGE_FILES 及 _LARGE_FILE_API。
- 在程式原始檔中定義巨集 _LARGE_FILES ,或在編譯指令上指定 DEFINE ('_LARGE_FILES')。 程式碼中的現有 C 執行時期函數及相關資料類型都會自動對映或重新定義至其 64 位元版本。
- 在程式原始檔中定義巨集 _LARGE_FILE_API ,或在編譯指令上指定 DEFINE ('_LARGE_FILE_API')。 這會顯示一組新的 64 位元 C 執行時期函數及資料類型。 應用程式必須明確指定要使用的 C 執行時期函數名稱 (現有版本及 64 位元版本)。
64 位元 C 執行時期功能包括下列: int
fgetpos64()、 FILE *fopen64()、 FILE
*freopen64()、 FILE *wfopen64()、 int
fsetpos64(FILE *, const fpost64_t *)、 FILE *tmpfile64()、 int
fseeko(FILE *, off_t, int)、 int fseeko64(FILE *,
off64_t, int)、 off_t ftello(FILE *)及 off64_t
ftello64()。
二進位檔 包含一系列字元。 對於二進位檔,系統不會轉換輸入或輸出上的控制字元。
如果二進位檔不存在,您可以使用下列指令來建立一個:
CRTPF FILE(MYLIB/MYFILE) RCDLEN(LRECL) MBR(MYMBR)
MAXMBRS(*NOMAX) SYSTEM(*FILETYPE)
當您以 a、 a +、 ab、 a + b 或 ab + 模式開啟檔案時,所有寫入作業都會在檔案結尾進行。 雖然您可以使用 fseek() 函數或 rewind() 函數來重新定位檔案指標,但在執行任何作業之前,寫入函數會將檔案指標移回檔案結尾。 此動作可防止您改寫現有資料。
當您指定更新模式 (在第二個或第三個位置使用 + ) 時,您可以讀取及寫入檔案。 不過,在讀取與寫入之間切換時,您必須併入中間的定位函數,例如 fseek()、 fsetpos()、 rewind()或 fflush()。 如果偵測到檔案結尾,則輸出可以緊接在輸入之後。
非Integrated File System 的關鍵字參數
- blksize=value
- 指定記錄實體區塊的長度上限 (以位元組為單位)。
- lrecl=value
- 指定固定長度記錄的長度 (以位元組為單位) 及可變長度記錄的最大長度。
- recfm=value
- value 可以是:
- F
- 固定長度, deblocked 記錄
- FB
- 固定長度,區塊記錄
- V
- 可變長度, deblocked 記錄
- VB
- 可變長度,區塊記錄
- VBS
- 磁帶檔案的可變長度、區塊、跨區記錄
- VS.
- 磁帶檔案的可變長度、deblocked、跨區記錄
- D
- 磁帶檔案的 ASCII D 格式的可變長度、解除鎖定、非跨距記錄
- DB
- 磁帶檔案的 ASCII D 格式的可變長度、區塊化、非跨距記錄
- U
- 磁帶檔案的未定義格式
- FA
- 固定長度,使用印表機檔案的第一個字元格式控制資料
附註: 如果使用 CTLCHAR (*FCFC) 建立檔案,則會使用第一個字元格式控制。 如果使用 CTLCHAR (*NONE) 建立,則不會使用第一個字元格式控制。 - commit=值
- value 可以是:
N 此參數識別此檔案未在確定控制下開啟。 這是預設值。
Y 此參數識別在確定控制下開啟此檔案。
- ccsid=value
- 如果指定作業系統不支援的 CCSID ,則資料管理會忽略它。
在編譯指令上指定 LOCALETYPE (*LOCALEUTF) 時,預設值是 LC_CTYPE CCSID 值,由現行語言環境設定決定。 如需語言環境設定的進一步相關資訊,請參閱 setlocale ()-設定語言環境 。 未在編譯指令上指定 LOCALETYPE (*LOCALEUTF) 時,預設值為工作 CCSID 值。 如需檔案 CCSID 值的進一步相關資訊,請參閱 檔案 CCSID 。
- arrseq=值
- value 可以是:
N 此參數識別以建立檔案的方式處理此檔案。 這是預設值。
Y 此參數識別以到達順序處理此檔案。
- indicators=value
- value 可以是:
N 此參數識別顯示器、ICF 或印表機檔案中的指示器儲存在檔案緩衝區中。 這是預設值。
Y 此參數識別顯示器、ICF 或印表機檔案中的指示器儲存在個別指示器區域中,而不是儲存在檔案緩衝區中。 檔案緩衝區是系統在寫入及讀取時,用來與使用者程式及作業系統來回傳送資料的區域。 在處理 ICF 檔案時,您必須將指示器儲存在個別指示器區域中。
- 類型 =值
- value 可以是:
memory 此參數會將此檔案識別為只能從 C 程式使用的記憶體檔。 這是預設值。
record 此參數指定要開啟檔案以進行循序記錄 I/O。 檔案必須以二進位檔開啟; 否則,
fopen()函數會失敗。 讀取及寫入作業是使用fread()函數及fwrite()函數來完成。
僅限 Integrated File System 的關鍵字參數
- 類型 =值
- value 可以是:
record 開啟檔案以進行循序記錄 I/O。 (檔案必須以二進位串流開啟。)
- ccsid=value
- ccsid 會轉換為字碼頁值。 預設值是使用工作 CCSID 值作為字碼頁。 無法同時指定 CCSID 及字碼頁選項。 CCSID 選項提供與作業系統及資料管理型串流 I/O 的相容性。附註: 文字的檔案資料處理模式不支援混合資料 (資料同時包含單位元組及雙位元組字元)。 二進位檔案處理模式支援混合資料。
如果您指定 ccsid 關鍵字,則無法指定 o_ccsid 關鍵字或字碼頁關鍵字。
由於轉換資料可能擴充或縮小,因此假設資料大小及現行檔案偏移是危險的。 例如,檔案可能具有 100 個位元組的實體大小,但在應用程式從檔案讀取 100 個位元組之後,現行檔案偏移可能只有 50 個位元組。 為了讀取整個檔案,應用程式可能必須讀取 200 個位元組以上,視所涉及的 CCSID 而定。 因此,檔案定位功能 (例如
ftell()、fseek()、fgetpos()及fsetpos()) 可能無法運作。 這些功能可能因錯誤 ENOTSUP 而失敗。 如果緩衝功能已開啟,則讀取功能也將無法運作,因為依預設是如此。 若要關閉緩衝功能,請搭配使用 setvbuf 函數與 _IONBF 關鍵字。當發生下列所有三種狀況時,fopen()函數可能會失敗並產生 ECONVERT 錯誤:- 檔案資料處理模式是文字。
- 未指定字碼頁。
- 工作的 CCSID 是 'mixed-data' (資料同時包含單位元組和雙位元組字元)。
- o_ccsid=value
在編譯指令上指定 LOCALETYPE (*LOCALEUTF) 時,預設值是 LC_CTYPE CCSID 值,由現行語言環境設定決定。 如需語言環境設定的進一步相關資訊,請參閱 setlocale ()-設定語言環境 。 未在編譯指令上指定 LOCALETYPE (*LOCALEUTF) 時,預設值為工作 CCSID 值。 如需檔案 CCSID 值的進一步相關資訊,請參閱 檔案 CCSID 。
此參數類似於 ccsid 參數,但指定的值不會轉換為字碼頁。 此外,還支援混合資料。 如果建立檔案,則會以指定的 CCSID 來標示它。 如果檔案已存在,則在讀取作業上,資料將從檔案的 CCSID 轉換為指定的 CCSID。 在寫入作業時,會假設資料採用指定的 CCSID ,並轉換成檔案的 CCSID。
由於轉換資料可能擴充或縮小,因此假設資料大小及現行檔案偏移是危險的。 例如,檔案可能具有 100 個位元組的實體大小,但在應用程式從檔案讀取 100 個位元組之後,現行檔案偏移可能只有 50 個位元組。 為了讀取整個檔案,應用程式可能必須讀取 200 個位元組以上,視所涉及的 CCSID 而定。 因此,檔案定位功能 (例如
ftell()、fseek()、fgetpos()及fsetpos()) 將無法運作。 這些功能將因 ENOTSUP 而失敗。 如果緩衝功能已開啟,則讀取功能也將無法運作,因為依預設是如此。 若要關閉緩衝功能,請搭配使用 setvbuf 函數與 _IONBF 關鍵字。使用 o_ccsid 的範例
/* Create a file that is tagged with CCSID 37 */ if ((fp = fopen("/MYFILE" , "w, o_ccsid=37")) == NULL) { printf("Failed to open file with o_ccsid=37\n"); } fclose(fp); /* Now reopen the file with CCSID 13488, because your application wants to deal with the data in UNICODE */ if ((fp = fopen("/MYFILE" , "r+, o_ccsid=13488")) == NULL) { printf("Failed to open file with o_ccsid=13488\n"); } /* Turn buffering off because read functions do not work when buffering is on */ if (setbuf(fp, NULL, _IONBF, 0) != 0){ printf("Unable to turn buffering off\n"); } /* Because you opened with o_ccsid = 13488, you must provide all input data as unicode. If this program is compiled with LOCALETYPE(*LOCALEUCS2), L constrants will be unicode. */ funcreturn = fputws(L"ABC", fp); /* Write a unicode ABC to the file. */ if (funcreturn < 0) { printf("Error with 'fputws' on line %d\n", __LINE__); } /* Because the file was tagged with CCSID 37, the unicode ABC was converted to EBCDIC ABC when it was written to the file. */- codepage=value
- 使用 value 指定的字碼頁。
如果您指定字碼頁關鍵字,則無法指定 ccsid 關鍵字或 o_ccsid 關鍵字。
如果要開啟的檔案不存在,且開啟模式指定應該建立檔案,則會建立檔案並以計算的字碼頁標示。 如果檔案已存在,則在讀取作業期間,從檔案讀取的資料會從檔案的字碼頁轉換為計算的字碼頁。 寫入檔案的資料會假設為計算的字碼頁,並在寫入作業期間轉換為檔案的字碼頁。
- crln=值
- value 可以是:
Y 要使用的行終止符號是換行 [CR] ,新行 [NL] 組合。 讀取資料時,會針對字串函數刪除所有換行 [CR]。 將資料寫入檔案時,會在每一個換行 [NL] 字元之前新增換行 [CR]。 只有在以文字模式開啟檔案時,才會進行字行終止字元處理。 這是預設值。
N 要使用的行終止符號僅是換行 [NL]。
關鍵字參數不區分大小寫,且應該以逗點區隔。
如果參數不符, fopen() 函數通常會失敗。
回覆值
fopen() 函數會傳回一個指標,指向可用來存取開啟檔案的 FILE 結構類型。NULL 指標回覆值指出發生錯誤。
- Value
- 意義
- EBADMODE
- 指定的檔案模式無效。
- EBADNAME
- 指定的檔名無效。
- ECONEVRT
- 轉換錯誤。
- ENOENT
- 沒有檔案或檔案庫。
- ENOMEM
- 儲存體配置要求失敗。
- ENOTOPEN
- 檔案未開啟。
- EIOERROR
- 發生非可回復I/O錯誤。
- EIORECERR
- 發生可回復I/O錯誤。
- ESCANFAILURE
- 檔案已標示掃描失敗。
如果傳遞至 fopen() 的模式字串正確,不論檔案類型為何, fopen() 都不會將錯誤碼設為 EBADMODE。
如果傳遞至 fopen() 的模式字串無效,不論檔案類型為何, fopen() 都會將錯誤碼設為 EBADMODE。
如果傳遞至 fopen() 的模式字串正確,但對該特定類型的檔案無效,則不論檔案類型為何, fopen() 都會將錯誤碼設為 ENOTOPEN、EIOERROR 或 EIORECERR。
範例
#include <stdio.h>
#define MAX_LEN 60
int main(void)
{
FILE *stream;
fpos_t pos;
char line1[MAX_LEN];
char line2[MAX_LEN];
char *result;
char ch;
int num;
/* The following call opens a text file for reading. */
if ((stream = fopen("mylib/myfile", "r")) == NULL)
printf("Could not open data file\n");
else if ((result = fgets(line1,MAX_LEN,stream)) != NULL)
{
printf("The string read from myfile: %s\n", result);
fclose(stream);
}
/* The following call opens a fixed record length file */
/* for reading and writing. */
if ((stream = fopen("mylib/myfile2", "rb+, lrecl=80, \
blksize=240, recfm=f")) == NULL)
printf("Could not open data file\n");
else {
fgetpos(stream, &pos);
if (!fread(line2,sizeof(line2),1,stream))
perror("fread error");
else printf("1st record read from myfile2: %s\n", line2);
fsetpos(stream, &pos); /* Reset pointer to start of file */
fputs(result, stream); /* The line read from myfile is */
/* written to myfile2. */
fclose(stream);
}
}