官术网_书友最值得收藏!

文件讀寫

通常在比賽中,一道題會有多組測試數據,只有全部測試數據通過,該題才能得滿分。那么試想一下,如果在評測時,每道題都是手工輸入測試數據再手工檢查結果是否正確,那一定是一件讓人崩潰的事情。所以比賽要求選手編寫的代碼必須按要求能自動讀取文件中的測試數據,并將運算結果按指定格式以文件格式保存,評測軟件如Cena等可以自動比較所有選手的提交答案文件和標準答案文件是否相同而給予相應的分數。這種做法極大地提高了工作效率并且保證了結果的準確性。現以一道簡單的比賽仿真題來具體說明。

【例題描述】 求中間數(mid. cpp/c/pas)

對于任意輸入的三個整數中,找出大小順序處于中間的那個數。

【輸入格式】

輸入文件為mid.in,共一行,即三個整數,以空格間隔。

【輸出格式】

輸出文件為mid.out,共一行,即中間數。

【輸入樣例】

    1 2 3

【輸出樣例】

    2

【時間限制】

1秒

這道題表達的意思如下:

對于Pascal選手來說,提交的源程序名為mid.pas,C選手提交的程序名為mid.c,C++選手提交的程序名為mid.cpp。不允許提交可執行文件。

源程序編譯運行時,讀取mid.in文件里的數據,輸出結果需寫到mid.out文件中。每組測試數據必須一秒鐘之內出解。另外要注意的是:一定要嚴格按格式輸出,不允許增減任何字符包括空格,輸出的最后一行一般應以換行符結束。

讀寫文件主要有以下幾種方法,初學者,只要先熟練掌握其中的一兩種方法即可。

方法一(freopen)。

此方法是利用freopen將輸入、輸出重定向到文件中。例如下面的程序從sum.in文件中讀取兩個整數,計算出兩整數之和后輸出到sum.out文件中。

1 //freopen方式讀寫文件
2 #include <iostream>
3 #include <cstdlib>     //此行必加,否則linux下可能出問題
4 using namespace std;
5 int main()
6 {
7  int a,b;
8  freopen("sum.in","r",stdin);   //從sum.in中讀取數據
9  freopen("sum.out","w",stdout); //輸出到sum.out文件
10  cin>>a>>b;
11  cout<<a+b<<endl;
12  //system("pause");一定要將此句注釋掉
13 }

只需加入第8、9行語句,即可很方便地實現讀寫文件數據的功能。源代碼及讀寫文件名需根據題意嚴格定義。

注意:要成功運行該程序,一定要用記事本軟件事先建立一個輸入文件即文件名為“sum.in”的文件放在該程序的同一文件目錄下,否則程序運行時,會因無法找到輸入文件而報錯。此外,sum.in文件里應該有兩個用空格分隔的整數用于程序的讀取和計算。

一定要把system("pause");這句代碼去除,否則輸出文件中會多輸出“請按任意鍵繼續...”這一個字符串而導致評測錯誤。

千萬注意文件名別保存為“sum.in.txt”了。

上例是已知輸入文件中的數據個數,如果在不知道文件中有多少個數據的情況下,如何正確讀取數據并輸出呢?請看下例:

1 //讀取文件到末尾
2 #include <iostream>
3 using namespace std;
4 
5 int a[500000],i,n;
6 int main()
7 {
8  freopen("in.txt","r",stdin);     //從in.txt中讀取數據
9  freopen("out.txt","w",stdout); //輸出到out.txt文件
10  for(i=0;cin>>a[i];i++); //如果讀到文件末,沒數據讀取就退出,注意句末有分號
11 
12  n=i;
13  for(i=0;i<n;i++)
14   cout<<a[i]<<' ';
15  return 0;
16 }

方法二(FILE*):

此方法雖然要比方法一復雜,但該方法不屬于文件重定向語句,且讀取速度快,因此在比賽中推薦使用此方法。

1 //讀寫文件方法2 
2 #include <iostream>
3 #include <cstdlib>
4 int main()
5 {
6   int i,len=0,temp[100];
7   FILE *in=fopen("a.txt","r");      //指針指向輸入文件
8   FILE *out=fopen("b.txt","w"); //輸出文件格式
9   for(i=0;!feof(in);i++) //如未到文件末尾
10   {
11    fscanf(in,"%d",&temp[i]); //讀取文件中的數據
12    len++;
13   }
14   for(i=0;i<len-1;i++)  //寫入文件
15    fprintf(out,"%d ",temp[i]);
16   fclose(in); //關閉文件流
17   fclose(out); //關閉文件流
18 }

FILE的說明:每個被使用的文件都在內存中開辟一個區,用來存放文件的有關信息(如文件的名字、文件狀態及文件當前位置等)。這些信息是保存在一個結構體類型的變量中的。該結構體類型由系統定義,取名為FILE。文件讀寫完畢后需使用fclose函數關閉文件流。

feof函數的說明:feof(in)中in是文件指針。它只有兩個返回值。當遇到文件結束符(EOF)時返回1,否則返回0。所以第9行中!feof(in)的意思是,若feof(in)未遇到EOF,則一直執行for循環。

fprintf函數和fscanf函數的說明:fprintf函數和fscanf函數是格式化讀寫函數,但讀寫對象為文件。

方法三(fstream):

此方法使用了fstream頭文件,推薦C++學習者使用。請看下例:

1 //讀寫文件方法3
2 #include <iostream>
3 #include<fstream>
4 using namespace std;
5 int main()
6 {
7  int a,b,c;
8  ifstream fin("in.txt");
9  ofstream fout("out.txt");
10  fin>>a>>b>>c;
11  fout<<a*b*c<<endl;
12  fin.close();
13  fout.close();
14  return 0;
15 }

方法四(fread函數):

fread函數原型:size_tfread(void*buffer,size_tsize,size_tcount,FILE*in);

(1)buffer:用于接收數據的地址(指針)。

(2)size:單個元素的大小。單位是字節而不是位。

(3)count:元素個數。

(4)in:提供數據的文件指針。

(5)返回值:讀取的元素的個數。

參考程序如下:

1 //fread讀取文件1
2 #include <iostream>
3 #include <stdlib.h>
4 char a[1100000];
5 
6 int main()
7 {
8  FILE *in=fopen("a.in","rb");
9  FILE *out=fopen("a.out","w");
10  int n=fread(a,1,1100000,in);
11  for(int i=0;i<n;i++)
12   fprintf(out,"%c",a[i]);
13  return 0;
14 }

fread()是按照char類型讀取的,因此當讀取的數據類型為數值時,需要再次轉化為數值。參考程序如下:

1 //fread讀取文件2
2 #include <iostream>
3 using namespace std;
4 FILE *in=fopen("i.txt","rb");
5 int mark=0;
6 char a[10];
7 
8 int getnum()            //將char類型轉換為int類型
9 {
10   int obj=0;
11   while(!(a[mark]>='0' && a[mark]<='9'))
12    mark++;
13   while(a[mark]>='0' && a[mark]<='9')
14     obj=obj*10+a[mark++]-'0';
15   return obj;
16 }
17 
18 int main()
19 {
20  freopen("p.txt","w",stdout);  //文件輸出
21  int s=1,i;
22  fread(a,6,1,in);  //第二、三個參數依據數組大小而定,夠用就好
23  for(i=0;i<3;i++)
24   s*=getnum();
25  cout<<s<<endl;
26  return 0;
27 }

需要注意的是,無論何種文件讀寫方法,最后一行萬萬不可寫getchar()或system("pause")之類的語句,因為這類語句是在等待用戶再輸入一個字符。而文件讀寫形式的程序,是不需要暫停的。

四種文件讀寫方法的比較如表3.1所示:

表3.1

讀取10萬個數據(0≤數據≤399)并重新寫入文件的測試比較如表3.2所示(其評測環境為Cena)。

表3.2

主站蜘蛛池模板: 方正县| 余庆县| 绵阳市| 彩票| 双流县| 石台县| 历史| 长沙县| 泰兴市| 和静县| 日照市| 肥乡县| 仪陇县| 临颍县| 云林县| 从化市| 丹凤县| 柘城县| 连平县| 南郑县| 大埔县| 黄梅县| 安岳县| 青河县| 辽宁省| 延寿县| 抚顺市| 平陆县| 金湖县| 焦作市| 环江| 五台县| 西吉县| 木兰县| 霍城县| 乌恰县| 逊克县| 抚顺市| 双柏县| 乐至县| 开化县|