第十三章 文 件
13.1 C文件概述
文件:文件指存儲在外部介質(zhì)(如磁盤(pán)磁帶)上數據的集合。
操作系統是以文件為單位對數據進(jìn)行管理的。

文件的分類(lèi)
●從用戶(hù)觀(guān)點(diǎn):
特殊文件(標準輸入輸出文件或標準設備文件)。
普通文件(磁盤(pán)文件)。
●從操作系統的角度看,每一個(gè)與主機相連的輸入
輸出設備看作是一個(gè)文件。
例:輸入文件:終端鍵盤(pán)
輸出文件:顯示屏和打印機
(1)根據文件的內容,可分為程序文件和數據文件,程序文件又可分為源文件、目標文件和可執行文件。
(2)根據文件的組織形式,可分為順序存取文件和隨機存取文件。
(3)根據文件的存儲形式,可分為ASCII碼文件和二進(jìn)制文件。
ASCII碼文件的每1個(gè)字節存儲1個(gè)字符,因而便于對字符進(jìn)行逐個(gè)處理。但一般占用存儲空間較多,而且要花費轉換時(shí)間(二進(jìn)制與ASCII碼之間的轉換)。
二進(jìn)制文件是把內存中的數據,原樣輸出到磁盤(pán)文件中??梢怨澥〈鎯臻g和轉換時(shí)間,但1個(gè)字節并不對應1個(gè)字符,不能直接輸出字符形式。
C語(yǔ)言對文件的處理方法:
緩沖文件系統:系統自動(dòng)地在內存區為每一個(gè)正在使用的文件開(kāi)辟一個(gè)緩沖區。用緩沖文件系統進(jìn)行的輸入輸出又稱(chēng)為高級磁盤(pán)輸入輸出。
非緩沖文件系統:系統不自動(dòng)開(kāi)辟確定大小的緩沖區,而由程序為每個(gè)文件設定緩沖區。用非緩沖文件系統進(jìn)行的輸入輸出又稱(chēng)為低級輸入輸出系統。
說(shuō)明:
在UNIX系統下,用緩沖文件系統來(lái)處理文本文件,用非緩沖文件系統來(lái)處理二進(jìn)制文件。
ANSI C 標準只采用緩沖文件系統來(lái)處理文本文件和二進(jìn)制文件。
C語(yǔ)言中對文件的讀寫(xiě)都是用庫函數來(lái)實(shí)現。
13.2 文件類(lèi)型指針
Turbo C在stdio.h文件中有以下的文件類(lèi)型聲明:
typedef struct
{ shortlevel; /*緩沖區“滿(mǎn)”或“空”的程度*/
unsignedflags; /*文件狀態(tài)標志*/
charfd; /*文件描述符*/
unsignedcharhold; /*如無(wú)緩沖區不讀取字符*/
shortbsize; /*緩沖區的大小*/
unsignedchar*buffer;/*數據緩沖區的位置*/
unsignedar*curp;/*指針,當前的指向*/
unsignedistemp;/*臨時(shí)文件,指示器*/
shorttoken;/*用于有效性檢查*/}FILE;
在緩沖文件系統中,每個(gè)被使用的文件都要在內存中開(kāi)辟一
FILE類(lèi)型的區,存放文件的有關(guān)信息。
FILE類(lèi)型的數組:
FILE f[5];定義了一個(gè)結構體數組f,它有5個(gè)元素,可以用來(lái)存放5個(gè)文件的信息。
文件型指針變量:
FILE *fp;fp是一個(gè)指向FILE類(lèi)型結構體的指針變量??梢允?/span>fp指向某一個(gè)文件的結構體變量,從而通過(guò)該結構體變量中的文件信息能夠訪(fǎng)問(wèn)該文件。如果有n個(gè)文件,一般應設n個(gè)指針變量,使它們分別指向n個(gè)文件,以實(shí)現對文件的訪(fǎng)問(wèn)。
13.3 文件的打開(kāi)與關(guān)閉
一.文件的打開(kāi)(fopen函數)
函數調用:
FILE *fp;
fp=fopen(文件名,使用文件方式);
①需要打開(kāi)的文件名,也就是準備訪(fǎng)問(wèn)的文件的名字;
②使用文件的方式(“讀”還是“寫(xiě)”等);
③讓哪一個(gè)指針變量指向被打開(kāi)的文件。

二.文件的關(guān)閉(fclose函數)
函數調用:
fclose(文件指針);
函數功能:
使文件指針變量不指向該文件,也就是文件指針變量與文件“脫鉤”,此后不能再通過(guò)該指針對原來(lái)與其相聯(lián)系的文件進(jìn)行讀寫(xiě)操作。
返回值:
關(guān)閉成功返回值為0;否則返回EOF(-1) 。
13.4 文件的讀寫(xiě)
一、字符輸入輸出函數(fputs()和fgets())
1.fputs函數
函數調用:
fputs ( ch,fp ) ;
函數功能:
將字符(ch的值)輸出到fp所指向的文件中去。
返回值:
如果輸出成功,則返回值就是輸出的字符;
如果輸出失敗,則返回一個(gè)EOF。
2.fgets函數
函數調用:
ch=fgets(fp);
函數功能:
從指定的文件讀入一個(gè)字符,該文件必須是以讀或讀寫(xiě)方式打開(kāi)的。
返回值:
讀取成功一個(gè)字符,賦給ch。
如果遇到文件結束符,返回一個(gè)文件結束標志EOF 。
常見(jiàn)的讀取字符操作
從一個(gè)文本文件順序讀入字符并在屏幕上顯示出來(lái):
ch= fgetc(fp);
while(ch!=EOF)
{
putchar(ch);
ch = fgetc(fp);
}
注意:EOF不是可輸出字符,因此不能在屏幕上顯示。由于字符的ASCII碼不可能出現-1,因此EOF定義為-1是合適的。當讀入的字符值等于-1時(shí),表示讀入的已不是正常的字符而是文件結束符。
常見(jiàn)的讀取字符操作
從一個(gè)二進(jìn)制文件順序讀入字符:
while(!feof(fp))
{
ch = fgetc(fp);
}
注意:ANSI C提供一個(gè)feof()函數來(lái)判斷文件是否真的結束。如果是文件結束,函數feof(fp)的值為1(真);否則為0(假)。以上也適用于文本文件的讀取。
#include<stdlib.h>
#include<stdio.h>
void main(void)
{ FILE*fp;
char ch,filename[10];
scanf("%s",filename);
if((fp=fopen(filename,"w"))==NULL)
{
printf("cannotopen file\n");
exit(0); /*終止程序*/
}
ch=getchar( ); /*接收執行scanf語(yǔ)句時(shí)最后輸入的回車(chē)符 */
ch=getchar( ); /* 接收輸入的第一個(gè)字符 */
while(ch!='#’)
{
fputc(ch,fp);putchar(ch);
ch=getchar();
}
fclose(fp);
}
![]() |
#include <stdlib.h>
#include <stdio.h>
main( )
{
FILE *in,*out;
char ch,infile[10],outfile[10];
printf("Enter theinfile name:\n");
scanf("%s",infile);
printf("Enter theoutfile name:\n");
scanf("%s",outfile);
if((in=fopen(infile,"r"))==NULL)
{
printf("cannot open infile\n");
exit(0);
}
if((out=fopen(outfile,"w"))==NULL)
{
printf("cannot open outfile\n");
exit(0);
}
while(!feof(in))fputc(fgetc(in),out);
close(in);
fclose(out);
}

#include <stdlib.h>
#include <stdio.h>
main(int argc,char *argv[ ])
{
FILE *in,*out;
char ch;
if (argc!=3)
{
printf("You forgot to enter afilename\n");
exit(0);
}
if((in=fopen(argv[1],"rb"))==NULL)
{
printf("cannot open infile\n");
exit(0);
}
if((out=fopen(argv[2],"wb"))==NULL)
{
printf("cannot open outfile\n");
exit(0);
}
while(!feof(in))fputc(fgetc(in),out);
fclose(in);
fclose(out);
}
![]() |
二、數據塊讀寫(xiě)函數(fread()和fwrite())
函數調用:
fread (buffer,size,count,fp);
fwrite(buffer,size,count,fp);
參數說(shuō)明:
buffer:是一個(gè)指針。
對fread 來(lái)說(shuō),它是讀入數據的存放地址。
對fwrite來(lái)說(shuō),是要輸出數據的地址(均指起始地址)。
size: 要讀寫(xiě)的字節數。
count: 要進(jìn)行讀寫(xiě)多少個(gè)size字節的數據項。
fp: 文件型指針。
使用舉例:
若文件以二進(jìn)制形式打開(kāi):
fread(f,4,2,fp);
此函數從fp所指向的文件中讀入2個(gè)4個(gè)字節的數據,存儲到數組f中。
使用舉例:
若有如下結構類(lèi)型:
struct student_type
{
char name[10];
int num;
int age;
char addr[30];}stud[40];
}
可以用fread和fwrite來(lái)進(jìn)行數據的操作:
for(i=0;i<40;i++)
fread(&stud[i],sizeof(structstudent-type),1,fp);
for(i=0;i<40,i++)
fwrite(&stud[i],sizeof(structstudent-type),1,fp);
使用舉例:
例13.3從鍵盤(pán)輸入4個(gè)學(xué)生的有關(guān)數據,然后把它們轉存到磁盤(pán)文件上去。
#include <stdio.h>
#define SIZE 4
struct student_type
{ char name[10];
int num;
int age;
char addr[15];
}stud[SIZE]; /*定義結構*/
void save( )
{
FILE *fp;
int i;
if((fp=fopen("stu-list","wb"))==NULL)
{
printf("cannot openfile\n");
return;
}
for(i=0;i<SIZE;i++)/*二進(jìn)制寫(xiě)*/
if(fwrite(&stud[i],sizeof(structstudent_type),1,fp)!=1)
printf(“file write error\n”);/*出錯處理*/
fclose(fp); } /*關(guān)閉文件*/
main()
{
int i;
for(i=0;i<SIZE;i++)/*從鍵盤(pán)讀入學(xué)生信息*/
scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr);
save( );
}/*調用save()保存學(xué)生信息*/
![]() |
#include <stdio.h>
#define SIZE 4
struct student_type
{ char name[10];
int num;
int age;
char addr[15];
}stud[SIZE];
main( )
{ int i;
FILE*fp;
fp=fopen("stu-list","rb");
for(i=0;i<SIZE;i++)
{
fread(&stud[i],sizeof(struct student_type),1,fp);
printf("%\-10s%4d %4d %\-15s\n",stud[i].name,stud[i].num,stud[i]. age,stud[i].addr);
}
fclose (fp);
}
![]() |
如果已有的數據已經(jīng)以二進(jìn)制形式存儲在一個(gè)磁盤(pán)文件“stu-dat”中,要求從其中讀入數據并輸出到“stu-list”文件中,可以編寫(xiě)一個(gè)load函數,從磁盤(pán)文件中讀二進(jìn)制數據。
void load( )
{
FILE *fp;int i;
if((fp=fopen("stu-dat","rb"))==NULL)
{
printf("cannot open infile\n");
return;
}
for(i=0;i<SIZE;i++)
if(fread(&stud[i],sizeof(structstudent_type),1,fp)!=1)
{
if(feof(fp)) {fclose(fp); return;}
printf("fileread error\n");
}
fclose (fp);
}
三、格式化讀寫(xiě)函數(fprintf()和fscanf())
函數調用:
fprintf ( 文件指針,格式字符串,輸出表列);
fscanf ( 文件指針,格式字符串,輸入表列);
函數功能:
從磁盤(pán)文件中讀入或輸出字符。
例:
fprintf(fp,”%d,%6.2f”,i,t);
Fscanf (fp,”%d,%f”,&i,&t);
注意:
用fprintf和fscanf函數對磁盤(pán)文件讀寫(xiě),使用方便,容易理解,但由于在輸入時(shí)要將ASCII碼轉換為二進(jìn)制形式,在輸出時(shí)又要將二進(jìn)制形式轉換成字符,花費時(shí)間比較多。因此,在內存與磁盤(pán)頻繁交換數據的情況下,最好不用fprintf和fscanf函數,而用fread和fwrite函數。
四、其他讀寫(xiě)函數
putw()和getw()
函數調用:
putw(int i,FILE * fp);
int i = getw(FILE * fp);
函數功能:
對磁盤(pán)文件中讀寫(xiě)一個(gè)字(整數)。
例:
putw(10,fp);
i = getw(fp);
gutw函數定義如下:
gutw(FILE *fp)
{
char s;
s=char *&i;
s[0] = getc(fp);
s[1] = getc(fp);
return i;
}
用戶(hù)自定義讀取其他類(lèi)型數據的函數。
向磁盤(pán)文件寫(xiě)一個(gè)實(shí)數(用二進(jìn)制方式)的函數putfloat :
putfloat(float num,FILE *fp)
{
char *s;
int count;
s =(char*)#
for(count = 0;count< 4;count++)
putc(s[count],fp);
}
fgets函數
函數作用:
從指定文件讀入一個(gè)字符串。
函數調用:
fgets(str,n,fp);
從fp指向的文件輸入n-1個(gè)字符,在最后加一個(gè)’\0’。
返回值:
str的首地址。
fputs函數
函數作用:
向指定的文件輸出一個(gè)字符串。
函數調用:
fgets(“china”,fp);
第一個(gè)參數可以是字符串常量、字符數組名或字符型指針。字符串末尾的′\0′不輸出。
返回值:
輸入成功,返回值為0;
輸入失敗,返回EOF。
13.5 文件的定位
#include<stdio.h>
main()
{ FILE *fp1,*fp2;
fp1=fopen("file1.c","r");
fp2=fopen("file2.c","w");
while(!feof(fp1)) putchar(getc(fp1));
rewind(fp1);
while(!feof(fp1))
putc(getc(fp1),fp2);
fclose(fp1);fclose(fp2);
}
順序讀寫(xiě)和隨機讀寫(xiě)
順序讀寫(xiě):
位置指針按字節位置順序移動(dòng)。
隨機讀寫(xiě):
讀寫(xiě)完上一個(gè)字符(字節)后,并不一定要讀寫(xiě)其后續的字符(字節),而可以讀些文件中任意位置上所需要的字符(字節)。
fseek函數(一般用于二進(jìn)制文件)
函數功能:
改變文件的位置指針。
函數調用形式:
fseek(文件類(lèi)型指針,位移量,起始點(diǎn))
起始點(diǎn):文件開(kāi)頭 SEEK_SET 0
文件當前位置 SEEK_CUR 1
文件末尾 SEEK_END 2
位移量:以起始點(diǎn)為基點(diǎn),向前移動(dòng)的字節數。一般
要求為long型。
fseek函數應用舉例
fseek(fp,100L,0);//將位置指針移到離文件頭100個(gè)字節處。
fseek(fp,50L, 1);//將位置指針移到離當前位置50個(gè)字節處。
fseek(fp,50L, 2);//將位置指針從文件末尾處向后退10個(gè)字節。
#include <stdlib.h>
#include<stdio.h>
struct student_type
{ char name[10];
int num;
int age;
char sex;
}stud[10];
main()
{ int i;
FILE *fp;
if((fp=fopen("stud-dat","rb"))==NULL)
{
printf("can not open file\n");
exit(0);
}
for(i=0;i<10;i+=2)
{
fseek(fp,i*sizeof(struct student_type),0);
fread(&stud[i], sizeof(structstudent_type),1,fp);
printf(“%s %d %d %c\n”,stud[i].name,stud[i].num,stud[i].age,stud[i].sex);
}
fclose(fp);
}
ftell函數
函數作用:
得到流式文件中的當前位置,用相對于文件開(kāi)頭的位移量來(lái)表示。
返回值:
返回當前位置,出錯時(shí)返回-1L。
應用舉例:
i = ftell(fp);
if(i==-1L) printf(“error\n”);
13.6 出錯的檢測
ferror函數
調用形式:
ferror(fp);
返回值:
返回0,表示未出錯;返回非0,表示出錯。
在調用一個(gè)輸入輸出函數后立即檢查ferror函數的值,否則信息會(huì )丟失。在執行fopen函數時(shí),ferror函數的初始值自動(dòng)置為0。
clearerr函數
調用形式:
clearerr(fp);
函數作用:
使文件錯誤標志和文件結束標志置為0。
只要出現錯誤標志,就一直保留,直到對同一文件調用clearerr函數或rewind函數,或任何其他一個(gè)輸入輸出函數。
13.7 文件輸入輸出小結


聯(lián)系客服