欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言文件操作詳解以及詳細步驟

 更新時間:2022年06月17日 09:48:08   作者:zjruiiiiii  
文件(file)一般指存儲在外部介質(zhì)上數(shù)據(jù)的集合,比如我們經(jīng)常使用的.txt,?.bmp,?jpg.?.exe,.rmvb等等,下面這篇文章主要給大家介紹了關(guān)于C語言文件操作的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

一、為什么使用文件?

當(dāng)我們在編寫一個項目的時候,自然而然想到要把之前寫入的數(shù)據(jù)保存起來。而只有我們自己選擇刪除數(shù)據(jù)的時候,數(shù)據(jù)才不復(fù)存在。這就涉及到了數(shù)據(jù)持久化的問題,我們一般數(shù)據(jù)持久化的方法有,把數(shù)據(jù)存放在磁盤文件、存放到數(shù)據(jù)庫等方式。此處我們就講到如何將數(shù)據(jù)放入到磁盤文件當(dāng)中。

二、什么是文件?

磁盤上的文件就是文件。例如電腦當(dāng)中的C盤內(nèi)放入的文件夾內(nèi)的內(nèi)容就是文件。但是在程序設(shè)計中,我們一般談的文件有兩種:程序文件、數(shù)據(jù)文件(從文件功能的角度來分類的)。

1.程序文件

包括源程序文件(后綴為.c),目標文件(windows環(huán)境后綴為.obj),可執(zhí)行程序(windows環(huán)境后綴為.exe)。

2.數(shù)據(jù)文件

文件的內(nèi)容不一定是程序,而是程序運行時讀寫的數(shù)據(jù),比如程序運行需要從中讀取數(shù)據(jù)的文件,或者輸出內(nèi)容的文件。

此篇博客討論的大部分都是數(shù)據(jù)文件。因為我們要學(xué)會如何將文件中的數(shù)據(jù)輸入到內(nèi)存中和如何將程序中的數(shù)據(jù)輸出到文件當(dāng)中。在以前各章所處理數(shù)據(jù)的輸入輸出都是以終端為對象的,即從終端的鍵盤輸入數(shù)據(jù),運行結(jié)果顯示到顯示器上。其實有時候我們會把信息輸出到磁盤上,當(dāng)需要的時候再從磁盤上把數(shù)據(jù)讀取到內(nèi)存中使用,這里處理的就是磁盤上文件。

3.文件名

一個文件要有一個唯一的文件標識,以便用戶識別和引用。

文件名包含3部分:文件路徑+文件名主干+文件后綴

例如: c:\code\test.txt

為了方便起見,文件標識常被稱為文件名

三、文件的打開和關(guān)閉

1.文件指針

緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡稱**“文件指針”**。

每個被使用的文件都在內(nèi)存中開辟了一個相應(yīng)的文件信息區(qū),用來存放文件的相關(guān)信息(如文件的名字,文件狀態(tài)及文件當(dāng)前的位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是有系統(tǒng)聲明的,取名FILE。

例如,VS2013編譯環(huán)境提供的 stdio.h 頭文件中有以下的文件類型申明:

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
       };
typedef struct _iobuf FILE;
FILE* pf;//文件指針變量

不同的C編譯器的FILE類型包含的內(nèi)容不完全相同,但是大同小異。

每當(dāng)打開一個文件的時候,系統(tǒng)會根據(jù)文件的情況自動創(chuàng)建一個FILE結(jié)構(gòu)的變量,并填充其中的信息,使用者不必關(guān)心細節(jié)。
一般都是通過一個FILE的指針來維護這個FILE結(jié)構(gòu)的變量,這樣使用起來更加方便。

下面我們可以創(chuàng)建一個FILE*的指針變量:

FILE* pf;//文件指針變量

定義pf是一個指向FILE類型數(shù)據(jù)的指針變量??梢允筽f指向某個文件的文件信息區(qū)(是一個結(jié)構(gòu)體變量)。通過該文件信息區(qū)中的信息就能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它關(guān)聯(lián)的文件。

2.文件的打開和關(guān)閉

文件在讀寫之前應(yīng)該先打開文件,在使用結(jié)束之后應(yīng)該關(guān)閉文件。

在編寫程序的時候,在打開文件的同時,都會返回一個FILE*的指針變量指向該文件,也相當(dāng)于建立了指針和文件的關(guān)系。

ANSIC 規(guī)定使用fopen函數(shù)來打開文件,fclose來關(guān)閉文件。

要記住的是當(dāng)打開文件后對數(shù)據(jù)進行處理完一定要關(guān)閉文件,否則可能會造成數(shù)據(jù)的丟失。

//打開文件
FILE * fopen ( const char * filename, const char * mode );
//關(guān)閉文件
int fclose ( FILE * stream );

對于文件的寫入和讀取方式,重點掌握以下幾種即可。

文件使用方式含義如果指定文件不存在
“r”(只讀)為了輸入數(shù)據(jù),打開一個已經(jīng)存在的文本文件出錯
“w”(只寫)為了輸出數(shù)據(jù),打開一個文本文件建立一個新的文件
“a”(追加)向文本文件尾添加數(shù)據(jù)建立一個新的文件
“rb”(只讀)為了輸入數(shù)據(jù),打開一個二進制文件出錯
“wb”(只寫)為了輸出數(shù)據(jù),打開一個二進制文件建立一個新的文件

實例代碼:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
  FILE * pFile;
  //打開文件
  pFile = fopen ("myfile.txt","w");//以輸出的形式(寫)打開文件
  //文件操作
  if (pFile!=NULL)
 {
    fputs ("fopen example",pFile);//以字符串的形式寫入
    //關(guān)閉文件
    fclose (pFile);
 }
  return 0; 
}

3.文件的順序讀寫

文件的輸出/寫入就是將數(shù)據(jù)寫入到文件當(dāng)中,而文件的輸入/讀取就是將文件中的內(nèi)容讀取到內(nèi)存當(dāng)中。

以下的對于文件的讀寫方式的函數(shù)均要求掌握

功能函數(shù)名適用于
字符輸入函數(shù)fgetc所有輸入流
字符輸出函數(shù)fputc所有輸出流
文本行輸入函數(shù)fgets所有輸入流
文本行輸出函數(shù)fputs所有輸出流
格式化輸入函數(shù)fscanf所有輸入流
格式化輸出函數(shù)fprintf所有輸出流
二進制輸入fread文件
二進制輸出fwrite文件

四、fseek函數(shù)

根據(jù)文件指針的位置和偏移量來定位文件指針。文件指針顧名思義也是一個指針,它能指向一個字符串中的某個位置。它要接收的參數(shù)有:

第一個參數(shù)是文件指針的名字(流),第二個參數(shù)是文件指針向后偏移數(shù),第三個參數(shù)是fseek函數(shù)中規(guī)定的三個選項之中的其一。

這三項中第一項是SEEK_CUR,即當(dāng)前文件指針的偏移處開始向后偏移。第二項是SEEK_END,即從文件的最末尾處開始向前偏移,當(dāng)然在偏移數(shù)一定要為負數(shù)才能讀取文件中的內(nèi)容。第三項是SEEK_SET,即從文件的最前端處開始向后偏移。舉個例子:

#include <stdio.h>
int main ()
{
  FILE * pFile;
  pFile = fopen ( "example.txt" , "wb" );
  fputs ( "This is an apple." , pFile );
  fseek ( pFile , 9 , SEEK_SET );
  fputs ( " sam" , pFile );
  fclose ( pFile );
  return 0; }

為什么最后在記事本中打印出的結(jié)果是This is a sample.呢?原因是在第一次fputs中是把This is an apple.先放入記事本當(dāng)中,當(dāng)調(diào)用fseek函數(shù)時,從當(dāng)前的文件指針處向后偏移9個字節(jié),文件指針一開始默認指向的是文件的首地址處。因此向后偏移9個字節(jié)后(偏移一個字節(jié)包括空格)指向的是最后一個空格的地址處。而第二次fputs函數(shù)是將“ sam”這個內(nèi)容在上次文件指針指向的地址處開始寫入。因此最后程序運行的結(jié)果如圖:

五、ftell函數(shù)

返回文件指針相對于起始位置的偏移量。

這個函數(shù)比較簡單,輸入的參數(shù)為文件指針流,而返回值的類型為int,即返回的是文件指針所指向的偏移量處。

#include <stdio.h>
int main ()
{
  FILE * pFile;
  long size;
  pFile = fopen ("myfile.txt","rb");
  if (pFile==NULL) perror ("Error opening file");
  else
 {
    fseek (pFile, 0, SEEK_END);   // non-portable
    size=ftell (pFile);
    fclose (pFile);
    printf ("Size of myfile.txt: %ld bytes.\n",size);
 }
  return 0; 
}

因為是從文件內(nèi)容的最末尾處開始相對于起始位置的偏移量。則結(jié)果為17。

代碼運行結(jié)果為:

六、rewind函數(shù)

讓文件指針的位置回到文件的起始位置。

rewind函數(shù)的返回值類型為void型,它所需要的參數(shù)是文件指針流。這個函數(shù)相對來說也比較簡單,我們直接舉例子。

#include <stdio.h>
int main ()
{
  int n;
  FILE * pFile;
  char buffer [27];
  pFile = fopen ("myfile.txt","w+");
  for ( n='A' ; n<='Z' ; n++)
    fputc ( n, pFile);
  rewind (pFile);
  fread (buffer,1,26,pFile);
  fclose (pFile);
  buffer[26]='\0';
  puts (buffer);
  return 0; }

代碼運行結(jié)果:

并且在程序的文件夾中有此內(nèi)容的記事本產(chǎn)生:

七、文本文件和二進制文件

根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件被稱為文本文件或者二進制文件。

數(shù)據(jù)在內(nèi)存中以二進制的形式存儲,如果不加轉(zhuǎn)換的輸出到外存,就是二進制文件。

如果要求在外存上以ASCII碼的形式存儲,則需要在存儲前轉(zhuǎn)換。以ASCII字符的形式存儲的文件就是文本文件。(如整數(shù)10000,需要以ASCII碼輸出到磁盤上,則在磁盤中的存儲形式就是10000)。

如有整數(shù)10000,如果以ASCII碼的形式輸出到磁盤,則磁盤中占用5個字節(jié)(每個字符一個字節(jié)),而二進制形式輸出,則在磁盤上只占4個字節(jié)(VS2013測試)。

再用整數(shù)10000舉例。如果以二進制的形式輸出到磁盤上,則在磁盤上是以二進制的形式存儲。但是我們到文件底下去看二進制形式的文本時,都是亂碼無法看懂(但機器能夠看懂)。此時我們再將該文本文件移到編譯器(VS2019)中。而編譯器內(nèi)有一個二進制編輯器能夠?qū)⒃搧y碼翻譯為二進制數(shù)顯示出來。詳細步驟如下:

代碼:

#include <stdio.h>
int main()
{
 int a = 10000;
 FILE* pf = fopen("test.txt", "wb");
 fwrite(&a, 4, 1, pf);//二進制的形式寫到文件中
 fclose(pf);
 pf = NULL;
 return 0; }

到文件底下去查看文本:

將該文本移到編譯器中后按照以下圖例操作:

此時我們在編譯器中打開該文本:

是什么原因讓10000用二進制的形式存儲變?yōu)榱?0 27 00 00呢?原因是我們先將10000的二進制序列寫出來,為:00000000 00000000 00100111 00010000,每四位則為一個16進制數(shù)字。則結(jié)果為00 00 27 10,但是我們的編譯器是以小端的形式存儲的。即數(shù)據(jù)的低位存儲到內(nèi)存的低地址中,數(shù)據(jù)的高位存儲到高地址中。則存儲的形式就為:10 27 00 00 。

八、文件讀取結(jié)束的判定

1.feof函數(shù)的錯誤使用

在文件讀取過程中,不能用feof函數(shù)的返回值直接用來判斷文件的是否結(jié)束。

而是應(yīng)用于當(dāng)文件讀取結(jié)束的時候,判斷是讀取失敗結(jié)束,還是遇到文件尾結(jié)束。(feof函數(shù)是判斷結(jié)束過程而不是判斷結(jié)束的結(jié)果)

1.文本文件讀取是否結(jié)束,判斷返回值是否為 EOF(getc)或者NULL(fgets)

例如:

fgetc 判斷是否為 EOF .

fgets 判斷返回值是否為 NULL.

2. 二進制文件的讀取結(jié)束判斷,判斷返回值是否小于實際要讀的個數(shù)。

例如:

fread判斷返回值是否小于實際要讀的個數(shù)。

文件文本中正確使用feof函數(shù)的例子:

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int c; // 注意:int,非char,要求處理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 當(dāng)讀取失敗的時候或者遇到文件結(jié)束的時候,都會返回EOF
    while ((c = fgetc(fp)) != EOF) // 標準C I/O讀取文件循環(huán)
   { 
       putchar(c);
   }
 //判斷是什么原因結(jié)束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

二進制文件中正確使用feof函數(shù)的例子:

#include <stdio.h>
enum { SIZE = 5 };
int main(void) {
    double a[SIZE] = {1.,2.,3.,4.,5.};
    FILE *fp = fopen("test.bin", "wb"); // 必須用二進制模式
    fwrite(a, sizeof *a, SIZE, fp); // 寫 double 的數(shù)組
    fclose(fp);
    double b[SIZE];
    fp = fopen("test.bin","rb");
    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 讀 double 的數(shù)組
    if(ret_code == SIZE) {
        puts("Array read successfully, contents: ");
        for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
        putchar('\n');
   } else { // error handling
       if (feof(fp))
          printf("Error reading test.bin: unexpected end of file\n");
       else if (ferror(fp)) {
           perror("Error reading test.bin");
       }
   }
    fclose(fp);
}

九、文件緩沖區(qū)

說到文件緩沖區(qū),我們就自然而然想到輸入緩沖區(qū),即當(dāng)一個字符一個字符從鍵盤上輸入時,并不是直接輸入到磁盤內(nèi),而是先放到輸入緩沖區(qū),而當(dāng)輸入緩沖區(qū)內(nèi)的字符放滿后,文件緩沖區(qū)才向磁盤內(nèi)輸入字符。

文件緩沖區(qū)也是一樣的道理。從內(nèi)存向磁盤輸出數(shù)據(jù)會先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤上。如果從磁盤向計算機讀入數(shù)據(jù),則從磁盤文件中讀取數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再從緩沖區(qū)逐個地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等)。緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定的。

測試代碼:

#include <stdio.h>
#include <windows.h>
//VS2013 WIN10環(huán)境測試
int main()
{
 FILE*pf = fopen("test.txt", "w");
 fputs("abcdef", pf);//先將代碼放在輸出緩沖區(qū)
 printf("睡眠10秒-已經(jīng)寫數(shù)據(jù)了,打開test.txt文件,發(fā)現(xiàn)文件沒有內(nèi)容\n");
 Sleep(10000);
 printf("刷新緩沖區(qū)\n");
 fflush(pf);//刷新緩沖區(qū)時,才將輸出緩沖區(qū)的數(shù)據(jù)寫到文件(磁盤)
 //注:fflush 在高版本的VS上不能使用了
 printf("再睡眠10秒-此時,再次打開test.txt文件,文件有內(nèi)容了\n");
 Sleep(10000);
 fclose(pf);
 //注:fclose在關(guān)閉文件的時候,也會刷新緩沖區(qū)
 pf = NULL;
 return 0; }

我們可以測試一下這個代碼,在程序第一個到fgets函數(shù)處時,立刻去打開test.txt文本文件,我們會發(fā)現(xiàn)里面沒有內(nèi)容,而我們用刷新文件緩沖區(qū)的fflush函數(shù)時再次打開test.txt文本文件時,會發(fā)現(xiàn)里面已經(jīng)有輸入的內(nèi)容。則能夠證實的確有文件緩沖區(qū)的存在。

因為有緩沖區(qū)的存在,C語言在操作文件的時候,需要做刷新緩沖區(qū)或者在文件操作結(jié)束的時候關(guān)閉文件。如果不做,可能導(dǎo)致讀寫文件的問題。

總結(jié)

到此這篇關(guān)于C語言文件操作的文章就介紹到這了,更多相關(guān)C語言文件操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言的數(shù)字游戲算法效率問題探討實例

    C語言的數(shù)字游戲算法效率問題探討實例

    這篇文章主要介紹了C語言的數(shù)字游戲算法效率問題探討實例,需要的朋友可以參考下
    2014-04-04
  • C++重載的奧義之運算符重載詳解

    C++重載的奧義之運算符重載詳解

    函數(shù)的重載是指利用相同的函數(shù)名設(shè)計一系列功能相近,但是功能細節(jié)不一樣的函數(shù)接口;因此運算符重載也是指對于同一個運算符來說,它可以用于實現(xiàn)不同的功能。下面就一起來理解下運算符重載的應(yīng)用吧
    2023-04-04
  • C++如何實現(xiàn)二叉樹鏈表

    C++如何實現(xiàn)二叉樹鏈表

    這篇文章主要介紹了C++如何實現(xiàn)二叉樹鏈表,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 對C語言中遞歸算法的深入解析

    對C語言中遞歸算法的深入解析

    C通過運行時堆棧支持遞歸函數(shù)的實現(xiàn)。遞歸函數(shù)就是直接或間接調(diào)用自身的函數(shù)
    2013-07-07
  • Qt線程QThread開啟和安全退出的實現(xiàn)

    Qt線程QThread開啟和安全退出的實現(xiàn)

    本文主要介紹了Qt線程QThread開啟和安全退出的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • C++string字符串拼接遇到的問題及解決

    C++string字符串拼接遇到的問題及解決

    這篇文章主要介紹了C++string字符串拼接遇到的問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • C++實現(xiàn)簡單FTP客戶端軟件開發(fā)

    C++實現(xiàn)簡單FTP客戶端軟件開發(fā)

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡單FTP客戶端軟件開發(fā),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • OpenCV實現(xiàn)圖像的直線檢測

    OpenCV實現(xiàn)圖像的直線檢測

    這篇文章主要為大家詳細介紹了OpenCV實現(xiàn)圖像直線檢測的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 詳談全排列next_permutation() 函數(shù)的用法(推薦)

    詳談全排列next_permutation() 函數(shù)的用法(推薦)

    下面小編就為大家?guī)硪黄斦勅帕衝ext_permutation() 函數(shù)的用法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • C語言詳細分析結(jié)構(gòu)體的內(nèi)存對齊規(guī)則

    C語言詳細分析結(jié)構(gòu)體的內(nèi)存對齊規(guī)則

    C 數(shù)組允許定義可存儲相同類型數(shù)據(jù)項的變量,結(jié)構(gòu)是 C 編程中另一種用戶自定義的可用的數(shù)據(jù)類型,它允許你存儲不同類型的數(shù)據(jù)項,本篇讓我們來了解C 的結(jié)構(gòu)體內(nèi)存對齊
    2022-07-07

最新評論