C 和 C++ 文件操作详解
?
來源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html
來源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html
?
?
?
CPP 的文件操作
?
在C++中,有一個stream這個類,所有的I/O都以這個“流”類為基礎的,包括我們要認識的文件I/O,stream這個類有兩個重要的運算符:
1、插入器(<<)
向流輸出數據。比如說系統有一個默認的標準輸出流(cout),一般情況下就是指的顯示器,所以,cout<<"Write Stdout"<<''\n'';就表示把字符串"Write Stdout"和換行字符(''\n'')輸出到標準輸出流。
2、析取器(>>)
從流中輸入數據。比如說系統有一個默認的標準輸入流(cin),一般情況下就是指的鍵盤,所以,cin>>x;就表示從標準輸入流中讀取一個指定類型(即變量x的類型)的數據。
在C++中,對文件的操作是通過stream的子類fstream(file stream)來實現的,所以,要用這種方式操作文件,就必須加入頭文件fstream.h。
C++ 通過以下幾個類支持文件的輸入輸出:
- ofstream: 寫操作(輸出)的文件類 (由ostream引申而來)
- ifstream: 讀操作(輸入)的文件類(由istream引申而來)
- fstream: 可同時讀寫操作的文件類 (由iostream引申而來)
?
?
打開文件(Open a file)
對這些類的一個對象所做的第一個操作通常就是將它和一個真正的文件聯系起來,也就是說打開一個文件。被打開的文件在程序中由一個流對象(stream object)來表示 (這些類的一個實例) ,而對這個流對象所做的任何輸入輸出操作實際就是對該文件所做的操作。
?
1. 通過一個流對象調用open函數打開一個文件。
我們使用它的成員函數open():void open (const char * filename, openmode mode);
這里filename 是一個字符串,代表要打開的文件名,mode 是以下標志符的一個組合: ios::in 為輸入(讀)而打開文件
文件的輸入輸出是從內存的角度看的:數據載入內存叫做輸入,數據從內存到其他地方叫做輸出。
- ios::out?文件以輸出(寫)方式打開?
- ios::in ? ?文件以輸入(讀)方式打開
- ios::ate 初始位置:文件尾
- ios::app 所有輸出附加在文件末尾
- ios::trunc 如果文件已存在則先刪除該文件
- ios::binary 二進制方式
這些標識符可以被組合使用,中間以”或”操作符(|)間隔。例如,如果我們想要以二進制方式打開文件”example.bin” 來寫入一些數據,我們可以通過以下方式調用成員函數open()來實現:
ofstream file; file.open ("example.bin", ios::out | ios::app | ios::binary);ofstream, ifstream 和 fstream所有這些類的成員函數open 都包含了一個默認打開文件的方式,這三個類的默認方式各不相同: 類 參數的默認方式
- ofstream ios::out | ios::trunc
- ifstream ios::in
- fstream ios::in | ios::out
只有當函數被調用時沒有聲明方式參數的情況下,默認值才會被采用。如果函數被調用時聲明了任何參數,默認值將被完全改寫,而不會與調用參數組合。
?
2. 通過 類 對象 構造函數 打開文件。
類 ofstream, ifstream 和 fstream 的 對象 所進行的第一個操作通常都是打開文件,這些類都有一個構造函數可以直接調用open 函數,并擁有同樣的參數。這樣,我們就可以通過以下方式進行與上面同樣的定義對象和打開文件的操作:
ofstream file ("example.bin", ios::out | ios::app | ios::binary); 例如:以二進制輸入方式打開文件c:\config.sys fstream file1; file1.open("c:\\config.sys",ios::binary|ios::in,0);//如果open函數只有文件名一個參數,則是以讀/寫普通文件打開,即: file1.open("c:\\config.sys");<=>file1.open("c:\\config.sys",ios::in|ios::out,0);//另外,fstream還有和open()一樣的構造函數,對于上例,在定義的時侯就可以打開文件了: fstream file1("c:\\config.sys");以上 兩種 打開文件的方式都是正確的。
?
通過調用成員函數is_open()來檢查一個文件是否已經被順利的打開:bool is_open()。它返回一個布爾(bool)值,為真(true)代表文件已經被順利打開,假( false )則相反。
?
#include <fstream> ofstream //文件寫操作 內存寫入存儲設備 ifstream //文件讀操作,存儲設備讀區到內存中 fstream //讀寫操作,對打開的文件可進行讀寫操作在fstream類中,成員函數open()實現打開文件的操作,從而將數據流和文件進行關聯,通過ofstream,ifstream,fstream對象 進行對文件的讀寫操作
在fstream類中,有一個成員函數open(),就是用來打開文件的,其原型是:
void open(const char* filename,int mode,int access);
參數:
filename: 要打開的文件名 mode: 要打開文件的方式 access: 打開文件的屬性打開文件的方式在類ios(是所有流式I/O類的基類)中定義,常用的值如下:
ios::app: 以追加的方式打開文件 ios::ate: 文件打開后定位到文件尾,ios:app就包含有此屬性 ios::binary: 以二進制方式打開文件,缺省的方式是文本方式。兩種方式的區別見前文 ios::in: 文件以輸入(讀)方式打開 ios::out: 文件以輸出(寫)方式打開 ios::nocreate: 不建立文件,所以文件不存在時打開失敗 ios::noreplace:不覆蓋文件,所以打開文件時如果文件存在失敗 ios::trunc: 如果文件存在,把文件長度設為0。即刪除該文件。可以用“或”把以上屬性連接起來,如ios::out|ios::binary
ofstream out; out.open("Hello.txt", ios::in|ios::out|ios::binary) //根據自己需要進行適當的選取打開文件的屬性取值是:
0:普通文件,打開訪問 1:只讀文件 2:隱含文件 4:系統文件可以用“或”或者“+”把以上屬性連接起來 ,如3或1|2就是以只讀和隱含屬性打開文件。
例如:以二進制輸入方式打開文件c:config.sys
fstream file1; file1.open("c:config.sys",ios::binary|ios::in,0); // 如果open函數只有文件名一個參數,則是以讀/寫普通文件打開,即: // file1.open("c:config.sys");<=>file1.open("c:config.sys",ios::in|ios::out,0); // 另外,fstream還有和open()一樣的構造函數,對于上例,在定義的時侯就可以打開文件了: fstream file1("c:config.sys"); // fstream有兩個子類:ifstream(input file stream)和ofstream(outpu file stream),ifstream默認以輸入方式打開文件,而ofstream默認以輸出方式打開文件。 ifstream file2("c:pdos.def");//以輸入方式打開文件 ofstream file3("c:x.123");//以輸出方式打開文件所以,在實際應用中,根據需要的不同,選擇不同的類來定義:如果想以輸入方式打開,就用ifstream來定義;如果想以輸出方式打開,就用ofstream來定義;如果想以輸入/輸出方式來打開,就用fstream來定義。很多程序中,可能會碰到ofstream out("Hello.txt"), ifstream in("..."),fstream foi("...")這樣的的使用,并沒有顯式的去調用open()函數就進行文件的操作,直接調用了其默認的打開方式,因為在stream類的構造函數中調用了open()函數,并擁有同樣的構造函數,所以在這里可以直接使用流對象進行文件的操作,默認方式如下:
ofstream out("...", ios::out); ifstream in("...", ios::in); fstream foi("...", ios::in|ios::out);當使用默認方式進行對文件的操作時,你可以使用成員函數is_open()對文件是否打開進行驗證
?
?
關閉文件(Closing a file)
當文件讀寫操作完成之后,我們必須將文件關閉以使文件重新變為可訪問的。關閉文件需要調用成員函數close(),它負責將緩存中的數據排放出來并關閉文件。
void close (); ? ?這個函數一旦被調用,原先的流對象(stream object)就可以被用來打開其它的文件了,這個文件也就可以重新被其它的進程(process)所有訪問了。
為防止流對象被銷毀時還聯系著打開的文件,析構函數(destructor)將會自動調用關閉函數close。
?
打開的文件使用完成后一定要關閉,fstream提供了成員函數close()來完成此操作,如:file1.close();就把file1相連的文件關閉。
?
?
讀寫文件
讀寫文件分為?文本文件?和 二進制文件 的讀取,
對于文本文件的讀取比較簡單,用插入器和析取器就可以。而對于二進制的讀取就要復雜些。
下要就詳細的介紹這兩種方式:
?
文本文件(Text mode files)
類ofstream, ifstream 和fstream 是分別從ostream, istream 和iostream 中引申而來的。這就是為什么 fstream 的對象可以使用其父類的成員來訪問數據。
一般來說,我們將使用這些類與同控制臺(console)交互同樣的成員函數(cin 和 cout)來進行輸入輸出。如下面的例題所示,我們使用重載的插入操作符
文本文件的讀寫很簡單:用插入器(>>)從文件輸入。假設file1是以輸入方式打開,file2以輸出打開。示例如下:
file2<<"I Love You";//向文件寫入字符串"I Love You" int i; file1>>i;//從文件輸入一個整數值。這種方式還有一種簡單的格式化能力,比如可以指定輸出為16進制等等,具體的格式有以下一些
?
操縱符 功能 輸入/輸出
dec 格式化為十進制數值數據 輸入和輸出
endl 輸出一個換行符并刷新此流 輸出
ends 輸出一個空字符 輸出
hex 格式化為十六進制數值數據 輸入和輸出
oct 格式化為八進制數值數據 輸入和輸出
setpxecision(int p) 設置浮點數的精度位數 輸出
比如要把123當作十六進制輸出:file1<<hex<<123;要把3.1415926以5位精度輸出:file1<<setpxecision(5)<<3.1415926。
類ofstream, ifstream 和fstream 是分別從ostream, istream 和iostream 中引申而來的。這就是為什么 fstream 的對象可以使用其父類的成員來訪問數據。
一般來說,我們將使用這些類與同控制臺(console)交互同樣的成員函數(cin 和 cout)來進行輸入輸出。如下面的例題所示,我們使用重載的插入操作符<<:
例子中讀入一個文本文件的內容,然后將它打印到屏幕上。注意我們使用了一個新的成員函數叫做eof ,它是ifstream 從類 ios 中繼承過來的,當到達文件末尾時返回true 。
?
二進制文件(Binary files)
在二進制文件中,使用<< 和>>,以及函數(如getline)來操作符輸入和輸出數據,沒有什么實際意義,雖然它們是符合語法的。
文件流包括兩個為順序讀寫數據特殊設計的成員函數:write 和 read。第一個函數 (write) 是ostream 的一個成員函數,都是被ofstream所繼承。而read 是istream 的一個成員函數,被ifstream 所繼承。類 fstream 的對象同時擁有這兩個函數。它們的原型是:
write ( char * buffer, streamsize size );
read ( char * buffer, streamsize size );
這里 buffer 是一塊內存的地址,用來存儲或讀出數據。參數size 是一個整數值,表示要從緩存(buffer)中讀出或寫入的字符數。
// reading binary file #include <iostream> #include <fstream> using namespace std; int main () {const char * filename = "example.txt";char * buffer;long size;ifstream file(filename, ios::in|ios::binary|ios::ate);size = file.tellg();file.seekg(0, ios::beg);buffer = new char [size];file.read(buffer, size);file.close();cout <<"the complete file is in a buffer";delete[] buffer;return 0; } //The complete file is in a buffer①put()
put()函數向流寫入一個字符,其原型是ofstream &put(char ch),使用也比較簡單,如file1.put(‘c’);就是向流寫一個字符’c’。
②get()
get()函數比較靈活,有3種常用的重載形式:
一種就是和put()對應的形式:ifstream &get(char &ch);功能是從流中讀取一個字符,結果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示從文件中讀取一個字符,并把讀取的字符保存在x中。
另一種重載形式的原型是: int get();這種形式是從流中返回一個字符,如果到達文件尾,返回EOF,如x=file2.get();和上例功能是一樣的。
還 有一種形式的原型是:ifstream &get(char *buf,int num,char delim=’n’);這種形式把字符讀入由 buf 指向的數組,直到讀入了 num 個字符或遇到了由 delim 指定的字符,如果沒使用 delim 這個參數,將使用缺省值換行符’n’。例如:
file2.get(str1,127,’A’);//從文件中讀取字符到字符串str1,當遇到字符’A’或讀取了127個字符時終止。
③讀寫數據塊
要讀寫二進制數據塊,使用成員函數read()和write()成員函數,它們原型如下:
read(unsigned char *buf,int num);
write(const unsigned char *buf,int num);
read() 從文件中讀取 num 個字符到 buf 指向的緩存中,如果在還未讀入 num 個字符時就到了文件尾,可以用成員函數 int gcount();來取得實際讀取的字符數;而 write() 從buf 指向的緩存寫 num 個字符到文件中,值得注意的是緩存的類型是 unsigned char *,有時可能需要類型轉換。
?
?
狀態標志符的驗證(Verification of state flags)
除了eof()以外,還有一些驗證流的狀態的成員函數(所有都返回bool型返回值):
bad():如果在讀寫過程中出錯,返回 true 。例如:當我們要對一個不是打開為寫狀態的文件進行寫入時,或者我們要寫入的設備沒有剩余空間的時候。
fail():除了與bad() 同樣的情況下會返回 true 以外,加上格式錯誤時也返回true ,例如當想要讀入一個整數,而獲得了一個字母的時候。
eof():如果讀文件到達文件末尾,返回true。
good():這是最通用的:如果調用以上任何一個函數返回true 的話,此函數返回 false 。
要想重置以上成員函數所檢查的狀態標志,你可以使用成員函數clear(),沒有參數。
?
緩存和同步(Buffers and Synchronization)
當我們對文件流進行操作的時候,它們與一個streambuf 類型的緩存(buffer)聯系在一起。這個緩存(buffer)實際是一塊內存空間,作為流(stream)和物理文件的媒介。例如,對于一個輸出流, 每次成員函數put (寫一個單個字符)被調用,這個字符不是直接被寫入該輸出流所對應的物理文件中的,而是首先被插入到該流的緩存(buffer)中。
當緩存被排放出來(flush)時,它里面的所有數據或者被寫入物理媒質中(如果是一個輸出流的話),或者簡單的被抹掉(如果是一個輸入流的話)。這個過程稱為同步(synchronization),它會在以下任一情況下發生:
?
1. 當文件被關閉時: 在文件被關閉之前,所有還沒有被完全寫出或讀取的緩存都將被同步。
2. 當緩存buffer 滿時:緩存Buffers 有一定的空間限制。當緩存滿時,它會被自動同步。
3. 控制符明確指明:當遇到流中某些特定的控制符時,同步會發生。這些控制符包括:flush 和endl。
4. 明確調用函數sync(): 調用成員函數sync() (無參數)可以引發立即同步。這個函數返回一個int 值,等于-1 表示流沒有聯系的緩存或操作失敗
?
檢測 EOF
成員函數eof()用來檢測是否到達文件尾,如果到達文件尾返回非0值,否則返回0。原型是int eof();
if(in.eof())ShowMessage("已經到達文件尾!");
?
文件定位
和 C的文件操作方式不同的是,C++ I/O系統管理兩個與一個文件相聯系的指針。一個是讀指針,它說明輸入操作在文件中的位置;另一個是寫指針,它下次寫操作的位置。每次執行輸入或輸出時, 相應的指針自動變化。所以,C++的文件定位分為讀位置和寫位置的定位,對應的成員函數是 seekg()和 seekp(),seekg()是設置讀位置,seekp是設置寫位置。它們最通用的形式如下:
istream &seekg(streamoff offset,seek_dir origin); ostream &seekp(streamoff offset,seek_dir origin);streamoff 定義于 iostream.h 中,定義有偏移量 offset 所能取得的最大值,seek_dir 表示移動的基準位置,是一個有以下值的枚舉:
ios::beg: 文件開頭 ios::cur: 文件當前位置 ios::end: 文件結尾這兩個函數一般用于二進制文件,因為文本文件會因為系統對字符的解釋而可能與預想的值不同。
file1.seekg(1234,ios::cur);//把文件的讀指針從當前位置向后移1234個字節 file2.seekp(1234,ios::beg);//把文件的寫指針從文件開頭向后移1234個字節?
?
獲得和設置流指針(get and put stream pointers)
所有輸入/輸出流對象(i/o streams objects)都有至少一個流指針:
ifstream, 類似istream, 有一個被稱為get pointer的指針,指向下一個將被讀取的元素。
ofstream, 類似 ostream, 有一個指針 put pointer ,指向寫入下一個元素的位置。
fstream, 類似 iostream, 同時繼承了get 和 put
我們可以通過使用以下成員函數來讀出或配置這些指向流中讀寫位置的流指針:
tellg() 和 tellp()
這兩個成員函數不用傳入參數,返回pos_type 類型的值(根據ANSI-C++ 標準) ,就是一個整數,代表當前get 流指針的位置 (用tellg) 或 put 流指針的位置(用tellp).
seekg() 和seekp()
這對函數分別用來改變流指針get 和put的位置。兩個函數都被重載為兩種不同的原型:
seekg ( pos_type position ); seekp ( pos_type position );使用這個原型,流指針被改變為指向從文件開始計算的一個絕對位置。要求傳入的參數類型與函數 tellg 和tellp 的返回值類型相同。
seekg ( off_type offset, seekdir direction ); seekp ( off_type offset, seekdir direction );使用這個原型可以指定由參數direction決定的一個具體的指針開始計算的一個位移(offset)。它可以是:
ios::beg 從流開始位置計算的位移 ios::cur 從流指針當前位置開始計算的位移 ios::end 從流末尾處開始計算的位移?
流指針 get 和 put 的值對文本文件(text file)和二進制文件(binary file)的計算方法都是不同的,因為文本模式的文件中某些特殊字符可能被修改。由于這個原因,建議對以文本文件模式打開的文件總是使用seekg 和 seekp的第一種原型,而且不要對tellg 或 tellp 的返回值進行修改。對二進制文件,你可以任意使用這些函數,應該不會有任何意外的行為產生。
以下例子使用這些函數來獲得一個二進制文件的大小:
// obtaining file size #include <iostream> #include <fstream> using namespace std;int main () {const char * filename = "example.txt";long l,m;ifstream file(filename, ios::in|ios::binary);l = file.tellg();file.seekg(0, ios::end);m = file.tellg();file.close();cout <<"size of "<< filename;cout <<" is "<< (m-l)<<" bytes.\n";return 0; } //size of example.txt is 40 bytes.?
?
C語言文件操作詳解
?
基于C的文件操作
在ANSI C中,對文件的操作分為兩種方式,即流式文件操作和I/O文件操作,下面就分別介紹之。
一、流式文件操作:這種方式的文件操作有一個重要的結構FILE,FILE在stdio.h中定義如下:
typedef struct {short level; /* fill/empty level of buffer */unsigned flags; /* File status flags */char fd; /* File descriptor */unsigned char hold; /* Ungetc char if no buffer */short bsize; /* Buffer size */unsigned char *buffer; /* Data transfer buffer */unsigned char *curp; /* Current active pointer */unsigned istemp; /* Temporary file indicator */short token; /* Used for validity checking */ }FILE; /* This is the FILE object */ FILE這個結構包含了文件操作的基本屬性,對文件的操作都要通過這個結構的指針來進行。C語言中沒有輸入輸出語句,所有的輸入輸出功能都用 ANSI C提供的一組標準庫函數來實現。文件操作標準庫函數有:
文件的打開操作 fopen 打開一個文件文件的關閉操作 fclose 關閉一個文件文件的讀寫操作 fgetc 從文件中讀取一個字符fputc 寫一個字符到文件中去fgets 從文件中讀取一個字符串fputs 寫一個字符串到文件中去fprintf 往文件中寫格式化數據fscanf 格式化讀取文件中數據fread 以二進制形式讀取文件中的數據fwrite 以二進制形式寫數據到文件中去getw 以二進制形式讀取一個整數putw 以二進制形式存貯一個整數文件狀態檢查函數 feof 文件結束ferror 文件讀/寫出錯clearerr 清除文件錯誤標志ftell 了解文件指針的當前位置文件定位函數 rewind 反繞fseek 隨機定位?
?
?
文件的打開
1.函數原型:FILE *fopen(char *pname,char *mode)
2.功能說明
按照mode 規定的方式,打開由pname指定的文件。若找不到由pname指定的相應文件,就按以下方式之一處理:
? ? ? ?(1) 此時如mode 規定按寫方式打開文件,就按由pname指定的名字建立一個新文件;
? ? ? ?(2) 此時如mode 規定按讀方式打開文件,就會產生一個錯誤。
? ? ? ? 打開文件的作用是:
? ? ? ? (1)分配給打開文件一個FILE 類型的文件結構體變量,并將有關信息填入文件結構體變量;
? ? ? ? (2)開辟一個緩沖區;
? ? ? ? (3)調用操作系統提供的打開文件或建立新文件功能,打開或建立指定文件;
? ? ? ? FILE *:指出fopen是一個返回文件類型的指針函數;
3.參數說明
pname:是一個字符指針,指向要打開的文件名。 mode:是一個指向文件處理方式字符串的字符指針。 字符串 含義 "r" 打開只讀文件,該文件必須存在。 "w" 打開只寫文件,若文件存在則文件長度清為0,即該文件內容會消失。若文件不存在則建立該文件。 "a" 以追加方式打開只寫文件。文件不存在建立該文件,如文件存在,寫入的數據會被加到文件尾,即文件原先的內容會被保留。 "r+" 以讀/寫方式打開文件,該文件必須存在。如無文件則出錯 "w+" 以讀/寫方式打開文件,若文件存在則文件長度清為零,即文件內容清空。若文件不存在則建立該文件。上述的形態字符串都可以再加一個b字符,如rb、w+b或ab+等組合,加入b 字符用來告訴函數庫打開的文件為二進制文件,而非純文字文件。不過在POSIX系統,包含Linux都會忽略該字符。由fopen()所建立的新文件會具有S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)權限,此文件權限也會參考umask值。
返回值 文件順利打開后,指向該流的文件指針就會被返回。若果文件打開失敗則返回NULL,并把錯誤代碼存在errno 中。
附加說明 一般而言,開文件后會作一些文件讀取或寫入的動作,若開文件失敗,接下來的讀寫動作也無法順利進行,所以在fopen()后請作錯誤判斷及處理。
一個文件可以以文本模式或二進制模式打開,這兩種的區別是:在文本模式中回車被當成一個字符''\n'',而二進制模式認為它是兩個字符0x0D,0x0A;如果在文件中讀到0x1B,文本模式會認為這是文件結束符,也就是二進制模型不會對文件進行處理,而文本方式會按一定的方式對數據作相應的轉換。
系統默認的是以文本模式打開,可以修改全部變量_fmode的值來修改這個設置,例如_fmode=O_TEXT;就設置默認打開方式為文本模式;而_fmode=O_BINARY;則設置默認打開方式是二進制模式。
我們也可以在模式字符串中指定打開的模式,如"rb"表示以二進制模式打開只讀文件,"w+t"或"wt+"表示以文本模式打開讀/寫文件。
此函數返回一個FILE指針,所以申明一個FILE指針后不用初始化,而是用fopen()來返回一個指針并與一個特定的文件相連,如果成敗,返回NULL。
?
4.返回值
正常返回:被打開文件的文件指針。
異常返回:NULL,表示打開操作不成功。
要說明的是:C語言將計算機的輸入輸出設備都看作是文件。例如,鍵盤文件、屏幕文件等。ANSI C標準規定,在執行程序時系統先自動打開鍵盤、屏幕、錯誤三個文件。這三個文件的文件指針分別是:標準輸入stdin、標準輸出stdout和標準出錯 stderr。
freopen(打開文件)
相關函數 fopen,fclose
表頭文件 #include<stdio.h>
定義函數 FILE * freopen(const char * path,const char * mode,FILE * stream);
函數說明 參數path字符串包含欲打開的文件路徑及文件名,參數mode請參考fopen()說明。參數stream為已打開的文件指針。Freopen()會將原stream所打開的文件流關閉,然后打開參數path的文件。
返回值 文件順利打開后,指向該流的文件指針就會被返回。如果文件打開失敗則返回NULL,并把錯誤代碼存在errno 中。
?
?
文件的關閉
1. 函數原型:int fclose(FILE *fp);
2. 功能說明
關閉由fp指出的文件。此時調用操作系統提供的文件關閉功能,關閉由fp->fd指出的文件;釋放由fp指出的文件類型結構體變量;返回操作結果,即0或EOF。
3. 參數說明
fp:一個已打開文件的文件指針。
4. 返回值
正常返回:0。
異常返回:EOF,表示文件在關閉時發生錯誤。
例如:
?
文件的讀寫操作
1. 從文件中讀取一個字符
1. 函數原型:int fgetc(FILE *fp);
2. 功能說明:從fp所指文件中讀取一個字符。
3. 參數說明:fp:這是個文件指針,它指出要從中讀取字符的文件。
4. 返回值
正常返回: 返回讀取字符的代碼。
非正常返回:返回EOF。例如,要從"寫打開"文件中讀取一個字符時,會發生錯誤而返回一個EOF。
?
2. 寫一個字符到文件中去
1. 函數原型:int fputc(int ch,FILE *fp)
2. 功能說明:把ch中的字符寫入由fp指出的文件中去。
3. 參數說明
ch:是一個整型變量,內存要寫到文件中的字符(C語言中整型量和字符量可以通用)。
fp:這是個文件指針,指出要在其中寫入字符的文件。
4. 返回值
正常返回: 要寫入字符的代碼。
非正常返回:返回EOF。例如,要往"讀打開"文件中寫一個字符時,會發生錯誤而返回一個EOF。
示例代碼
//按十進制和字符顯示文件代碼,若遇不可示字符就用井號"#"字符代替之。 //程序名為:dumpf.c //執行時可用:dumpf filename1 形式的命令行運行。 // File dump program. #include <stdio.h> void main(int argc,char *argv[]) {char str[9];int ch,count,i;FILE *fp;if(argc!=2){printf("Error format,Usage: dumpf filename\n");return;}if((fp=fopen(argv[1],"r"))==NULL){printf("The file %s can not be opened.\n",argv[1]);return;}count=0;do{i=0;//按八進制輸出第一列,作為一行八個字節的首地址printf("%06o: ",count*8);do{// 從打開的文件中讀取一個字符ch=fgetc(fp);// 按十進制方式輸出這個字符的ASCII碼printf("%4d",ch);// 如果是不可示字符就用"#"字符代替if(ch<' '||ch>'~') str[i]='#';// 如果是可示字符,就將它存入數組str以便形成字符串else str[i]=ch;// 保證每一行輸出八個字符if(++i==8) break;}while(ch!=EOF); // 遇到文件尾標志,結束讀文件操作str[i]='\0'; // 在數組str加字符串結束標志for(;i<8;i++) printf(" "); // 一行不足八個字符用空格填充printf(" %s\n",str); // 輸出字符串count++; // 準備輸出下一行}while(ch!=EOF); // 直到文件結束fclose(fp); // 關閉fp所指文件 }?
3. 從文件中讀取一個字符串
1. 函數原型:char *fgets(char *str,int n,FILE *fp)
2. 功能說明
從由fp指出的文件中讀取n-1個字符,并把它們存放到由str指出的字符數組中去,最后加上一個字符串結束符'\0'。
3. 參數說明
str:接收字符串的內存地址,可以是數組名,也可以是指針。
n: 指出要讀取字符的個數。
fp:這是個文件指針,指出要從中讀取字符的文件。
4. 返回值
正常返回:返回字符串的內存首地址,即str的值。
非正常返回:返回一個NULL值,此時應當用feof()或ferror()函數來判別是讀取到了文件尾,還是發生了錯誤。例如,要從"寫打開"文件中讀取字符串,將
發生錯誤而返回一個NULL值。
?
4. 寫一個字符串到文件中去
1. 函數原型:int fputs(char *str,FILE *fp)
2. 功能說明
把由str指出的字符串寫入到fp所指的文件中去。
3. 參數說明
str:指出要寫到文件中去的字符串。
fp:這是個文件指針,指出字符串要寫入其中的文件。
4. 返回值
正常返回: 寫入文件的字符個數,即字符串的長度。
非正常返回:返回一個NULL值,此時應當用feof()或ferror()函數來判別是讀取到了文件尾,還是發生了錯誤。例如,要往一個"讀打開" 文件中寫字符串時,
會發生錯誤而返回一個NULL值。
?
5. 往文件中寫格式化數據
1.函數原型:int fprintf(FILE *fp,char *format,arg_list)
2.功能說明
將變量表列(arg_list)中的數據,按照format指出的格式,寫入由fp指定的文件。fprintf()函數與printf()函數的功能相同,只是printf()函數是將數據寫入屏幕文件(stdout)。
3.參數說明
fp:這是個文件指針,指出要將數據寫入的文件。
format:這是個指向字符串的字符指針,字符串中含有要寫出數據的格式,所以該字符串成為格式串。格式串描述的規則與printf()函數中的格式串相同。
arg_list:是要寫入文件的變量表列,各變量之間用逗號分隔。
4.返回值:無。
?
fscanf ?從一個流中執行格式化輸入
表頭文件:#include<stdio.h>
函數原型:int fscanf(FILE *stream, char *format[,argument...]);
FILE* 一個FILE型的指針
char* 格式化輸出函數,和scanf里的格式一樣
返回值:成功時返回轉換的字節數,失敗時返回一個負數
fp = fopen("/local/test.c","a+");
fscanf(fp,"%s",str);
?
fdopen(將文件描述詞轉為文件指針)
相關函數 fopen,open,fclose
表頭文件 #include<stdio.h>
定義函數 FILE * fdopen(int fildes,const char * mode);
函數說明 fdopen()會將參數fildes 的文件描述詞,轉換為對應的文件指針后返回。參數mode 字符串則代表著文件指針的流形態,此形態必須和原先文件描述詞讀寫模式相同。關于mode 字符串格式請參考fopen()。
返回值 轉換成功時返回指向該流的文件指針。失敗則返回NULL,并把錯誤代碼存在errno中。
?
fflush(更新緩沖區)
相關函數 write,fopen,fclose,setbuf
表頭文件 #include<stdio.h>
定義函數 int fflush(FILE* stream);
函數說明 fflush()會強迫將緩沖區內的數據寫回參數stream指定的文件中。如果參數stream為NULL,fflush()會將所有打開的文件數據更新。
返回值 成功返回0,失敗返回EOF,錯誤代碼存于errno中。
錯誤代碼 EBADF 參數stream 指定的文件未被打開,或打開狀態為只讀。其它錯誤代碼參考write()。
?
fileno(返回文件流所使用的文件描述詞)
相關函數 open,fopen
表頭文件 #include<stdio.h>
定義函數 int fileno(FILE * stream);
函數說明 fileno()用來取得參數stream指定的文件流所使用的文件描述詞。
返回值 返回文件描述詞。
?
6. 以二進制形式讀取文件中的數據
1. 函數原型:int fread(void *buffer,unsigned sife,unsigned count,FILE *fp)
2. 功能說明
從由fp指定的文件中,按二進制形式將sife*count個數據讀到由buffer指出的數據區中。
3. 參數說明
4.返回值
正常返回:實際讀取數據塊的個數,即count。
異常返回:如果文件中剩下的數據塊個數少于參數中count指出的個數,或者發生了錯誤,返回0值。此時可以用feof()和ferror()來判定到底出現了什么情況。
#include<stdio.h> #define nmemb 3 struct test {char name[20];int size; }s[nmemb]; int main() {FILE * stream;int i;stream = fopen(“/tmp/fwrite”,”r”);fread(s,sizeof(struct test),nmemb,stream);fclose(stream);for(i=0;i<nmemb;i++)printf("name[%d]=%-20s:size[%d]=%d/n",i,s.name,i,s.size);return 0; }執行結果: name[0]=Linux! size[0]=6 name[1]=FreeBSD! size[1]=8 name[2]=Windows2000 size[2]=11?
7. 以二進制形式寫數據到文件中去
1. 函數原型:int fwrite(void *buffer,unsigned sife,unsigned count,FILE *fp)
2. 功能說明
按二進制形式,將由buffer指定的數據緩沖區內的sife*count個數據寫入由fp指定的文件中去。
3. 參數說明
4.返回值
正常返回:實際輸出數據塊的個數,即count。
異常返回:返回0值,表示輸出結束或發生了錯誤。
#include <stdio.h> #define SIZE 4 struct worker { int number;char name[20];int age; }; void main() {struct worker wk;int n;FILE *in,*out;if((in=fopen("file1.txt","rb"))==NULL){printf("The file %s can not be opened.\n","file1.txt");return;}if((out=fopen("file2.txt","wb"))==NULL){printf("The file %s can not be opened.\n","file2.txt");return;}while(fread(&wk,sizeof(struct worker),1,in)==1)fwrite(&wk,sizeof(struct worker),1,out);fclose(in);fclose(out); }示例代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define set_s(x,y) {strcpy(s[x].name,y);s[x].size=strlen(y);} #define nmemb 3 struct test {char name[20];int size; }s[nmemb];main() {FILE * stream;set_s(0,"Linux!");set_s(1,"FreeBSD!");set_s(2,"Windows2000.");stream=fopen("fwrite","w");fwrite(s,sizeof(struct test),nmemb,stream);fclose(stream); }執行 參考fread()。?
8. 以二進制形式讀取一個整數
1. 函數原型:int getw(FILE *fp)
2. 功能說明
從由fp指定的文件中,以二進制形式讀取一個整數。
3. 參數說明
fp:是文件指針。
4. 返回值
正常返回:所讀取整數的值。
異常返回:返回EOF,即-1。由于讀取的整數值有可能是-1,所以必須用feof()或ferror()來判斷是到了文件結束,還是出現了一個出錯。
?
9. 以二進制形式存貯一個整數
1.函數原型:int putw(int n,FILE *fp)
2. 功能說明
以二進制形式把由變量n指出的整數值存放到由fp指定的文件中。
3. 參數說明
n:要存入文件的整數。
fp:是文件指針。
4. 返回值
正常返回:所輸出的整數值。
異常返回:返回EOF,即-1。由于輸出的整數值有可能是-1,所以必須用feof()或ferror()來判斷是到了文件結束,還是出現了一個出錯。
?
文件狀態檢查
1. 文件結束
(1) 函數原型:int feof(FILE *fp)
(2) 功能說明
該函數用來判斷文件是否結束。
(3) 參數說明
fp:文件指針。
(4) 返回值
0:假值,表示文件未結束。
1:真值,表示文件結束。
?
2. 文件讀/寫出錯
(1) 函數原型:int ferror(FILE *fp)
(2) 功能說明
檢查由fp指定的文件在讀寫時是否出錯。
(3) 參數說明
fp:文件指針。
(4) 返回值
0:假值,表示無錯誤。
1:真值,表示出錯。
?
3. 清除文件錯誤標志
(1) 函數原型:void clearerr(FILE *fp)
(2) 功能說明
清除由fp指定文件的錯誤標志。
(3) 參數說明
fp:文件指針。
(4) 返回值:無。
?
4. 了解文件指針的當前位置
(1) 函數原型:long ftell(FILE *fp)
(2) 功能說明
取得由fp指定文件的當前讀/寫位置,該位置值用相對于文件開頭的位移量來表示。
(3) 參數說明
fp:文件指針。
(4) 返回值
正常返回:位移量(這是個長整數)。
異常返回:-1,表示出錯。
(5) 實例
?
文件定位
1. 反繞
(1) 函數原型:void rewind(FILE *fp)
(2) 功能說明
使由文件指針fp指定的文件的位置指針重新指向文件的開頭位置。
(3) 參數說明
fp:文件指針。
(4) 返回值:無。
?
2. 隨機定位:移動文件流的讀寫位置
(1) 函數原型:int fseek(FILE *fp,long offset,int base)
(2) 功能說明
使文件指針fp移到基于base的相對位置offset處。
(3)參數說明
fp:文件指針。
offset:相對base的字節位移量。這是個長整數,用以支持大于64KB的文件。
base:文件位置指針移動的基準位置,是計算文件位置指針位移的基點。ANSI C定義了base的可能取值,以及這些取值的符號常量。
(4)返回值
正常返回:當前指針位置。
異常返回:-1,表示定位操作出錯。
下列是較特別的使用方式:
1) 欲將讀寫位置移動到文件開頭時:fseek(FILE *stream,0,SEEK_SET);
2) 欲將讀寫位置移動到文件尾時:fseek(FILE *stream,0,0SEEK_END);
返回值 當調用成功時則返回0,若有錯誤則返回-1,errno會存放錯誤代碼。
附加說明 fseek()不像lseek()會返回讀寫位置,因此必須使用ftell()來取得目前讀寫的位置。
示例代碼:
#include <stdio.h> #include <stdlib.h>#include<stdio.h> void main() {FILE * stream;long offset;fpos_t pos;stream=fopen(“/etc/passwd”,”r”);fseek(stream,5,SEEK_SET);printf("offset=%d/n",ftell(stream));rewind(stream);fgetpos(stream,&pos);printf("offset=%d/n",pos);pos=10;fsetpos(stream,&pos);printf("offset = %d/n",ftell(stream));fclose(stream); } 執行 結果 offset = 5 offset =0 offset=10ftell(取得文件流的讀取位置)
相關函數 fseek,rewind,fgetpos,fsetpos
表頭文件 #include<stdio.h>
定義函數 long ftell(FILE * stream);
函數說明 ftell()用來取得文件流目前的讀寫位置。參數stream為已打開的文件指針。
返回值 當調用成功時則返回目前的讀寫位置,若有錯誤則返回-1,errno會存放錯誤代碼。
錯誤代碼 EBADF 參數stream無效或可移動讀寫位置的文件流。
范例 參考fseek()。
?
?
關于exit()函數
1. 函數原型:void exit(int status)
2. 功能說明:exit()函數使程序立即終止執行,同時將緩沖區中剩余的數據輸出并關閉所有已經打開的文件。
3. 參數說明:status:為0值表示程序正常終止,為非0值表示一個定義錯誤。
4. 返回值:無。
* 關于feof()函數
1. 函數原型:int feof(FILE *fp)
2. 功能說明
在文本文件(ASCII文件)中可以用值為-1的符號常量EOF來作為文件的結束符。但是在二進制文件中-1往往可能是一個有意義的數據,因此不能用它 來作為文件的結束標志。為了能有效判別文件是否結束,ANSI C提供了標準函數feof(),用來識別文件是否結束。
3. 參數說明:fp:文件指針。
4. 返回值
返回為非0值:已到文件尾。
返回為0值:表示還未到文件尾。
?
?
C語言的直接I\O文件操作
?
這是 C 提供的另一種文件操作,它是通過直接 存/取 文件來完成對文件的處理(也就是 系統調用。更多關于 系統調用 和 庫函數 可以參看 APUE《Advanced Programming in the Unix Environment》),而上面所說流式文件操作是通過緩沖區來進行操作的(也就是通過庫函數(庫函數帶緩沖區,系統調用不帶緩沖區)來操作文件);流式文件操作是圍繞一個FILE指針來進行,而此類文件操作是圍繞一個文件的“句柄”來進行,什么是句柄呢?它是一個整數,是系統用來標識一個文件(在WINDOWS中,句柄的概念擴展到所有設備資源的標識)的唯一的記號。此類文件操作常用的函數如下表,這些函數及其所用的一些符號在io.h和fcntl.h中定義,在使用時要加入相應的頭文件。
函數 說明 open() 打開一個文件并返回它的句柄 close() 關閉一個句柄 lseek() 定位到文件的指定位置 read() 塊讀文件 write() 塊寫文件 eof() 測試文件是否結束 filelength() 取得文件長度 rename() 重命名文件 chsize() 改變文件長度?
1.open()
打開一個文件并返回它的句柄,如果失敗,將返回一個小于0的值,原型是int open(const char *path, int access [, unsigned mode]); 參數path是要打開的文件名,access是打開的模式,mode是可選項。表示文件的屬性,主要用于UNIX系統中,在DOS/WINDOWS這個參數沒有意義。其中文件的打開模式如下表。
符號 含義 符號 含義 符號 含義
O_RDONLY 只讀方式 O_WRONLY 只寫方式 O_RDWR 讀/寫方式
O_NDELAY 用于UNIX系統 O_APPEND 追加方式 O_CREAT 如果文件不存在就創建
O_TRUNC 把文件長度截為0 O_EXCL 和O_CREAT連用,如果文件存在返回錯誤 O_BINARY 二進制方式 O_TEXT 文本方式
對于多個要求,可以用"|"運算符來連接,如O_APPEND|O_TEXT表示以文本模式和追加方式打開文件。
例:inthandle=open("c:\\msdos.sys",O_BINARY|O_CREAT|O_WRITE)
2.close()
關閉一個句柄,原型是int close(int handle);如果成功返回0
例:close(handle)
3.lseek()
定位到指定的位置,原型是:long lseek(int handle,long offset, int fromwhere);參數offset是移動的量,fromwhere是移動的基準位置,取值和前面講的fseek()一樣,SEEK_SET:文件首部;SEEK_CUR:文件當前位置;SEEK_END:文件尾。此函數返回執行后文件新的存取位置。
例:
lseek(handle,-1234L,SEEK_CUR);//把存取位置從當前位置向前移動1234個字節。
x=lseek(hnd1,0L,SEEK_END);//把存取位置移動到文件尾,x=文件尾的位置即文件長度
4.read()
從文件讀取一塊,原型是int read(int handle, void*buf, unsigned len);參數buf保存讀出的數據,len是讀取的字節。函數返回實際讀出的字節。
例:char x[200];read(hnd1,x,200);
5.write()
寫一塊數據到文件中,原型是int write(int handle,void *buf, unsigned len);參數的含義同read(),返回實際寫入的字節。
例:char x[]="I LoveYou";write(handle,x,strlen(x));
7.eof()
類似feof(),測試文件是否結束,是返回1,否則返回0;原型是:inteof(int handle);
例:while(!eof(handle1)){……};
8.filelength()
返回文件長度,原型是long filelength(int handle);相當于lseek(handle,0L,SEEK_END)
例:long x=filelength(handle);
9.rename()
重命名文件,原型是int rename(const char*oldname, const char *newname); 參數oldname是舊文件名,newname是新文件名。成功返回0
例:rename("c:\\config.sys","c:\\config.w40");
10.chsize();
改變文件長度,原型是int chsize(int handle, longsize);參數size表示文件新的長度,成功返回0,否則返回-1,如果指定的長度小于文件長度,則文件被截短;如果指定的長度大于文件長度,則在文件后面補''\0''。
例:chsize(handle,0x12345);
如果熟悉匯編可能會發現這種方式和匯編語言的DOS功能調用句柄式文件操作很像,比如open()就像DOS服務的3CH號功能調用,其實這種操作還有兩種類型的函數就是直接用DOS功能來完成的,如_open(),_dos_open()等等。有興趣可自已查詢BCB的幫助。
同流式文件操作相同,這種也提供了Unicode字符操作的函數,如_wopen()等等,用于9X/NT下的寬字符編程,有興趣可自已查詢BCB的幫助。
另外,此種操作還有lock(),unlock(),locking()等用于多用戶操作的函數,但在BCB中用得并不多,我就不介紹了,但如果要用C來寫CGI,這些就必要的常識了,如果你有這方面的要求,那就得自已好好看幫助了.
setbuffer(設置文件流的緩沖區)
相關函數 setlinebuf,setbuf,setvbuf
表頭文件 #include<stdio.h>
定義函數 void setbuffer(FILE * stream,char * buf,size_t size);
函數說明 在打開文件流后,讀取內容之前,調用setbuffer()可用來設置文件流的緩沖區。參數stream為指定的文件流,參數buf指向自定的緩沖區起始地址,參數size為緩沖區大小。
返回值
setlinebuf(設置文件流為線性緩沖區)
相關函數 setbuffer,setbuf,setvbuf
表頭文件 #include<stdio.h>
定義函數 void setlinebuf(FILE * stream);
函數說明 setlinebuf()用來設置文件流以換行為依據的無緩沖IO。相當于調用:setvbuf(stream,(char * )NULL,_IOLBF,0);請參考setvbuf()。
返回值
setvbuf(設置文件流的緩沖區)
相關函數 setbuffer,setlinebuf,setbuf
表頭文件 #include<stdio.h>
定義函數 int setvbuf(FILE * stream,char * buf,int mode,size_t size);
函數說明 在打開文件流后,讀取內容之前,調用setvbuf()可以用來設置文件流的緩沖區。參數stream為指定的文件流,參數buf指向自定的緩沖區起始地址,參數size為緩沖區大小,參數mode有下列幾種
_IONBF 無緩沖IO
_IOLBF 以換行為依據的無緩沖IO
_IOFBF 完全無緩沖IO。如果參數buf為NULL指針,則為無緩沖IO。
返回值
?
?
?
總結
以上是生活随笔為你收集整理的C 和 C++ 文件操作详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转载:使用 Frida 来 hook 加
- 下一篇: 在 VC++ 中使用 内联汇编