[TOC]
UNIX的哲學(xué),萬物皆文件.
打開關(guān)閉文件
FILE * fopen(const char *filename,const char * type);
系統(tǒng)調(diào)用fopen()打開文件:給用戶指定的文件在內(nèi)存中分配一個FILE結(jié)構(gòu),并將結(jié)構(gòu)返回給用戶程序,以后用戶就可以更具FILE指針來實現(xiàn)對文件的存取操作了.當使用打開函數(shù)時必須給出文件名和操作方式.如果文件名不存在,就意味著創(chuàng)建文件,并將FILE *指針指向該文件.如果存在就意味著刪除該文件.
FILE 結(jié)構(gòu)體如下
typedef struct __sFILE {
unsigned char *_p; /* current position in (some) buffer */
int _r; /* read space left for getc() */
int _w; /* write space left for putc() */
short _flags; /* flags, below; this FILE is free if 0 */
short _file; /* fileno, if Unix descriptor, else -1 */
struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
int _lbfsize; /* 0 or -_bf._size, for inline putc */
/* operations */
void *_cookie; /* cookie passed to io functions */
int (* _Nullable _close)(void *);
int (* _Nullable _read) (void *, char *, int);
fpos_t (* _Nullable _seek) (void *, fpos_t, int);
int (* _Nullable _write)(void *, const char *, int);
/* separate buffer for long sequences of ungetc() */
struct __sbuf _ub; /* ungetc buffer */
struct __sFILEX *_extra; /* additions to FILE to not break ABI */
int _ur; /* saved _r when _r is counting ungetc data */
/* tricks to meet minimum requirements even when malloc() fails */
unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
unsigned char _nbuf[1]; /* guarantee a getc() buffer */
/* separate buffer for fgetln() when line crosses buffer boundary */
struct __sbuf _lb; /* buffer for fgetln() */
/* Unix stdio files get aligned to block boundaries on fseek() */
int _blksize; /* stat.st_blksize (may be != _bf._size) */
fpos_t _offset; /* current lseek offset (see WARNING) */
} FILE;
1.對于mode有常見的方式
mode | description |
---|---|
r (read) | 以只讀方式打開文件.該文件必須存在; |
w (write) | 只寫的方式.若文件存在原有的內(nèi)容會被清除;若文件不存在,創(chuàng)建文件; |
a (append) | 追加方式打開只寫文件,只允許進行寫操作.文件存在,則添加內(nèi)容在文件末尾;文件不存在則創(chuàng)建文件 (EOF符保留) |
+ (read and write) | 可讀可寫 |
b (binary) | 以二進制方式打開文件 |
t (text) | 以文本方式打開文件(默認以該模式打開文件) |
2.常見的組合方式
composed mode | description |
---|---|
r+ | 以讀寫的方式操作文件,允許讀寫.文件必須存在,否則返回NULL.打開成功返回指向文件的指針,指向文件的頭部 (注意很多書上或資料上講述追加方式打開成功后位置指針指向文件末尾是錯誤的); |
rb+ | 以可讀可寫,二進制方式打開文件,允許讀寫.文件必須存在,否則返回NULL.若打開文件成功返回文件指針,指向文件頭部; |
rt+ | 以可讀可寫,文本方式打開文件,允許讀寫.文件必須存在,否則返回NULL.若打開文件成功,返回文件指針,指向文件頭部; |
w | 以只寫的方式打開文件拄轻,只允許寫滑频,若文件存在,文件中原有內(nèi)容會被清除;若文件不存在,則創(chuàng)建文件钾虐,打開成功后返回文件指針,位置指針指向文件頭部 |
w+ | 以讀寫的方式打開文件,允許讀寫庆冕,若文件存在,文件中原有內(nèi)容會被清除劈榨;若文件不存在访递,則創(chuàng)建文件,打開成功后返回文件指針鞋既,位置指針指向文件頭部 |
a | 以追加只寫的方式打開文件,只允許寫.若文件存在,則追加的內(nèi)容在文件的末尾,若文件不存在則創(chuàng)建文件.打開成功后返回文件的指針,指向文件的頭部. |
a+ | 以追加力九、可讀寫的方式打開文件耍铜,允許讀寫邑闺。若進行讀操作,則從頭開始讀棕兼;若進行寫操作陡舅,則將內(nèi)容添加在末尾。若文件不存在伴挚,則創(chuàng)建文件靶衍。打開成功后返回文件指針,位置指針指向文件頭部(不保留EOF) |
二進制和文本打開方式基本相同,不同的地方是讀取文本是碰到ASCII碼為26的字符是,則會停止文件的讀寫,默認文件以及結(jié)束.應(yīng)為正常的文本不會有ASCII碼26的字符.而二進制打開方式不存在這個問題.(UNIX下沒有區(qū)別);
注意:
1)在以追加方式打開文件時茎芋,位置指針指向文件的首部颅眶。
? 在這里區(qū)分一下位置指針和文件指針:
? 文件指針:指向存儲文件信息的一個結(jié)構(gòu)體的指針
? 位置指針:對文件進行讀寫操作時移動的指針
? 在頭文件<stdio.h>中存在一個結(jié)構(gòu)體_iobuf,在VC6.0中選中FILE田弥,然后F12涛酗,則可以看到_iobuf的具體定義(UNIX 的大致相同):
struct _iobuf
{
char *_ptr; // 指向buffer中第一個未讀的字節(jié)
int _cnt; // 記錄剩余未讀字節(jié)的個數(shù)
char *_base; // 指向一個字符數(shù)組,即這個文件的緩沖
int _flag; // FILE結(jié)構(gòu)所代表的打開文件的一些屬性
int _file; // 用于獲取文件描述偷厦,可以使用fileno函數(shù)獲得此文件的句柄商叹。
int _charbuf; // 單字節(jié)的緩沖,即緩沖大小僅為1個字節(jié)只泼,如果為單字節(jié)緩沖剖笙,_base將無效
int _bufsiz; // 記錄這個緩沖的大小
char *_tmpfname; // temporary file (i.e., one created by tmpfile()
// call). delete, if necessary (don't have to on
// Windows NT because it was done by the system when
// the handle was closed). also, free up the heap
// block holding the pathname.
};
typedef struct _iobuf FILE;
? 比如用FILE *fp定義了一個文件指針,并成功打開一個文件之后请唱,fp只是指向該結(jié)構(gòu)體弥咪,而在對文件進行讀寫操作時过蹂,fp的值并不會改變,改變的是結(jié)構(gòu)體中_ptr的值聚至,這個_ptr就是位置指針榴啸。
? 2)以追加方式打開時,若進行寫操作晚岭,則rewind函數(shù)和fseek函數(shù)不會起到作用鸥印,因為以追加方式打開時進行寫操作的話,系統(tǒng)會自動將位置指針移動到末尾坦报。
? 3)當文件打開用于更新時库说,可以通過文件指針對文件進行讀寫操作,但是如果沒有給出fseek或者rewind的話片择,讀操作后面不能直接跟寫操作潜的,否則會是無效的寫操作(位置指針會移動,但是需要寫入文件的內(nèi)容不會被寫入到文件當中)字管,但是寫操作后可以直接跟讀操作啰挪。
每次調(diào)用fopen()打開文件后都要記得調(diào)用fclose()關(guān)閉文件
C語言提供了以下幾種文件讀寫方式
1.字符讀寫: fgetc()/fputc() (讀/寫);
fgetc()函數(shù):
(1)一般調(diào)用形式: char ch = fgetc(fd);
(2)作用: 文件中讀取一個字符;
(3)返回值:
? 成功:返回值所得到的字符;
? 失敵笆濉:返回EOF(-1)亡呵。
*注意問的打開方式
fputc()函數(shù):
(1)一般調(diào)用形式: char res = fputc(fd,ch);
(2)作用: 文件中寫入一個字符;
(3)返回值
? 成功:函數(shù)輸入的字符;
? 失斄蚋辍:返回EOF(-1)锰什。
說明:函數(shù)putchar()是在stdio.h中用預(yù)處理命令定義的宏,即:
//define putchar(c) fputc(c,stdout)
char a = 'a';
char ch = fgetc(fd);
char res = fputc(a, fd);
字符串讀寫: fgets()/fputs() (讀/寫);
1.fgets()函數(shù):
-
一般調(diào)用形式:char * fgets(char *str ,int num ,FILE *fd); (fd 的mode rt)
參數(shù)說明: str 保存從文件中讀取的字符串;
? num 從文件中讀取的字符串中字符個數(shù)不超過num-1.在讀入最后一個字符后加上串結(jié)束標志'\0'; -
返回值:
成功: 返的字符串;失敗: 返回NULL
?
2.fputs() 文件中寫入字符串
-
一般調(diào)用形式: int num = fputs(char *s,FILE *fd); (fd 的mode at+)
s 要寫入的字符串;
fd 待寫入的文件;
返回值:
? 成功: 寫入的字符個數(shù)num;
? 失敗: EOF(-1);
int res = fputs("test", fd);
char rs[11];
char *r = fgets(rs, 11, fd);
數(shù)據(jù)塊讀寫: fwrite()/fread() (讀/寫)
-
一般調(diào)用形式:
size_t fwrite(void *buffer,size_t size ,size_t count, FILE *fd);
size_t fread(void *buffer,size_t size, size_t count ,FILE *fd);
-
參數(shù)說明:
buffer: 緩沖區(qū)指針.對fread,它是暫存讀入數(shù)據(jù)的指針;對fwrite,它是要輸出數(shù)據(jù)的指針;
size: 要讀寫的字節(jié)數(shù);
count: 要進行讀寫多少個size字節(jié)的數(shù)據(jù)項;
fd: 待讀寫的文件指針;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu{
int age;
int num;
char name[10];
char addr[20];
}boya[2],boyb[2],*qq,*pp;
int main() {
FILE *fd;
char ch;
int i;
qq = boya;
pp = boyb;
if ((fd = fopen("/Users/sks/Desktop/stu_list", "wb+")) == NULL) {
printf("Cannot open file. Strike any key to exit!");
getchar();
exit(1);
}
printf("intput data\n");
for (i=0; i<2; i++,qq++) {
scanf("%d%d%s%s",&qq->age,&qq->num,qq->name,qq->addr);
}
qq = boya;
size_t writeSize = fwrite(qq, sizeof(struct stu), 2, fd);
rewind(fd);
size_t readSize = fread(pp, sizeof(struct stu), 2, fd);
printf("\n\nname\tnumber age addr\n");
for (i=0; i<2; i++,pp++) {
printf("%s %d %d %s\n",pp->name,pp->num,pp->age,pp->addr);
}
fclose(fd);
return 0;
}
本例程序定義了一個結(jié)構(gòu)stu丁逝,說明了兩個結(jié)構(gòu)數(shù)組boya和boyb以及兩個結(jié)構(gòu)指針變量pp和qq汁胆。pp指向boya,qq指向boyb霜幼。程序第14行以讀寫方式打開二進制文件“stu_list”嫩码,輸入二個學(xué)生數(shù)據(jù)之后,寫入該文件中罪既,然后把文件內(nèi)部位置指針移到文件首铸题,讀出兩塊學(xué)生數(shù)據(jù)后,在屏幕上顯示萝衩。
格式化讀寫: fscanf()/fprintf() (寫/讀);
一般調(diào)用形式:
? (1)int fprintf(FILE *stream,const char *format,[argument]…) 輸出格式化字符串或者將格式化字符串輸出到流 (文件);
? (2)int fscanf(FILE *stream, const char *) 輸入文件中的內(nèi)容到某個變量中.
? fscanf(fd,"%s",res)
返回值:
? 成功:
? fprintf讀取的字符個數(shù);
? fscanf: 返回1
? 失敗:
? EOF;
int res = fprintf(fd, "%s",s);
if (res == EOF) {
printf("輸入失敗\n");
}
char tmp[26];
//
int len = fscanf(fd, "%s\n",tmp);
?
其他文件相關(guān)操作
ftell()函數(shù): 得到流式文件的當前讀寫位置,返回流式文件當前讀寫位置距離文件頭部的字節(jié)數(shù).
long ftell(FILE *);
fseek(): 把fd 的文件讀寫位置指針移動到知道的位置;
@param FILE* 待操作的文件指針
@param long 距離起始點的位置
@parma int 計算的起始點
@return 0 success 文件位置指針指向正確的offset,錯誤返回-1
/*
有三類起始點
SEEK_SET 0 文件開頭
SEEK_CUR 1 文件當前位置
SEEK_END 2 文件末尾
*/
int fseek(FILE *, long offset, int origin);
rewind(): 將文件位置指針重新指向一個文件流的開頭
void rewind(FILE *);
eg:
long fileLength = 0;
fseek(fd, 0, SEEK_END);
fileLength = ftell(fd);
rewind(fd);
fflush():清空緩存
所謂flush一個緩沖回挽,是指對寫緩沖而言,將緩沖內(nèi)的數(shù)據(jù)全部寫入實際的文件猩谊,并將緩沖清空千劈,這樣可以保證文件處于最新的狀態(tài)。之所以需要flush牌捷,是因為寫緩沖使得文件處于一種不同步的狀態(tài)墙牌,邏輯上一些數(shù)據(jù)已經(jīng)寫入了文件涡驮,但實際上這些數(shù)據(jù)仍然在緩沖中,如果此時程序意外地退出(發(fā)生異诚脖酰或斷電等)捉捅,那么緩沖里的數(shù)據(jù)將沒有機會寫入文件。flush可以在一定程度上避免這樣的情況發(fā)生虽风。
在這個表中我們還能看到C語言支持兩種緩沖棒口,即行緩沖(Line Buffer)和全緩沖(Full Buffer)。全緩沖是經(jīng)典的緩沖形式辜膝,除了用戶手動調(diào)用fflush外无牵,僅當緩沖滿的時候,緩沖才會被自動flush掉厂抖。而行緩沖則比較特殊茎毁,這種緩沖僅用于文本文件,在輸入輸出遇到一個換行符時忱辅,緩沖就會被自動flush七蜘,因此叫行緩沖。
FILE *fd;
if ((fd = fopen("/Users/sks/Desktop/ch.txt", "w")) == NULL) {
printf("Open file failed.Press any key to exit!");
getchar();
exit(1);
}
Student stu;
stu.number = 10000;
// stu.name = "guohuabing";
strcpy(stu.name, "guohuabing");
fflush(fd);
fwrite(&stu, sizeof(struct SStudent), 1, fd);
fclose(fd);
socket 通信和文件操作的關(guān)系
待續(xù)....
C語言文件操作和操作系統(tǒng)文件子系統(tǒng)的關(guān)系
參考:
? http://www.2cto.com/kf/201207/143344.html
? http://www.cnblogs.com/L-hq815/archive/2012/06/30/2571066.html
? http://www.cnblogs.com/dolphin0520/archive/2011/10/05/2199598.html