1. 程式人生 > >常用的C/C++文字檔案的讀寫函式

常用的C/C++文字檔案的讀寫函式

一. 概述

文字檔案的讀寫是演算法研究和工程應用中常見的功能模組。C和C++的標準庫中提供了多種文字檔案的讀寫方法,我們一般都會掌握其中比較習慣使用的一種或幾種方法。解決問題的方法不在多,而在精。經過在網上的資料搜尋和總結,這裡我對實際程式設計中經常用到的幾類方法總結如下。對C和C++分開介紹,目的是讓大家即能用C++讀寫文字檔案,又能用C讀寫文字檔案。不多不少,恰到好處地掌握好該掌握的讀寫知識。
文字檔案內容:後面在程式碼示例中讀入的文字檔案text.txt的內容如下:

Never give up, it's truth.
012  34 

二. C讀寫函式

這裡我們使用簡捷好用的流式檔案操作

,即FILE結構,需要加入標頭檔案fstream.h。可以通過FILE *fopen(const char *filename,const char *mode)開啟檔案流。其中,引數filename指向要開啟的檔名,mode表示開啟狀態的字串,其取值如下:

  • r 以只讀方式開啟檔案
  • rb 以只讀方式開啟二進位制檔案
  • a 以追加(寫)方式開啟檔案
  • w 以只寫方式開啟檔案
  • wb 以只寫方式開啟二進位制檔案
  • r+ 以讀/寫方式開啟檔案,如無檔案出錯
  • w+ 以讀/寫方式開啟檔案,如無檔案生成新檔案

下面通過特別設定的例項對相應的函式進行介紹和說明。

1. 文字檔案

讀操作

函式fscanf的格式控制非常方便,基本上能應對所有的文字檔案讀取任務。有時候為了更便捷,需要使用某些特定功能的函式:
int fseek(FILE *stream, long offset, int whence)
此函式一般用於二進位制模式開啟的檔案中,功能是定位到流中指定的位置。引數offset是移動的字元數,whence是移動的基準可取值為:SEEK_SET 0 檔案開頭;SEEK_CUR 1 當前讀寫的位置;SEEK_END 2 檔案尾部。
char *fgets(char *s, int n, FILE *stream)
此函式表示從流中讀一行或指定個字元(n-1),引數s是來接收字串,如果成功則返回s的指標,否則返回NULL。

string filePath = "text.txt";
FILE *fp = fopen(filePath.c_str(), "r");
if (fp == nullptr)
{
    cout<<"Invalid file path\n";
    return;
}
char str[512];
fscanf(fp, "%s", &str);
int offset = sizeof(char)*9;
fseek(fp, offset, 1);
char str1[512];
int n = 12;
fgets(str1, n+1, fp);
cout<<str1<<endl;
int no, k1, k2;
fscanf(fp, "%d%s%d%d", &no, &str, &k1, &k2);
cout<<no<<" "<<k1<<" "<<k2<<endl; 

寫操作

函式fprintf主要要掌握的就是對於輸出格式的控制,語法規則是百分符號%+代表型別的字母,格式控制就寫在二者之間。

  • %d 整數int型
  • %f 單精度float型
  • %lf 雙進度double型
  • %e 以科學計數法表示
  • %s 字串char[]型

下列程式碼中,%6.2lf表示以6個字元寬度、2位小數的精度輸出;%03d表示以3個字元寬度不足部分以0填充的格式輸出。

string filePath = "text.txt";
FILE *fp = fopen(filePath.c_str(), "a");
if (fp == nullptr)
{
    cout<<"Invalid file path\n";
    return;
}
int a = 91;
fprintf(fp, "C appending %03d\n", a);
double k = 192.3345;
fprintf(fp, "%6.2lf\n", k);
fclose(fp);

2. 二進位制檔案

相比文字檔案而言,二進位制檔案的讀寫不需要考慮輸出格式的相關問題。原因有二,一是二進位制檔案內容是使用者看不懂的二進位制位元組;二是二進位制檔案的讀寫操作都是按位元組個數讀取的,無需顧及格式。所以,寫二進位制檔案的時候千萬不要輸出那些格式控制相關的字元,如\n,那樣徒增資料讀取的難度,百害而無一益。

讀操作

函式fread的原型是size_t fread(void ptr, size_t size, size_t n, FILE *stream),引數ptr是儲存讀取的資料,void的指標可用任何型別的指標來替換,如char*、int *等來替換;size是每塊的位元組數;n是讀取的塊數,如果成功,返回實際讀取的塊數(不是位元組數)。

string filePath = "binary.bin";
FILE *fp = fopen(filePath.c_str(), "rb");
int intSize = sizeof(int);
int charSize = sizeof(char);
char *buffer1 = new char[13];
int *buffer2 = new int[3];
fread(buffer1, charSize, 13, fp);
fread(buffer2, intSize, 3, fp);
cout<<buffer1<<endl;
cout<<buffer2[0]<<" "<<buffer2[1]<<" "<<buffer2[2]<<endl;
fclose(fp);

寫操作

函式fwrite的形參型別與上文提到的函式fread的形參型別一致,此處不再贅述。

string filePath = "binary.bin";
FILE *fp = fopen(filePath.c_str(), "wb");
int intSize = sizeof(int);
int charSize = sizeof(char);
int doubleSize = sizeof(double);
char *buffer1 = "Hello, world!";
int *buffer2 = new int[3];
buffer2[0] = 0; buffer2[1] = 12; buffer2[2] = 34;
double *buffer3 = new double[1];
buffer3[0] = 192.3;
fwrite(buffer1, charSize,  13, fp);
fwrite(buffer2, intSize,    3, fp);
fwrite(buffer3, doubleSize, 1, fp);
fclose(fp);

三. C++讀寫函式

在C++中,對檔案的操作是通過stream的子類fstream來實現的。要用這種方式操作檔案,就必須加入標頭檔案fstream.h。。

1. 文字檔案

讀操作

函式open的原型是*void open(const char filename,int mode,int access)。引數filename:要開啟的檔名;引數mode:要開啟檔案的方式;access:開啟檔案的屬性。開啟檔案的方式在類ios(是所有流式I/O類的基類)中定義,常用的值如下(可以用“|”或者“+”把以下屬性連線起來):

  • ios::in 以只讀方式開啟檔案
  • ios::out 以只寫方式開啟檔案
  • ios::app 以追加(寫)方式開啟檔案
  • ios::_Nocreate 不建立檔案,所以檔案不存在時開啟失敗
  • ios::_Noreplace 不覆蓋檔案,所以開啟檔案時如果檔案存在失敗
  • ios::binary 以二進位制方式開啟檔案

另外,此處程式碼中的函式seekggetline的用法和功能與C讀寫函式中的fseekfgets類似,故略之。

string filePath = "text.txt";
ifstream fin;
fin.open(filePath.c_str(), ios::in);
char str[512];
fin>>str;
int offset = 9;
fin.seekg(offset, ios::cur);
int n = 12;
char str1[512];
fin.getline(str1, n+1);
cout<<str1<<endl;
int no, k1, k2;
fin>>no;
int n = 2;  //! to skip ':' and ' '
fin.seekg(n+1, ios::cur);
fin>>k1>>k2;
cout<<no<<" "<<k1<<" "<<k2<<endl;
fin.close();

寫操作

在C++語法中,文字檔案輸出函式的重點也是對輸出格式的控制。這裡是通過呼叫標準庫中相應的輸出格式設定函式來實現的,呼叫時需要包含標頭檔案iomanip.h。比較常用的格式控制函式有:字元寬度設定函式setw;預設填充字元設定函式setfill;輸出精度設定函式setprecision。具體的用法如下列程式碼中的呼叫方法。

string filePath = "text.txt";
ofstream fout;
fout.open(filePath.c_str(), ios::app | ios::_Nocreate);
char str[512] = "C++ appending ";
fout<<str;
fout<<0<<" : "<<oct<<12<<" "<<dec<<34<<endl;
fout<<setw(3)<<setfill('0')<<91<<" ";
double k = 192.9773;
fout<<setprecision(6)<<k<<endl;
fout.close();

2. 二進位制檔案

在C++中,對二進位制的讀寫是通過函式readwrite來實現。這組函式的用法和功能與C中的函式freadfwrite相一致,這裡不再做過多介紹。值得注意的是,函式的第一個形參型別必須是 unsigned char *,因此當資料的真實型別不是unsigned char時,需要進行型別轉換。

讀操作

string filePath = "binary.bin";
ifstream fin;
fin.open(filePath.c_str(), ios::binary);
int intSize = sizeof(int);
int charSize = sizeof(char);
char *buffer1 = new char[13];
char *buffer2 = new char[3*intSize];
fin.read(buffer1, charSize*13);
fin.read(buffer2, intSize*3);
cout<<buffer1<<endl;
cout<<(int)buffer2[0]<<" "<<(int)buffer2[1]<<endl;
fin.close();

寫操作

string filePath = "binary.bin";
ofstream fout;
fout.open(filePath.c_str(), ios::binary);
int intSize = sizeof(int);
int charSize = sizeof(char);
int doubleSize = sizeof(double);
char *buffer1 = "Hello, world!";
char *buffer2 = new char[3*intSize];
buffer2[0] = 0; buffer2[1] = 12; buffer2[2] = 34;
char *buffer3 = new char[doubleSize*1];
buffer3[0] = 192.3;
fout.write(buffer1, charSize*13);
fout.write(buffer2, intSize*3);
fout.write(buffer3, doubleSize*1);
fout.close();

四. 總結

本文總結了C和C++中常用的讀寫文字檔案和二進位制檔案的函式。目的是為C/C++初學者提供一份簡單實用、詳略得當的關於檔案讀寫的學習資料。當然,要真正掌握其用法,還必須是親身實踐和多次練習,實踐出真知!