C語言 IO操做

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *from,*to;
    char ch;
    if((from = fopen("from.txt","r"))==NULL)
    {
        printf("文件打開失敗!\n");
        exit(1);
    }
    else
    {
        to = fopen("to.txt","w");
        while((ch=fgetc(from))!=EOF)
        {
            fputc(ch,to);
        }
        fclose(from);
        fclose(to);
        exit(0);
    }
}

 

轉自:http://blog.csdn.net/my_offer/article/details/6791324程序員

1、標準文件的讀寫編程

1.文件的打開fopen() 文件的打開操做表示將給用戶指定的文件在內存分配一個FILE結構區,並將該結構的指針返回給用戶程序,之後用戶程序就可用此FILE指針來實現對指定文件的存取操做了。當使用打開函數時,必須給出文件名、文件操做方式(讀、寫或讀寫),若是該文件名不存在,就意味着創建(只對寫文件而言,對讀文件則出錯),並將文件指針指向文件開頭。若已有一個同名文件存在,則刪除該文件,若無同名文件,則創建該文件,並將文件指針指向文件開頭。 fopen(char *filename,char *type); 其中*filename是要打開文件的文件名指針,通常用雙引號括起來的文件名錶示,也可以使用雙反斜槓隔開的路徑名。而*type參數表示了對打開文件的操做方式。其可採用的操做方式以下: 方式 含義 "r" 打開,只讀 "w" 打開,文件指針指到頭,只寫 "a" 打開,指向文件尾,在已存在文件中追加 "rb" 打開一個二進制文件,只讀 "wb" 打開一個二進制文件,只寫 "ab" 打開一個二進制文件,進行追加 "r+" 以讀/寫方式打開一個已存在的文件 "w+" 以讀/寫方式創建一個新的文本文件 "a+" 以讀/寫方式打開一個文件文件進行追加 "rb+" 以讀/寫方式打開一個二進制文件 "wb+" 以讀/寫方式創建一個新的二進制文件 "ab+" 以讀/寫方式打開一個二進制文件進行追加 當用fopen(0成功的打開一個文件時,該函數將返回一個FILE指針,若是文件打開失敗,將返回一個NULL指針。如想打開test文件,進行寫: FILE *fp; if((fp=fopen("test","w"))==NULL) { printf("File cannot be opened"); exit(); } else printf("File opened for writing"); …… fclose(fp); DOS操做系統對同時打開的文件數目是有限制的,缺省值爲5,能夠經過修改CONFIG.SYS文件改變這個設置。數組

2.關閉文件函數fclose() 文件操做完成後,必需要用fclose()函數進行關閉,這是由於對打開的文件進行寫入時,若文件緩衝區的空間未被寫入的內容填滿,這些內容不會寫到打開的文件中去而丟失。只有對打開的文件進行關閉操做時,停留在文件緩衝區的內容才能寫到該文件中去,從而使文件完整。再者一旦關閉了文件,該文件對應的FILE結構將被釋放,從而使關閉的文件獲得保護,由於這時對該文件的存取操做將不會進行。文件的關閉也意味着釋放了該文件的緩衝區。 int fclose(FILE *stream); 它表示該函數將關閉FILE指針對應的文件,並返回一個整數值。若成功地關閉了文件,則返回一個0值,不然返回一個非0值。經常使用如下方法進行測試: if(fclose(fp)!=0) { printf("File cannot be closed"); exit(1); } else printf("File is now closed"); 當打開多個文件進行操做,而又要同時關閉時,可採用fcloseall()函數,它將關閉全部在程序中打開的文件。 int fcloseall(); 該函數將關閉全部已打開的文件,將各文件緩衝區未裝滿的內容寫到相應的文件中去,接着釋放這些緩衝區,並返回關閉文件的數目。如關閉了4個文件,則當執行: n=fcloseall(); 時,n應爲4。緩存

3.文件的讀寫 (1).讀寫文件中字符的函數(一次只讀寫文件中的一個字符): int fgetc(FILE *stream); int getchar(void); int fputc(int ch,FILE *stream); int putchar(int ch); int getc(FILE *stream); int putc(int ch,FILE *stream); 其中fgetc()函數將把由流指針指向的文件中的一個字符讀出,例如: ch=fgetc(fp); 將把流指針fp指向的文件中的一個字符讀出,並賦給ch,當執行fgetc()函數時,若當時文件指針指到文件尾,即遇到文件結束標誌EOF(其對應值爲-1),該函數返回一個-1給ch,在程序中經常使用檢查該函數返回值是否爲-1來判斷是否已讀到文件尾,從而決定是否繼續。 #include "stdio.h" main() { FILE *fp; ch ch; if((fp=fopen("myfile.tex","r"))==NULL) { printf("file cannot be opened"); exit(1); } while((ch=fgetc(fp))!=EOF) fputc(ch,stdout); fclose(fp); } 該程序以只讀方式打開myfile.txt文件,在執行while循環時,文件指針每循環一次後移一個字符位置。用fgetc()函數將文件指針指定的字符讀到ch變量中,而後用fputc()函數在屏幕上顯示,當讀到文件結束標誌EOF時,變關閉該文件。 上面的程序用到了fputc()函數,該函數將字符變量ch的值寫到流指針指定的文件中去,因爲流指針用的是標準輸出(顯示器)的FILE指針stdout,故讀出的字符將在顯示器上顯示。又好比: fputc(ch,fp); 該函數執行結構,將把ch表示的字符送到流指針fp指向的文件中去。 在TC中,putc()等價於fputc(),getc()等價於fgetc()。 putchar(c)至關於fputc(c,stdout);getchar()至關於fgetc(stdin)。 注意,這裏使用char ch,實際上是不科學的,由於最後判斷結束標誌時,是看ch!=EOF,而EOF的值爲-1,這顯然和char是不能比較的。因此,某些使用,咱們都定義成int ch。 (2).讀寫文件中字符串的函數 char *fgets(char *string,int n,FILE *stream); char *gets(char *s); int fprintf(FILE *stream,char *format,variable-list); int fputs(char *string,FILE *stream); int fscanf(FILE *stream,char *format,variable-list); 其中fgets()函數將把由流指針指定的文件中n-1個字符,讀到由指針stream指向的字符數組中去,例如: fgets(buffer,9,fp); 將把fp指向的文件中的8個字符讀到buffer內存區,buffer能夠是定義的字符數組,也能夠是動態分配的內存區。 注意,fgets()函數讀到''就中止,而不論是否達到數目要求。同時在讀取字符串的最後加上''。 fgets()函數執行完之後,返回一個指向該串的指針。若是讀到文件尾或出錯,則均返回一個空指針NULL,因此長用feof()函數來測定是否到了文件尾或者是ferror()函數來測試是否出錯,例以下面的程序用fgets()函數讀test.txt文件中的第一行並顯示出來: #include "stdio.h" main() { FILE *fp; char str[128]; if((fp=fopen("test.txt","r"))==NULL) { printf("cannot open file"); exit(1); } while(!feof(fp)) { if(fgets(str,128,fp)!=NULL) printf("%s",str); } fclose(fp); } gets()函數執行時,只要未遇到換行符或文件結束標誌,將一直讀下去。所以讀到何時爲止,須要用戶進行控制,不然可能形成存儲區的溢出。 fputs()函數想指定文件寫入一個由string指向的字符串,''不寫入文件。 fprintf()和fscanf()同printf()和scanf()函數相似,不一樣之處就是printf()函數是想顯示器輸出,fprintf()則是向流指針指向的文件輸出;fscanf()是從文件輸入。 下面程序是向文件test.dat裏輸入一些字符: #include main() { char *s="That's good news"; int i=617; FILE *fp; fp=fopen("test.dat", "w"); /×創建一個文字文件只寫*/ fputs("Your score of TOEFL is",fp); /×向所建文件寫入一串字符*/ fputc(':', fp); /×向所建文件寫冒號:*/ fprintf(fp, "%d", i); /×向所建文件寫一整型數*/ fprintf(fp, "%s", s); /×向所建文件寫一字符串*/ fclose(fp); } 用DOS的TYPE命令顯示TEST.DAT的內容以下所示: 屏幕顯示 Your score of TOEFL is: 617 That's good news 下面的程序是把上面的文件test.dat裏的內容在屏幕上顯示出來: #include main() { char *s, m[20]; int i; FILE *fp; fp=fopen("test.dat", "r"); /×打開文字文件只讀*/ fgets(s, 24, fp); /×從文件中讀取23個字符*/ printf("%s", s); fscanf(fp, "%d", &i); /×讀取整型數*/ printf("%d", i); putchar(fgetc(fp)); /×讀取一個字符同時輸出*/ fgets(m, 17, fp); /×讀取16個字符*/ puts(m); /×輸出所讀字符串*/ fclose(fp); getch(); } 運行後屏幕顯示: Your score of TOEFL is: 617 That's good news網絡

4.清除和設置文件緩衝區數據結構

(1).清除文件緩衝區函數: int fflush(FILE *stream); int flushall(); fflush()函數將清除由stream指向的文件緩衝區裏的內容,經常使用於寫完一些數據後,當即用該函數清除緩衝區,以避免誤操做時,破壞原來的數據。 flushall()將清除全部打開文件所對應的文件緩衝區。函數

(2).設置文件緩衝區函數 void setbuf(FILE *stream,char *buf); void setvbuf(FILE *stream,char *buf,int type,unsigned size); 這兩個函數將使得打開文件後,用戶可創建本身的文件緩衝區,而不使用fopen()函數打開文件設定的默認緩衝區。 對於setbuf()函數,buf指出的緩衝區長度由頭文件stdio.h中定義的宏BUFSIZE的值決定,缺省值爲512字節。當選定buf爲空時,setbuf函數將使的文件I/O不帶緩衝。而對setvbuf函數,則由malloc函數來分配緩衝區。參數size指明瞭緩衝區的長度(必須大於0),而參數type則表示了緩衝的類型,其值能夠取以下值: type 值 含義 _IOFBF 文件所有緩衝,即緩衝區裝滿後,才能對文件讀寫 _IOLBF 文件行緩衝,即緩衝區接收到一個換行符時,才能對文件讀寫 _IONBF 文件不緩衝,此時忽略buf,size的值,直接讀寫文件,再也不通過文件緩衝區緩衝測試

5.文件的隨機讀寫函數 前面介紹的文件的字符/字符串讀寫,均是進行文件的順序讀寫,即老是從文件的開頭開始進行讀寫。這顯然不能知足咱們的要求,C語言提供了移動文件指針和隨機讀寫的函數,它們是:操作系統

(1).移動文件指針函數: long ftell(FILE *stream); int rewind(FILE *stream); fseek(FILE *stream,long offset,int origin); 函數ftell()用來獲得文件指針離文件開頭的偏移量。當返回值是-1時表示出錯。rewind()函數用於文件指針移到文件的開頭,當移動成功時,返回0,不然返回一個非0值。fseek()函數用於把文件指針以origin爲起點移動offset個字節,其中origin指出的位置可有如下幾種: origin 數值 表明的具體位置 SEEK_SET 0 文件開頭 SEEK_CUR 1 文件指針當前位置 SEEK_END 2 文件尾 例如: fseek(fp,10L,0); 把文件指針從文件開頭移到第10字節處,因爲offset參數要求是長整型數,故其數後帶L。 fseek(fp,-15L,2); 把文件指針從文件尾向前移動15字節。.net

(2).文件隨機讀寫函數 int fread(void *ptr,int size,int nitems,FILE *stream); int fwrite(void *ptr,int size,int nitems,FILE *stream); fread()函數從流指針指定的文件中讀取nitems個數據項,每一個數據項的長度爲size個字節,讀取的nitems數據項存入由ptr指針指向的內存緩衝區中,在執行fread()函數時,文件指針隨着讀取的字節數而向後移動,最後移動結束的位置等於實際讀出的字節數。該函數執行結束後,將返回實際讀出的數據項數,這個數據項數不必定等於設置的nitems,由於若文件中沒有足夠的數據項,或讀中間出錯,都會致使返回的數據項數少於設置的nitems。當返回數不等於nitems時,能夠用feof()或ferror()函數進行檢查。 fwrite()函數從ptr指向的緩衝區中取出長度爲size字節的nitems個數據項,寫入到流指針stream指向的文件中,執行該操做後,文件指針將向後移動,移動的字節數等於寫入文件的字節數目。該函數操做完成後,也將返回寫入的數據項數。

2、非標準文件的讀寫 這類函數最先用於UNIX操做系統,ANSI標準未定義,但有時也常常用到,DOS 3.0以上版本支持這些函數。它們的頭文件爲io.h。 因爲咱們不經常使用這些函數,因此在這裏就簡單說一下。

1.文件的打開和關閉 open()函數的做用是打開文件,其調用格式爲: int open(char *filename, int access); 該函數表示按access的要求打開名爲filename的文件,返回值爲文件描述字,其中access有兩部份內容: 基本模式和修飾符, 二者用" "("或")方式鏈接。修飾符能夠有多個, 但基本模式只能有一個。 access的規定 ———————————————————————————————————————————————————————— 基本模式 含義 修飾符 含 義 ———————————————————————————————————————————————————————— O_RDONLY 只讀 O_APPEND 文件指針指向末尾 O_WRONLY 只寫 O_CREAT 文件不存在時建立文件, 屬性按基本模式屬性 O_RDWR 讀寫 O_TRUNC 若文件存在, 將其長度縮爲0, 屬性不變 O_BINARY 打開一個二進制文件 O_TEXT 打開一個文字文件 ————————————————————————————————————————————————————————- open()函數打開成功, 返回值就是文件描述字的值(非負值), 不然返回-1。 close()函數的做用是關閉由open()函數打開的文件, 其調用格式爲: int close(int handle); 該函數關閉文件描述字handle相連的文件。

2.讀寫函數 int read(int handle, void *buf, int count); read()函數從handle(文件描述字)相連的文件中, 讀取count個字節放到buf所指的緩衝區中, 返回值爲實際所讀字節數, 返回-1表示出錯。返回0 表示文件結束。 write()函數的調用格式爲: int write(int handle, void *buf, int count); write()函數把count個字節從buf指向的緩衝區寫入與handle相連的文件中, 返回值爲實際寫入的字節數。

3.隨機定位函數 lseek()函數的調用格式爲: int lseek(int handle, long offset, int fromwhere); 該函數對與handle相連的文件位置指針進行定位,功能和用法與fseek()函數相同。 tell()函數的調用格式爲: long tell(int handle); 該函數返回與handle相連的文件現生位置指針, 功能和用法與ftell()相同

5. read 函數和 write 函數

來源:螞蟻的 C/C++ 標準編程 做者:antigloss

1. read #include ssize_t read(int filedes, void *buf, size_t nbytes); 返回值:讀取到的字節數;0(讀到 EOF);-1(出錯) read 函數從 filedes 指定的已打開文件中讀取 nbytes 字節到 buf 中。如下幾種狀況會致使讀取到的字節數小於 nbytes :

A. 讀取普通文件時,讀到文件末尾還不夠 nbytes 字節。例如:若是文件只有 30 字節,而咱們想讀取 100 字節,那麼實際讀到的只有 30 字節,read 函數返回 30 。此時再使用 read 函數做用於這個文件會致使 read 返回 0 。

B. 從終端設備(terminal device)讀取時,通常狀況下每次只能讀取一行。

C. 從網絡讀取時,網絡緩存可能致使讀取的字節數小於 nbytes 字節。

D. 讀取 pipe 或者 FIFO 時,pipe 或 FIFO 裏的字節數可能小於 nbytes 。

E. 從面向記錄(record-oriented)的設備讀取時,某些面向記錄的設備(如磁帶)每次最多隻能返回一個記錄。 F. 在讀取了部分數據時被信號中斷。讀操做始於 cfo 。在成功返回以前,cfo 增長,增量爲實際讀取到的字節數。

2. write #include ssize_t write(int filedes, const void *buf, size_t nbytes); 返回值:寫入文件的字節數(成功);-1(出錯) write 函數向 filedes 中寫入 nbytes 字節數據,數據來源爲 buf 。返回值通常老是等於 nbytes,不然就是出錯了。常見的出錯緣由是磁盤空間滿了或者超過了文件大小限制。 對於普通文件,寫操做始於 cfo 。若是打開文件時使用了 O_APPEND,則每次寫操做都將數據寫入文件末尾。成功寫入後,cfo 增長,增量爲實際寫入的字節數。

 

轉自:http://blog.csdn.net/guo_ya_jie/article/details/52338065

 

  1. 文件和流的關係

      C將每一個文件簡單地做爲順序字節流(以下圖)。每一個文件用文件結束符結束,或者在特定字節數的地方結束,這個特定的字節數能夠存儲在系統維護的管理數據結構中。當打開文件時,就創建了和文件的關係。

      在開始執行程序的時候,將自動打開3個文件和相關的流:標準輸入流、標準輸出流和標準錯誤。流提供了文件和程序的通訊通道。例如,標準輸入流使得程序能夠從鍵盤讀取數據,而標準輸出流使得程序能夠在屏幕上輸出數據。打開一個文件將返回指向FILE結構(在stdio.h中定義)的指針,它包含用於處理文件的信息,也就是說,這個結構包含文件描述符。文件描述符是操做系統數組(打開文件列表的索引)。每一個數組元素包含一個文件控制塊(FCB, File Control Block),操做系統用它來管理特定的文件。

      標準輸入、標準輸出和標準錯誤是用文件指針stdin、stdout和stderr來處理的。

  2. C語言文件操做的底層實現簡介

    2.1 FILE結構體

    C語言的stdio.h頭文件中,定義了用於文件操做的結構體FILE。這樣,咱們經過fopen返回一個文件指針(指向FILE結構體的指針)來進行文件操做。能夠在stdio.h(位於visual studio2010安裝目錄下的include文件夾下)頭文件中查看FILE結構體的定義,以下:

    #ifndef _FILE_DEFINED
    struct _iobuf {
            char *_ptr;
            int   _cnt;
            char *_base;
            int   _flag;
            int   _file;
            int   _charbuf;
            int   _bufsiz;
            char *_tmpfname;
            };
    typedef struct _iobuf FILE;
    
    
    char *_ptr; //文件輸入的下一個位置
    int _cnt; //當前緩衝區的相對位置
    char *_base; //指基礎位置(便是文件的其始位置)
    int _flag; //文件標誌
    int _file; //文件的有效性驗證
    int _charbuf; //檢查緩衝區情況,若是無緩衝區則不讀取
    int _bufsiz; //???這個什麼意思
    char *_tmpfname; //臨時文件名

    2.2 C語言文件管理的實現

    C程序用不一樣的FILE結構管理每一個文件。程序員可使用文件,可是不須要知道FILE結構的細節。實際上,FILE結構是間接地操做系統的文件控制塊
    (FCB)來實現對文件的操做的,以下圖:

    上面圖中的_file其實是一個描述符,做爲進入打開文件表索引的整數。

    2.3 操做系統文件管理簡介

    從圖能夠看出,C語言經過FILE結構能夠間接操做文件控制塊(FCB)。爲了加深對這些的理解,這裏科普下操做系統對打開文件的管理。

    文件是存放在物理磁盤上的,包括文件控制塊(FCB)和數據塊。文件控制塊一般包括文件權限、日期(建立、讀取、修改)、擁有者、文件大小、數據塊信息。數據塊用來存儲實際的內容。對於打開的文件,操做系統是這樣管理的:

    系統維護了兩張表,一張是系統級打開文件表,一張是進程級打開文件表(每一個進程有一個)。

    系統級打開文件表複製了文件控制塊的信息等;進程級打開文件表保存了指向系統級文件表的指針及其餘信息。

    系統級文件表每一項都保存一個計數器,即該文件打開的次數。咱們初次打開一個文件時,系統首先查看該文件是否已在系統級文件表中,若是不在,則建立該項信息,不然,計數器加1。當咱們關閉一個文件時,相應的計數也會減1,當減到0時,系統將系統級文件表中的項刪除。

    進程打開一個文件時,會在進程級文件表中添加一項。每項的信息包括當前文件偏移量(讀寫文件的位置)、存取權限、和一個指向系統級文件表中對應文件項的指針。系統級文件表中的每一項經過文件描述符(一個非負整數)來標識。

    聯繫2.2和2.3上面的內容,能夠發現,應該是這樣的:FILE結構體中的_file成員應該是指向進程級打開文件表,而後,經過進程級打開文件表能夠找到系統級打開文件表,進而能夠經過FCB操做物理磁盤上面的文件。

相關文章
相關標籤/搜索