1.檔案的概念
檔案的基本概念
所謂“檔案”是指一組相關資料的有序集合, 這個資料集有一個名稱,叫做檔案名,實際上在前面的各章中我們已經多次使用了檔案,例如源程式檔案、目標檔案、可執行檔案、庫檔案 (頭檔案)等,檔案通常是駐留在外部介質(如磁盤等)上的,在使用時才調入記憶體中來,從不同的角度可對檔案作不同的分類,從用戶的角度看,檔案可分為普通檔案和設備檔案兩種,
普通檔案是指駐留在磁盤或其它外部介質上的一個有序資料集,可以是源檔案、目標檔案、可執行程式; 也可以是一組待輸入處理的原始資料,或者是一組輸出的結果,對于源檔案、目標檔案、 可執行程式可以稱作程式檔案,對輸入輸出資料可稱作資料檔案,
設備檔案是指與主機相聯的各種外部設備,如顯示幕、列印機、鍵盤等,在作業系統中,把外部設備也看作是一個檔案來進行管理,把它們的輸入、輸出等同于對磁盤檔案的讀和寫, 通常把顯示幕定義為標準輸出檔案,一般情況下在螢屏上顯示有關資訊就是向標準輸出檔案輸出,如前面經常使用的printf,putchar 函式就是這類輸出,鍵盤通常被指定標準的輸入檔案, 從鍵盤上輸入就意味著從標準輸入檔案上輸入資料,scanf,getchar函式就屬于這類輸入,
從檔案編碼的方式來看,檔案可分為ASCII碼檔案和二進制碼檔案兩種,
ASCII檔案也稱為文本檔案,這種檔案在磁盤中存放時每個字符對應一個位元組,用于存放對應的ASCII碼,例如,數5678的存盤形式為:
ASC碼: 00110101 00110110 00110111 00111000
↓ ↓ ↓ ↓
十進制碼: 5 6 7 8 共占用4個位元組,ASCII碼檔案可在螢屏上按字符顯示, 例如源程式檔案就是ASCII檔案,用DOS命令TYPE可顯示檔案的內容, 由于是按字符顯示,因此能讀懂檔案內容,
二進制檔案是按二進制的編碼方式來存放檔案的, 例如, 數5678的存盤形式為: 00010110 00101110只占二個位元組,二進制檔案雖然也可在螢屏上顯示,但其內容無法讀懂,C系統在處理這些檔案時,并不區分型別,都看成是字符流,按位元組進行處理,輸入輸出字符流的開始和結束只由程式控制而不受物理符號(如回車符)的控制, 因此也把這種檔案稱作“流式檔案”,
本章討論流式檔案的打開、關閉、讀、寫、定位等各種操作,檔案指標在C語言中用一個指標變數指向一個檔案, 這個指標稱為檔案指標,通過檔案指標就可對它所指的檔案進行各種操作,定義說明檔案指標的一般形式為: FILE* 指標變數識別符號; 其中FILE應為大寫,它實際上是由系統定義的一個結構,該結構中含有檔案名、檔案狀態和檔案當前位置等資訊, 在撰寫源程式時不必關心FILE結構的細節,例如:FILE *fp;表示fp是指向FILE結構的指標變數,通過fp 即可找存放某個檔案資訊的結構變數,然后按結構變數提供的資訊找到該檔案,實施對檔案的操作,習慣上也籠統地把fp稱為指向一個檔案的指標,檔案的打開與關閉檔案在進行讀寫操作之前要先打開,使用完畢要關閉,所謂打開檔案,實際上是建立檔案的各種有關資訊,并使檔案指標指向該檔案,以便進行其它操作,關閉檔案則斷開指標與檔案之間的聯系,也就禁止再對該檔案進行操作,
2.檔案操作函式的介紹
1.fopen
函式原型:
函式說明:
filenmae為檔案名,mode是打開方式,如果以“r"的方式打開,并且此檔案不存在則會出錯,下面我們來看一個例子:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "r");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
fclose(fp);
return 0;
}
此時我們用fopen這個函式來打開text.txt這個檔案,并且是以"r"的形式來打開的,而我并沒有創建這個檔案,所以此次打開是失敗的,我們可以用perror來列印錯誤資訊
運行結果:
如果我們以讀的方式打開,如果打開的檔案不存在它會自動生成,如果打開的檔案存在,則會將檔案里面的內容清空
下面我們來看例子:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "w");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
fclose(fp);
return 0;
}
我們可以發現當運行程式的時候,他會自動生成對應的檔案
如果我此時點進去,并輸入資料進去,并將其保存
當運行完這個程式之后:
我們可以發現里面的資料被清空了
總結:打開檔案的作用:
1)分配給打開檔案一個FILE 型別的檔案結構體變數,并將有關資訊填入檔案結構體變數;
(2)開辟一個緩沖區;
(3)呼叫作業系統提供的打開檔案或建立新檔案功能,打開或建立指定檔案;
FILE *:指出fopen是一個回傳檔案型別的指標函式;回傳值
正常回傳:被打開檔案的檔案指標,
例外回傳:NULL,表示打開操作不成功,
要說明的是:C語言將計算機的輸入輸出設備都看作是檔案,例如,鍵盤檔案、螢屏檔案等,ANSI C標準規定,在執行程式時系統先自動打開鍵盤、螢屏、錯誤三個檔案,這三個檔案的檔案指標分別是:標準輸入stdin、標準輸出stdout和標準出錯 stderr,
fclose():檔案關閉
3.fclose:
1.函式原型:
函式說明:stream
回傳值:0表示正常回傳
例外回傳:EOF,表示檔案關閉失敗;或者關閉時發生錯誤
fgetc()讀取一個字符
1.函式原型:
函式說明:
從fp中讀取一個字符,并作為回傳值回傳
回傳值:
1.正常回傳:
回傳讀取字符的ASSCLL值
2.例外回傳:
讀取失敗,則會回傳EOF.例如:如果我們以寫的形式打開,但是我們使用fgetc()去讀取一個字符時,則會發生錯誤而回傳EOF
例:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "r");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
int ch = fgetc(fp);
printf("%d", ch);
fclose(fp);
fp = NULL;
return 0;
}
運行結果:
注意:之所以會列印-1,這是因為EOF是一個宏,值就是-1;
正常用法:
在這里我先往text.txt中輸入資料
然后在讀取:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "r");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
int ch=fgetc(fp);
printf("%c", ch);
fclose(fp);
fp = NULL;
return 0;
}
運行結果:
重點!!!!fgets()從所有輸入流中讀取字串
1.函式原型:
函式說明:
函式說明:由fp指出的檔案中讀取n-1個字符,并把他們存放到有str指出的字符陣列中區,最后加上一個由字串結束符'\0'
引數說明:str:接受字串的記憶體地址,可以是陣列別名,也可以是指標
n:指出要讀取的字符的個數
fp:這個是檔案指標,指出要從中讀取字符的檔案
回傳值:
正常回傳:字串的記憶體首地址,即str的值
例外回傳:回傳一個NULL值,此時應當用feof()或ferror()函式來判別是讀取到了檔案尾,
2.標準庫中的實作:
/****************************************************
char *fgets(char *s, int n, FILE *stream)
{
register int c;
register char *cs;
cs=s;
while(--n>0 &&(c = getc(stream))!=EOF)
if ((*cs++= c) =='\n')
break;
*cs ='\0';
return (c == EOF && cs == s) ?NULL :s ;
}
/********************************************************
使用注意:
在用fgets(..)讀入資料時,先定義一個字符陣列或字符指標,如果定義了字符指標 ,那么一定要初始化,
char*s;//不可以
char arr[20];//可以
所以如果要使用指標我們可以使用動態記憶體開辟的方式為其分配空間
char *s=(char*)malloc(sizeof(char)*20);
3. fgets()讀取文本行時有兩種情況:
1.當要讀取的個數大于一行字串的長度,那么當讀到末尾\n時,fegets將\n取走之后就停止讀取了,并且在字串s的末尾加上\0
首先在對應檔案中輸入資料,在運行下列程式
代碼:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "r");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
char tmp[20];
fgets(tmp, 12, fp);
printf(tmp);
fclose(fp);
fp = NULL;
return 0;
}
我們可以通過除錯來看是不是這樣的:
我們可以發現末尾的\n被讀走
2.當要讀取的個數小于一行的個數時,此時只會讀取n-1個字符
同樣是上面的代碼我們只改變讀取個數:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "r");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
char tmp[20];
fgets(tmp, 4, fp);
printf(tmp);
fclose(fp);
fp = NULL;
return 0;
}
同樣的我們通過除錯的方法進行驗證:
我們可以發現,我們是想要讀取4個字符但是他只讀取了3個字符,也就是說當我們想要讀取n個字符時,它實際上只會讀取n-1個字符
4.fgets和gets
在一定的情況下可以使用fgets代替gets
fgets(...)從標準設備讀資料,
用fgets(...)還也讀入標準輸入設備(一般為鍵盤)的資訊
原型 : fgets(s,n,stdin);
假設在控制臺下,我們可以用fgets(...)替代gets(),讀入鍵盤輸入的資訊,fgets()是安全的,因為不會像gets()有溢位的可能,,
比如 :輸入 abc
fgets(s,n,stdin)也會讀入n-1個字符,但是只是從stdin流讀入
fgets函式fgets函式用來從檔案中讀入字串,fgets函式的呼叫形式如下:fgets(str,n,fp);此處,fp是檔案指標;str是存放在字串的起始地址;n是一個int型別變數,函式的功能是從fp所指檔案中讀入n-1個字符放入str為起始地址的空間內;如果在未讀滿n-1個字符之時,已讀到一個換行符或一個EOF(檔案結束標志),則結束本次讀操作,讀入的字串中最后包含讀到的換行符,因此,確切地說,呼叫fgets函式時,最多只能讀入n-1個字符,讀入結束后,系統將自動在最后加'\0',并以str作為函式值回傳,
gets()將洗掉新行符, fgets()則保留新行符.
要去掉fgets()最后帶的“\0",只要用 s[strlen(s)-1]='\0';即可,
fgets不會像gets那樣自動地去掉結尾的\n,所以程式中手動將\n位置處的值變為\0,代表輸入的結束,
針對于fgets,還要再說兩句,下面這種用法,是安全的判斷檔案讀取結束或者出錯的好方式,切忌不能使用while(!feof(fp)) ,還有對于fgets的第二個引數是最大能讀取檔案字符的個數,一般最大的長度是1024位元組,
while(fgets(..., stream)){
/* ... */
}
if(ferror(stream)){
/* ... */
}
fputs
1.函式原型:
函式說明;是將字串string,輸出到輸出到檔案或者螢屏上
回傳值:
正常回傳:
寫入到檔案中的個數
例外回傳:
回傳一個NULL,此時應該用feof()或者ferror函式來判斷,是否讀到檔案的末尾,還是發生了錯誤
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "w");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
fputs("hello world", fp);
fclose(fp);
fp = NULL;
return 0;
}
運行之后:
我么可以發現對應的檔案中:
fprintf
1.函式原型
2,函式說明:
2.功能說明
將變數表列(arg_list)中的資料,按照format指出的格式,寫入由fp指定的檔案,fprintf()函式與printf()函式的功能相同,只是printf()函式是將資料寫入螢屏檔案(stdout),
3.引數說明
fp:這是個檔案指標,指出要將資料寫入的檔案,
format:這是個指向字串的字符指標,字串中含有要寫出資料的格式,所以該字串成為格式串,格式串描述的規則與printf()函式中的格式串相同,
arg_list:是要寫入檔案的變數表列,各變數之間用逗號分隔,
例子:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "w");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
int a = 10;
char tmp[] = "abceded";
fprintf(fp, "%d%s", a, tmp);
fclose(fp);
fp = NULL;
return 0;
}
運行結果:
同樣他也能夠像printf一樣輸出到螢屏上
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "w");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
int a = 10;
char tmp[] = "abceded";
fprintf(stdout, "%d %s", a, tmp);
fclose(fp);
fp = NULL;
return 0;
}
運行結果:
fread fwrite
1.函式原型:
2.函式說明:
2. 功能說明
從由fp指定的檔案中,按二進制形式將sife*count個資料讀到由buffer指出的資料區中,
3. 引數說明
buffer:這是一個void型指標,指出要將讀入資料存放在其中的存盤區首地址,
sife:指出一個資料塊的位元組數,即一個資料塊的大小尺寸,
count:指出一次讀入多少個資料塊(sife),
fp:這是個檔案指標,指出要從其中讀出資料的檔案,
4.回傳值
正常回傳:實際讀取資料塊的個數,即count,
例外回傳:如果檔案中剩下的資料塊個數少于引數中count指出的個數,或者發生了錯誤,回傳0值,此時可以用feof()和ferror()來判定到底出現了什么
情況,
H. 以二進制形式寫資料到檔案中去
1. 函式原型
int fwrite(void *buffer,unsigned sife,unsigned count,FILE *fp)
2. 功能說明
按二進制形式,將由buffer指定的資料緩沖區內的sife*count個資料寫入由fp指定的檔案中去,
3. 引數說明
buffer:這是一個void型指標,指出要將其中資料輸出到檔案的緩沖區首地址,
sife:指出一個資料塊的位元組數,即一個資料塊的大小尺寸,
count:一次輸出多少個資料塊(sife),
fp:這是個檔案指標,指出要從其中讀出資料的檔案,
4.回傳值
正常回傳:實際輸出資料塊的個數,即count,
例外回傳:回傳0值,表示輸出結束或發生了錯誤,
例子:
#include<stdio.h>
int main()
{
FILE*fp=fopen("text1.txt", "wb");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
int a = 10;
char tmp[] = "1abceded";
fwrite(tmp, sizeof(tmp), 1, fp);
fclose(fp);
fp = NULL;
return 0;
}
程式運行起來之后打開對應的檔案我們可以發現
我們看不懂此時我們可以使用fread來讀取
#include<stdio.h>
int main()
{
FILE*fp=fopen("text1.txt", "rb");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
char arr[10]={0};
fread(arr,sizeof(char)*9,1,fp);
printf(arr);
fclose(fp);
fp = NULL;
return 0;
}
運行結果:
fseek()
1.函式原型:
2.函式說明:
2) 功能說明
使檔案指標fp移到基于base的相對位置offset處,
(3)引數說明
fp:檔案指標,
offset:相對base的位元組位移量,這是個長整數,用以支持大于64KB的檔案,
base:檔案位置指標移動的基準位置,是計算檔案位置指標位移的基點,ANSI C定義了base的可能取值,以及這些取值的符號常量,
(4)回傳值
正常回傳:當前指標位置,
例外回傳:-1,表示定位操作出錯,
例子:
#include <stdio.h>
#include <string.h>
struct std_type
{
int num;
char name[20];
int age;
char class;
}stud;
int cstufile()
{
int i;
FILE *fp;
if((fp=fopen("stufile","wb"))==NULL)
{
printf("The file can't be opened for write.\n");
return 0;
}
for(i=1;i<=100;i++)
{
stud.num=i;
strcpy(stud.name,"aaaa");
stud.age=17;
stud.class='8';
fwrite(&stud,sizeof(struct std_type),1,fp);
}
fclose(fp);
return 1;
}
void main()
{
int n;
FILE *fp;
if(cstufile()==0) return;
if((fp=fopen("stufile","rb"))==NULL)
{
printf("The file can not be opened.\n");
return;
}
for(n=0;n<100;n+=2)
{
fseek(fp,n*sizeof(struct std_type),SEEK_SET);
fread(&stud,sizeof(struct std_type),1,fp);
printf("%10d%20s%10d%4c\n",stud.num,stud.name,stud.age,stud.class);
}
fclose(fp);
}
補充:
關于exit()函式
1. 函式原型
void exit(int status)
2. 功能說明
exit()函式使程式立即終止執行,同時將緩沖區中剩余的資料輸出并關閉所有已經打開的檔案,
3. 引數說明
status:為0值表示程式正常終止,為非0值表示一個定義錯誤,
4. 回傳值
無,
關于feof()函式
1. 函式原型
int feof(FILE *fp)
2. 功能說明
在文本檔案(ASCII檔案)中可以用值為-1的符號常量EOF來作為檔案的結束符,但是在二進制檔案中-1往往可能是一個有意義的資料,因此不能用它 來作為檔案的結束標志,為了能有效判別檔案是否結束,ANSI C提供了標準函式feof(),用來識別檔案是否結束,
3. 引數說明
fp:檔案指標,
4. 回傳值
回傳為非0值:已到檔案尾,
回傳為0值:表示還未到檔案尾,
fscanf
1.函式原型:fscanf(FILE *fp, const char *format, agars)
2,函式說明:
1.fscanf():
fscanf()函式的頭檔案是<stdio.h>,
函式原型 為 int fscanf(FILE*stream, constchar*format, [argument...]);
其功能為根據資料格式(format)從輸入流(stream)中寫入資料(argument);
【引數】stream為檔案指標,format為格式化字串,argument 為格式化控制符對應的引數,
從檔案指標fp指向的檔案中,按format中對應的控制格式讀取資料,并存盤在agars對應的變數中;
#include<stdio.h>
int main()
{
FILE*fp=fopen("text.txt", "r");
if (fp == NULL)
{
perror("fopen:");
return -1;
}
int a;
double b;
fscanf(fp, "%d %lf", &a, &b);
printf("%d %lf", a, b);
fclose(fp);
fp = NULL;
return 0;
}
檔案:
運行結果:
ssprintf()函式和sscanf()函式的用法
1、ssprinf( )函式的用法
sprintf的作用是將一個格式化的字串輸出到一個目的字串中,而printf是將一個格式化的字串輸出到螢屏,其原型為:
int sprintf(char *str, char * format [, argument, ...]);
sprintf()會根據引數format 字串來轉換并格式化資料,然后將結果復制到引數str 所指的字串陣列,直到出現字串結束('\0')為止,
【回傳值】成功則回傳引數str 字串長度,失敗則回傳-1,
sprintf()最常見的應用之一莫過于把整數列印到字串中,如:
sprintf(s, "%d", 123); //把整數123列印成一個字串保存在s中
sprintf(s, "%8x", 4567); //小寫16進制,寬度占8個位置,右對齊
2、sscanf( )函式的用法
sscanf與scanf類似,都是用于輸入的,只是后者以螢屏(stdin)為輸入源,前者以固定字串為輸入源,
sscanf與scanf類似,都是用于輸入的,只是后者以螢屏(stdin)為輸入源,前者以固定字串為輸入源,
函式原型:
int sscanf( string str, char *format, mixed var1, mixed var2 ... );
eg: sscanf(surBuf, "%[1-9]", dstBuf);
先說下%[]:其基本格式為 %[set],表示將接收一個由set指定格式的字串,其中set表示可接受的字符集合,
set一般有兩種情況:
一種是"^set"表示非, 即在輸入的字串中將匹配所有不在set中出現的字符,遇到set中的字符時停止匹配,
另一種是"set"表示在輸入的字串中將匹配所有在set中出現的字符,遇到非set中的字符時停止匹配,
對比一組函式
| 函式名稱 | 函式功能 | ||
| fscanf | 從所有輸入流中讀取格式化資料 | ||
| scanf | 從標準輸入流中讀取格式化資料 | ||
| sscnaf | 從字串中讀取格式化資料 |
| 函式名稱 | 函式功能 |
| printf | 把格式化資料輸出到螢屏上去 |
| fprintf | 把格式化資料輸出到所有輸出流中 |
| sprintf | 把格式化資料轉成字串 |
請大佬多多指教!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/305249.html
標籤:其他
上一篇:圖論最短路及生成樹(Prim,Djikstra,Spfa,Bellan-ford,kruskal,topsort)


























