C語(yǔ)言文件

[TOC]

UNIX的哲學(xué),萬(wàn)物皆文件.

打開(kāi)關(guān)閉文件

FILE * fopen(const char *filename,const char * type);

系統(tǒng)調(diào)用fopen()打開(kāi)文件:給用戶(hù)指定的文件在內(nèi)存中分配一個(gè)FILE結(jié)構(gòu),并將結(jié)構(gòu)返回給用戶(hù)程序,以后用戶(hù)就可以更具FILE指針來(lái)實(shí)現(xiàn)對(duì)文件的存取操作了.當(dāng)使用打開(kāi)函數(shù)時(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.對(duì)于mode有常見(jiàn)的方式

mode description
r (read) 以只讀方式打開(kāi)文件.該文件必須存在;
w (write) 只寫(xiě)的方式.若文件存在原有的內(nèi)容會(huì)被清除;若文件不存在,創(chuàng)建文件;
a (append) 追加方式打開(kāi)只寫(xiě)文件,只允許進(jìn)行寫(xiě)操作.文件存在,則添加內(nèi)容在文件末尾;文件不存在則創(chuàng)建文件 (EOF符保留)
+ (read and write) 可讀可寫(xiě)
b (binary) 以二進(jìn)制方式打開(kāi)文件
t (text) 以文本方式打開(kāi)文件(默認(rèn)以該模式打開(kāi)文件)

2.常見(jiàn)的組合方式

composed mode description
r+ 以讀寫(xiě)的方式操作文件,允許讀寫(xiě).文件必須存在,否則返回NULL.打開(kāi)成功返回指向文件的指針,指向文件的頭部 (注意很多書(shū)上或資料上講述追加方式打開(kāi)成功后位置指針指向文件末尾是錯(cuò)誤的);
rb+ 以可讀可寫(xiě),二進(jìn)制方式打開(kāi)文件,允許讀寫(xiě).文件必須存在,否則返回NULL.若打開(kāi)文件成功返回文件指針,指向文件頭部;
rt+ 以可讀可寫(xiě),文本方式打開(kāi)文件,允許讀寫(xiě).文件必須存在,否則返回NULL.若打開(kāi)文件成功,返回文件指針,指向文件頭部;
w 以只寫(xiě)的方式打開(kāi)文件,只允許寫(xiě),若文件存在,文件中原有內(nèi)容會(huì)被清除;若文件不存在,則創(chuàng)建文件,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
w+ 以讀寫(xiě)的方式打開(kāi)文件,允許讀寫(xiě),若文件存在,文件中原有內(nèi)容會(huì)被清除;若文件不存在,則創(chuàng)建文件,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
a 以追加只寫(xiě)的方式打開(kāi)文件,只允許寫(xiě).若文件存在,則追加的內(nèi)容在文件的末尾,若文件不存在則創(chuàng)建文件.打開(kāi)成功后返回文件的指針,指向文件的頭部.
a+ 以追加、可讀寫(xiě)的方式打開(kāi)文件,允許讀寫(xiě)。若進(jìn)行讀操作,則從頭開(kāi)始讀;若進(jìn)行寫(xiě)操作,則將內(nèi)容添加在末尾。若文件不存在,則創(chuàng)建文件。打開(kāi)成功后返回文件指針,位置指針指向文件頭部(不保留EOF)

二進(jìn)制和文本打開(kāi)方式基本相同,不同的地方是讀取文本是碰到ASCII碼為26的字符是,則會(huì)停止文件的讀寫(xiě),默認(rèn)文件以及結(jié)束.應(yīng)為正常的文本不會(huì)有ASCII碼26的字符.而二進(jìn)制打開(kāi)方式不存在這個(gè)問(wèn)題.(UNIX下沒(méi)有區(qū)別);

注意:

1)在以追加方式打開(kāi)文件時(shí),位置指針指向文件的首部。

? 在這里區(qū)分一下位置指針和文件指針:

? 文件指針:指向存儲(chǔ)文件信息的一個(gè)結(jié)構(gòu)體的指針

? 位置指針:對(duì)文件進(jìn)行讀寫(xiě)操作時(shí)移動(dòng)的指針

? 在頭文件<stdio.h>中存在一個(gè)結(jié)構(gòu)體_iobuf,在VC6.0中選中FILE,然后F12,則可以看到_iobuf的具體定義(UNIX 的大致相同):

struct _iobuf
{
        char *_ptr;               // 指向buffer中第一個(gè)未讀的字節(jié)       
        int   _cnt;                 // 記錄剩余未讀字節(jié)的個(gè)數(shù)
        char *_base;           // 指向一個(gè)字符數(shù)組,即這個(gè)文件的緩沖
        int   _flag;                // FILE結(jié)構(gòu)所代表的打開(kāi)文件的一些屬性
        int   _file;                 // 用于獲取文件描述,可以使用fileno函數(shù)獲得此文件的句柄。
        int   _charbuf;          // 單字節(jié)的緩沖,即緩沖大小僅為1個(gè)字節(jié),如果為單字節(jié)緩沖,_base將無(wú)效
        int   _bufsiz;            // 記錄這個(gè)緩沖的大小
        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定義了一個(gè)文件指針,并成功打開(kāi)一個(gè)文件之后,fp只是指向該結(jié)構(gòu)體,而在對(duì)文件進(jìn)行讀寫(xiě)操作時(shí),fp的值并不會(huì)改變,改變的是結(jié)構(gòu)體中_ptr的值,這個(gè)_ptr就是位置指針。

? 2)以追加方式打開(kāi)時(shí),若進(jìn)行寫(xiě)操作,則rewind函數(shù)和fseek函數(shù)不會(huì)起到作用,因?yàn)橐宰芳臃绞酱蜷_(kāi)時(shí)進(jìn)行寫(xiě)操作的話(huà),系統(tǒng)會(huì)自動(dòng)將位置指針移動(dòng)到末尾。

? 3)當(dāng)文件打開(kāi)用于更新時(shí),可以通過(guò)文件指針對(duì)文件進(jìn)行讀寫(xiě)操作,但是如果沒(méi)有給出fseek或者rewind的話(huà),讀操作后面不能直接跟寫(xiě)操作,否則會(huì)是無(wú)效的寫(xiě)操作(位置指針會(huì)移動(dòng),但是需要寫(xiě)入文件的內(nèi)容不會(huì)被寫(xiě)入到文件當(dāng)中),但是寫(xiě)操作后可以直接跟讀操作。

每次調(diào)用fopen()打開(kāi)文件后都要記得調(diào)用fclose()關(guān)閉文件

C語(yǔ)言提供了以下幾種文件讀寫(xiě)方式

1.字符讀寫(xiě): fgetc()/fputc() (讀/寫(xiě));

fgetc()函數(shù):

(1)一般調(diào)用形式: char ch = fgetc(fd);

(2)作用: 文件中讀取一個(gè)字符;

(3)返回值:

? 成功:返回值所得到的字符;
? 失?。悍祷谽OF(-1)。

*注意問(wèn)的打開(kāi)方式

fputc()函數(shù):

(1)一般調(diào)用形式: char res = fputc(fd,ch);

(2)作用: 文件中寫(xiě)入一個(gè)字符;

(3)返回值

? 成功:函數(shù)輸入的字符;
? 失?。悍祷谽OF(-1)。

說(shuō)明:函數(shù)putchar()是在stdio.h中用預(yù)處理命令定義的宏,即:

//define putchar(c) fputc(c,stdout)

char a = 'a';
char ch = fgetc(fd);
char res = fputc(a, fd);

字符串讀寫(xiě): fgets()/fputs() (讀/寫(xiě));

1.fgets()函數(shù):

  • 一般調(diào)用形式:char * fgets(char *str ,int num ,FILE *fd); (fd 的mode rt)

    參數(shù)說(shuō)明: str 保存從文件中讀取的字符串;
    ? num 從文件中讀取的字符串中字符個(gè)數(shù)不超過(guò)num-1.在讀入最后一個(gè)字符后加上串結(jié)束標(biāo)志'\0';

  • 返回值:
    成功: 返的字符串;

    失敗: 返回NULL

    ?

2.fputs() 文件中寫(xiě)入字符串

  • 一般調(diào)用形式: int num = fputs(char *s,FILE *fd); (fd 的mode at+)

    s 要寫(xiě)入的字符串;

    fd 待寫(xiě)入的文件;

    返回值:

    ? 成功: 寫(xiě)入的字符個(gè)數(shù)num;

    ? 失敗: EOF(-1);

int res = fputs("test", fd);
    
char rs[11];
char *r = fgets(rs, 11, fd);

數(shù)據(jù)塊讀寫(xiě): fwrite()/fread() (讀/寫(xiě))

  • 一般調(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ù)說(shuō)明:

    buffer: 緩沖區(qū)指針.對(duì)fread,它是暫存讀入數(shù)據(jù)的指針;對(duì)fwrite,它是要輸出數(shù)據(jù)的指針;
    size: 要讀寫(xiě)的字節(jié)數(shù);
    count: 要進(jìn)行讀寫(xiě)多少個(gè)size字節(jié)的數(shù)據(jù)項(xiàng);
    fd: 待讀寫(xiě)的文件指針;

#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;
}

本例程序定義了一個(gè)結(jié)構(gòu)stu,說(shuō)明了兩個(gè)結(jié)構(gòu)數(shù)組boya和boyb以及兩個(gè)結(jié)構(gòu)指針變量pp和qq。pp指向boya,qq指向boyb。程序第14行以讀寫(xiě)方式打開(kāi)二進(jìn)制文件“stu_list”,輸入二個(gè)學(xué)生數(shù)據(jù)之后,寫(xiě)入該文件中,然后把文件內(nèi)部位置指針移到文件首,讀出兩塊學(xué)生數(shù)據(jù)后,在屏幕上顯示。

格式化讀寫(xiě): fscanf()/fprintf() (寫(xiě)/讀);

一般調(diào)用形式:

? (1)int fprintf(FILE *stream,const char *format,[argument]…) 輸出格式化字符串或者將格式化字符串輸出到流 (文件);

? (2)int fscanf(FILE *stream, const char *) 輸入文件中的內(nèi)容到某個(gè)變量中.

? fscanf(fd,"%s",res)

返回值:

? 成功:

? fprintf讀取的字符個(gè)數(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ù): 得到流式文件的當(dāng)前讀寫(xiě)位置,返回流式文件當(dāng)前讀寫(xiě)位置距離文件頭部的字節(jié)數(shù).

long     ftell(FILE *);

fseek(): 把fd 的文件讀寫(xiě)位置指針移動(dòng)到知道的位置;

@param FILE* 待操作的文件指針
@param long  距離起始點(diǎn)的位置
@parma int   計(jì)算的起始點(diǎn)
@return  0 success 文件位置指針指向正確的offset,錯(cuò)誤返回-1
/*
    有三類(lèi)起始點(diǎn)
    SEEK_SET 0   文件開(kāi)頭
    SEEK_CUR 1   文件當(dāng)前位置
    SEEK_END 2   文件末尾
*/
int  fseek(FILE *, long offset, int origin);

rewind(): 將文件位置指針重新指向一個(gè)文件流的開(kāi)頭

void     rewind(FILE *);

eg:

long fileLength = 0; 
fseek(fd, 0, SEEK_END);
fileLength = ftell(fd);
rewind(fd);

fflush():清空緩存

所謂flush一個(gè)緩沖,是指對(duì)寫(xiě)緩沖而言,將緩沖內(nèi)的數(shù)據(jù)全部寫(xiě)入實(shí)際的文件,并將緩沖清空,這樣可以保證文件處于最新的狀態(tài)。之所以需要flush,是因?yàn)閷?xiě)緩沖使得文件處于一種不同步的狀態(tài),邏輯上一些數(shù)據(jù)已經(jīng)寫(xiě)入了文件,但實(shí)際上這些數(shù)據(jù)仍然在緩沖中,如果此時(shí)程序意外地退出(發(fā)生異?;驍嚯姷龋?,那么緩沖里的數(shù)據(jù)將沒(méi)有機(jī)會(huì)寫(xiě)入文件。flush可以在一定程度上避免這樣的情況發(fā)生。

在這個(gè)表中我們還能看到C語(yǔ)言支持兩種緩沖,即行緩沖(Line Buffer)和全緩沖(Full Buffer)。全緩沖是經(jīng)典的緩沖形式,除了用戶(hù)手動(dòng)調(diào)用fflush外,僅當(dāng)緩沖滿(mǎn)的時(shí)候,緩沖才會(huì)被自動(dòng)flush掉。而行緩沖則比較特殊,這種緩沖僅用于文本文件,在輸入輸出遇到一個(gè)換行符時(shí),緩沖就會(huì)被自動(dòng)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語(yǔ)言文件操作和操作系統(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

? http://c.biancheng.net/cpp/html/107.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 語(yǔ)言中對(duì)文件進(jìn)行操作必須首先打開(kāi)文件,打開(kāi)文件主要涉及到fopen函數(shù)。fopen函數(shù)的原型為 FILE* fop...
    朱森閱讀 911評(píng)論 0 1
  • 文件指針 FILE * 指針變量標(biāo)識(shí)符作用:通過(guò)該指針即可找到存放某個(gè)文件信息的結(jié)構(gòu)變量,然后按結(jié)構(gòu)變量提供的信息...
    永斷閻羅閱讀 503評(píng)論 0 3
  • 所謂“文件”是指一組相關(guān)數(shù)據(jù)的有序集合,該數(shù)據(jù)的集合的名字就是文件名。文件可以分為很多類(lèi),如源程序文件、目標(biāo)文件、...
    一葉之界閱讀 546評(píng)論 0 0
  • c語(yǔ)言里面的各種字符/字符串讀寫(xiě)一直搞得我分不清楚。。今天來(lái)學(xué)習(xí)總結(jié)一下:原文章來(lái)自http://www.cnbl...
    AwesomeAshe閱讀 558評(píng)論 0 0
  • Android NDK開(kāi)發(fā)之旅 目錄 文件讀寫(xiě) 一個(gè)文件,無(wú)論它是文本文件還是二進(jìn)制文件,都是代表了一系列的字節(jié)。...
    香沙小熊閱讀 4,676評(píng)論 0 4

友情鏈接更多精彩內(nèi)容