C语言再学习 -- 文件
文件是什么
一個文件(file)通常就是磁盤上的一段命名的存儲區。C 將文件看成是連續的字節序列,其中每一個字節都可以單獨地讀取。
二進制和文本模式
1、在windows系統中,文本模式下,文件以"\r\n"代表換行。若以文本模式打開文件,并用fputs等函數寫入換行符"\n"時,函數會自動在"\n"前面加上"\r"。即實際寫入文件的是"\r\n" 。
2、在類Unix/Linux系統中文本模式下,文件以"\n"代表換行。所以Linux系統中在文本模式和二進制模式下并無區別。
標準文件
C 程序自動打開3個文件。這3個文件被稱為標準輸入,標準輸出和標準錯誤輸出。默認的標準輸入是系統的一般輸入設備,通常為鍵盤;默認的標準輸出和標準錯誤輸出是系統的一般輸出設備,通常為顯示器,分別得到文件描述符 0, 1, 2.
下面的方法從標準輸入(鍵盤)獲得一個字符: ?ch = getchar ( );
標準文件指針:
stdio.h文件把3個文件指針與3個C 程序自動打開的標準文件進行了并聯,如下表所示:
| 標準文件 ? | 文件指針 ? | 一般使用的設備 ? |
| 標準輸入 | stdin | 鍵盤 |
| 標準輸出 | stdout | 顯示器 |
| 標準錯誤 | stderr | 顯示器 |
這些指針都是FILE指針類型,所以可以被用作標準I/O函數的參數。
stdout和stderr比較:
stderr -- 標準錯誤輸出設備
stdout -- 標準輸出設備 (printf("..")) 同 stdout。
兩者默認向屏幕輸出。但如果用轉向標準輸出到磁盤文件,則可看出兩者區別。stdout輸出到磁盤文件,stderr在屏幕,例如:
fprintf(stderr, "Can't open it!\n");
fprintf(stdout, "Can't open it!\n");
在my.exe
Can't open it!
Can't open it!
Can't open it!
轉向標準輸出到磁盤文件tmp.txt
my.exe > tmp.txt
Can't open it!
用TYPE 看 tmp.txt的內容:
TYPE tmp.txt
Can't open it!
Can't open it!
stderr是不緩存的,stdout是行間緩存的。請注意:
for(i = 0; i < 10; i++)
? ? {
? ? ? fprintf(stdout, "This is stdout[%d]", i);
? ? ? fprintf(stderr, "This is stderr[%d]", i);
? ? }
會全部顯示stderr之后,再顯示stdout。又因為stdout是行內緩存,所以加 \n 后會立刻顯示。
文件操作分成如下三個步驟:
1、打開文件 (fopen)
2、操作文件 (fread/fwrite)
3、關閉文件 (fclose)
下面來一一介紹:
打開文件 -- fopen ( )函數:
函數原型:
FILE * fopen(const char * path,const char * mode);
返回值:
文件順利打開后,指向該流的文件指針就會被返回。如果文件打開失敗則返回NULL,并把錯誤代碼存在errno中。
一般而言,打開文件后會做一些文件讀取或寫入的動作,若打開文件失敗,接下來的讀寫動作也無法順利進行,所以一般在fopen()后作錯誤判斷及處理。
參數說明:
path:字符串包含欲打開的文件路徑及文件名
mode:C 字符串,包含了文件訪問模式,模式如下:
| 模式字符串 | ? |
| “r” | 以只讀方式打開文件,該文件必須存在 |
| “r+” | 以只讀寫方式打開文件,該文件必須存在 |
| “w” | 打開只寫文件,若文件存在則文件長度清零,即該文件內容會消失。 若文件不存在則建立該文件 |
| “w+” | 打開可讀寫文件,若文件存在則文件長度清零,即該文件內容會消失。 若文件不存在則建立該文件。 |
| “a” | 以附加的方式打開只寫文件。若文件不存在,則會建立該文件,如果文件存在, 寫入的數據會被加到文件尾,即文件原先的內容會被保留。(EOF符保留) |
| “a+” | 以附加方式打開可讀寫的文件。若文件不存在,則會建立文件,如果文件存在, 寫入的數據會被加到文件尾后,即文件原先的內容會被保留。(原來的EOF符不保留) |
| “rb”, “wb”, “ab”, “ab+”, “a+b”, ?“wb+”, “w+b”, “ab+”, “a+b” | 與前面的模式相似,只是使用二進制模式而非文本模式打開文件 |
關閉文件 -- fclose ( )函數:
函數原型:
int fclose( FILE *fp );
返回值:
如果流成功關閉,fclose 返回 0,否則返回EOF(-1)。(如果流為NULL,而且程序可以繼續執行,fclose設定error number給EINVAL,并返回EOF。)
因此,可在fclose(fp)后使用
if(fclose())
{
? ? perror("fclose");
}
來判斷是否成功關閉文件,關閉失敗,則fclose返回“1”并輸出出錯原因。
擴展:C語言再學習 -- EOF與feof函數
[cpp]?view plaincopy
1、在定義文件指針時,要將文件指針指向空;如 FILE *fp = NULL;
2、需要判斷文件是否打開成功,如 if(NULL == fp)
3、文件操作完成后,注意要將文件關閉,否則會造成文件所占用內存泄露和在下次訪問文件時出現問題。
4、文件關閉后,需要將文件指針指向空,這樣做會防止出現游離指針,而對整個工程造成不必要的麻煩;如:fp = NULL;
[cpp]?view plaincopy
操作文件 -- fread ( )函數和fwrite ( )函數
fwrite ( )函數
函數功能:
指向文件寫入一個數據塊。
函數原型:
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
注意:這個函數以二進制形式對文件進行操作,不局限于文本文件
參數:
(1)buffer:是一個指針,對fwrite來說,是要獲取數據的地址;
(2)size:要寫入內容的單字節數;(size_t是sizeof返回的類型,通常是unsigned int類型)
(3)count:要進行寫入size字節的數據項的個數;
(4)stream:目標文件指針;
返回值:
返回實際寫入的數據塊數目 count。
fread ( )函數:
函數原型
size_t fread ( void *buffer, size_t size, size_t count, FILE *stream);
參數:
(1)buffer:用于接收數據的內存地址
(2)size:要讀的每個數據項的字節數,單位是字節?(size_t是sizeof返回的類型,通常是unsigned int類型)
(3)count:要讀count個數據項,每個數據項size個字節.
(4)stream:輸入流
返回值:
返回真實寫入的項數,若大于count則意味著產生了錯誤。另外,產生錯誤后,文件位置指示器是無法確定的。若其他stream或buffer為空指針,或在unicode模式中寫入的字節數為奇數,此函數設置errno為EINVAL以及返回0.
函數功能:
從一個文件流中讀數據,最多讀取count個項,每個項size個字節,如果調用成功返回實際讀取到的項個數(小于或等于count),如果不成功或讀到文件末尾返回 0。
[cpp]?view plaincopy
隨機存取:fseek ( )、ftell ( )、rewind ( )
fseek ( )函數
函數功能:
重定位流(數據流/文件)上的文件內部位置指針
注意:文件指針指向文件/流。位置指針指向文件內部的字節位置,隨著文件的讀取會移動,文件指針如果不重新賦值將不會改變或指向別的文件。
函數原型:
int fseek(FILE *stream, long offset, int fromwhere);
參數:
(1)stream:為文件指針
(2)offset:為偏移量,正數表示正向偏移,負數表示負向偏移(數字值用3L、10L等,L后綴表示long類型)
(3)origin:設定從文件的哪里開始偏移,可能取值為:SEEK_CUR、 SEEK_END 或 SEEK_SET
SEEK_SET: 文件開頭
SEEK_CUR: 當前位置
SEEK_END: 文件結尾
其中SEEK_SET,SEEK_CUR和SEEK_END依次為0,1和2.
返回值:
成功,返回 0,失敗返回 -1,并設置error的值,可以用perror()函數輸出錯誤。
函數描述:
函數設置文件指針stream的位置。如果執行成功,stream將指向以fromwhere(偏移起始位置:文件頭0(SEEK_SET),當前位置1(SEEK_CUR),文件尾2(SEEK_END))為基準,偏移offset(指針偏移量)個字節的位置。如果執行失敗(比如offset超過文件自身大小),則不改變stream指向的位置。
上面這句話意思是,函數執行之后,文件指針就移動到了fromwhere + offset位置處,如果offset超過文件自身大小,則不改變stream指向的位置。
fseek函數和lseek函數類似,但lseek返回的是一個off_t數值,而fseek返回的是一個整型.
#include <stdio.h> int main (void) {char ch = 0;FILE *fp = fopen ("abc.txt", "r");if (fp){//ABCDEFGHIGKLMNfseek (fp, 2L, SEEK_SET); //文件開頭 (ABC)//(2+0 = 2 文件指針移動到2的位置)fread (&ch,sizeof (char), 1, fp);printf ("%c\n", ch);fseek (fp, 3L, SEEK_CUR); //當前位置 (CDEFG)//(3+1 = 4 文件指針移動到4的位置)fread (&ch,sizeof (char), 1, fp); printf ("%c\n", ch);fseek (fp, -3L, SEEK_END); //文件結尾 MN) //(-3+2 = -1 文件指針移動到-1位置)fread (&ch,sizeof (char), 1, fp); printf ("%c\n", ch);fclose (fp); fp = NULL;} return 0; } 輸出結果: C G M
ftell ()函數
函數原型:
long ftell(FILE *stream);
函數功能:
函數 ftell() 用于得到文件位置指針當前位置相對于文件首的偏移字節數。在隨機方式存取文件時,由于文件位置頻繁的前后移動,程序不容易確定文件的當前位置。使用fseek函數后再調用函數ftell()就能非常容易地確定文件的當前位置。
返回值:
以一個long類型值返回一個文件的當前位置。如果發生錯誤,則返回 -1L,全局變量 errno 被設置為一個正值。
調用示例編輯:
ftell(fp);利用函數 ftell() 也能方便地知道一個文件的長。如以下語句序列: fseek(fp, 0L,SEEK_END); len =ftell(fp); 首先將文件的當前位置移到文件的末尾,然后調用函數ftell()獲得當前位置相對于文件首的位移,該位移值等于文件所含字節數。
#include <stdio.h> int main (void) {FILE *fp;int len;//ABCDEFfp = fopen ("abc.txt", "r");if (fp == NULL){perror ("error");return -1;}fseek (fp, 0, SEEK_END);len = ftell (fp);fclose (fp);printf ("abc.txt 的總大小 = %d 字節\n", len);return 0; }輸出結果: abc.txt 的總大小 = 8 字節
rewind ()函數:
函數原型:void rewind(FILE *stream)
返回值:
該函數不返回任何值。
函數功能:?
將文件內部的位置指針重新指向一個流(數據流/文件)的開頭
注意:不是文件指針而是文件內部的位置指針,隨著對文件的讀寫文件的位置指針(指向當前讀寫字節)向后移動。而文件指針是指向整個文件,如果不重新賦值文件指針不會改變。
rewind函數作用等同于 (void)fseek(stream, 0L, SEEK_SET);[1]?
#include <stdio.h>int main() {char str[] = "Hello World!";FILE *fp;int ch;/* 首先讓我們在文件中寫入一些內容 */fp = fopen( "file.txt" , "w" );fwrite(str , 1 , sizeof(str) , fp );fclose(fp);fp = fopen( "file.txt" , "r" );while(1){ch = fgetc(fp);if( feof(fp) ){break ;}printf("%c", ch);}rewind(fp); //從頭從新開始打印printf("\n");while(1){ch = fgetc(fp);if( feof(fp) ){break ;}printf("%c", ch);}printf ("\n");fclose(fp);return(0); } 輸出結果: Hello World! Hello World!
總結
以上是生活随笔為你收集整理的C语言再学习 -- 文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【高并发】——幂等的实现方案
- 下一篇: SpringMVC中使用@Respons