C語言中的各種文件讀寫方法小結
前言
找工作的時候,曾經(jīng)用C語言練習過一段時間的算法題目,也在幾個還算出名的OJ平臺有過還算靠譜的排名。之前以為C語言只限于練習一下算法,但是工作中的一個問題解決讓我意識到C語言的用處還是非常廣泛的。下面介紹一下,如果用C語言來操作文件保存一個字符串,和讀取一個字符串。算法中往往都是printf來打印出結果,但是真實工作中往往通過文件來進行一些持久化的存儲工作。
C-File I/O
文件的I/O操作是每一門語言的重點,因此這里我先來介紹一下如何用C語言去進行文件的I/O操作。
文件和流
就C語言程序而言,所有的I/O操作只是簡單地從程序移進或移出字節(jié)的事情。因此,這種字節(jié)流便被稱為流(stream)。程序只需要關心創(chuàng)建正確的輸出字節(jié)數(shù)據(jù),以及正確地解釋從輸入讀取的字節(jié)數(shù)據(jù)。特定I/O設備的細節(jié)對程序員是隱藏的。絕大多數(shù)流是完全緩沖的(fully buffered),這意味著“讀取”和“寫入”實際上是從一塊被稱為緩沖區(qū)(buffer)的內(nèi)存區(qū)域來回復制數(shù)據(jù)。從內(nèi)存中來回復制數(shù)據(jù)是非常快速的。用于輸出流的緩沖區(qū)只有當它寫滿時才會被刷新(flush,物理寫入)到設備或文件中。一次性把寫滿的緩沖區(qū)寫入和逐片把程序產(chǎn)生的輸出分別寫入相比效率更高。輸入緩沖區(qū)也是類似的原理。
流分為兩種類型,分別是文本流和二進制流。
打開流和關閉流
fopen函數(shù)打開一個特定的文件,并把一個流和這個文件相關聯(lián)。它的原型如下所示:
[cpp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
FILE* open(const char* name, const char* mode);
name參數(shù)是你希望打開的文件或設備的名字。mode參數(shù)標識流用于只讀、只寫還是既讀又寫,以及它是文本流還是二進制流。下面表格里列出了一些常用的模式:
如果fopen函數(shù)執(zhí)行成功,它將返回一個指向FILE結構的指針,該結構代表這個新創(chuàng)建的流。如果函數(shù)執(zhí)行失敗,它將返回一個NULL指針,error會提示問題的性質。
流是用函數(shù)fclose關閉的,它的原型如下:
[cpp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
int fclose(FILE *f);
對于輸出流,fclose函數(shù)在文件關閉之前刷新緩沖區(qū)。如果它執(zhí)行成功,fclose返回零值,否則返回EOF。
由于fopen和fclose打開和關閉的都是FILE結構體指針,而在stdio.h頭文件中,包含了對文件結構體FILE的描述。這里介紹一下FILE結構體定義:
struct _iobuf { char *_ptr; // 下一個要被讀取的字符的地址 int _cnr; // 剩余的字符 char *base; // 緩沖區(qū)基地址 int _flag; // 讀寫文件標志位 int _file; // 文件號 int _charbuf; // 檢查緩沖區(qū)的狀況 int _bufsiz; // 文件的大小 char *_tmpfname; // 臨時文件名 }; typedef struct _iobuf FILE;
字符I/O
當一個流被打開之后,它可以用于輸入和輸出。它最簡單的形式是字符I/O。字符輸入是由getchar函數(shù)家族執(zhí)行的,它們的原型如下所示:
int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void);
需要操作的流作為參數(shù)傳遞給getc和fgetc,但是getchar始終是從標準輸入讀取。每個函數(shù)從流中讀取下一個字符,并把它作為函數(shù)的返回值返回。如果流中不存在更多的字符,函數(shù)就返回常量值EOF(-1)。
為了把單個字符寫入到流中,可以使用putchar函數(shù)家族。它的原型如下:
[cpp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
int fputc(int character, FILE* stream); int putc(int character, FILE* stream); int putchar(int character);
行I/O
行I/O其實可以用兩種方式執(zhí)行——未格式化的或者格式化的。這兩種形式都用于操縱字符串。區(qū)別在于未格式化的I/O只是通過fgets和fputs簡單讀取或寫入字符串,而格式化的I/O則執(zhí)行數(shù)字和其他變量的內(nèi)部或外部表示形式之間的轉換。由于日常工作中操作的一般都是格式化I/O,因此這里不講fgets和fputs這種非格式化I/O操作了。(當然,還有一個重要的原因,fgets無法判斷緩沖區(qū)長度,容易導致溢出等情況)
scanf家族
scanf函數(shù)家族的原型如下所示。每個原型中的省略號表示一個可變長度的指針列表。從輸入轉換而來的值逐個存儲到這些指針參數(shù)所指向的內(nèi)存位置。
int fscanf(FILE* stream, const char* format, ...); int scanf(const char* format, ...); int sscanf(const char* string, const char* format, ...);
這些函數(shù)都從輸入源讀取字符并根據(jù)format字符串給出的格式化代碼對它們進行轉換。當格式化字符串到達末尾或者讀取的輸入不再匹配格式字符串所指定的類型時,輸入就停止。在任何一種情況下,被轉換的輸入值的數(shù)目作為函數(shù)的返回值返回。如果在任何輸入值被轉換之前文件就已經(jīng)到達尾部,函數(shù)就返回常量值EOF。
printf家族
printf函數(shù)家族用于創(chuàng)建格式化的輸出。它們的函數(shù)原型如下:
int fprintf(FILE *stream, const char* format, ...); int printf(const char* format, ...); int sprintf(char* buffer, const char* format, ...);
二進制I/O
把數(shù)據(jù)寫到文件里效率最高的方法是用二進制形式寫入,而且Android系統(tǒng)里也有很有用二進制文件通過位來存儲數(shù)據(jù)的應用場景。介紹一下操縱二進制I/O的函數(shù)原型。
fread函數(shù)用于讀取二進制數(shù)據(jù),fwrite函數(shù)用于寫入二進制數(shù)據(jù)。它們的原型如下所示:
[cpp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
size_t fread(void* buffer, size_t size, size_t count, FILE* stream); size_t fwrite(void* buffer, size_t size, size_t count, FILE* stream);
buffer是一個指向用于保存數(shù)據(jù)的內(nèi)存位置的指針,size是緩沖區(qū)中每個元素的字節(jié)數(shù),count是讀取或寫入的元素數(shù),stream是數(shù)據(jù)讀取或寫入的流。
刷新和定位函數(shù)
在處理流時,另外還有一些函數(shù)也較為有用。首先,是fflush,它迫使一個輸出流的緩沖區(qū)內(nèi)的數(shù)據(jù)進行物理寫入,不管它是不是已經(jīng)寫滿。它的原型如下所示:
int fflush(FILE* stream);
當我們需要立即把輸出緩沖區(qū)的數(shù)據(jù)進行物理寫入時,應該使用這個函數(shù)。
在正常的情況下,數(shù)據(jù)以線性的方式寫入,這意味著后面寫入的數(shù)據(jù)在文件中的位置是在以前所有寫入數(shù)據(jù)的后面。C同時支持隨機訪問I/O,也就是以任意順序訪問文件的不同位置。隨機訪問是通過在讀取或寫入前先定位到文件中需要的位置來實現(xiàn)的。一般使用fseek函數(shù)來實現(xiàn),函數(shù)原型如下:
int fseek(FILE* stream, long offset, int from);
fseek函數(shù)允許你在一個流中定位。這個操作將改變下一個讀取或寫入的位置。它的第一個參數(shù)是需要改變的流,它的第二個和第三個參數(shù)標識文件中需要定位的位置。下表描述了fseek參數(shù)的使用方法。
欄 目:C語言
下一篇:詳細分析Android中實現(xiàn)Zygote的源碼
本文標題:C語言中的各種文件讀寫方法小結
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/2932.html
您可能感興趣的文章
- 04-02c語言函數(shù)調用后清空內(nèi)存 c語言調用函數(shù)刪除字符
- 04-02c語言的正則匹配函數(shù) c語言正則表達式函數(shù)庫
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對數(shù)怎么表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段函數(shù)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段函數(shù)
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 04-02c語言調用函數(shù)求fibo C語言調用函數(shù)求階乘


閱讀排行
本欄相關
- 04-02c語言函數(shù)調用后清空內(nèi)存 c語言調用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調用函數(shù)求fibo C語言調用函數(shù)求
隨機閱讀
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實例總結
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 04-02jquery與jsp,用jquery