linux c文件操作,Linux C 文件的输入/输出操作
10.1 文件I/O操作概述
在Linux系統(tǒng)中,文件I/O操作可以分為兩類,一類是基于文件描述符的I/O操作,另一類是基于數(shù)據(jù)流的I/O操作。
10.1.1 文件描述符簡介
在文件操作一章中,也經(jīng)常提到文件描述符這個概念。所謂文件描述符,就是進程與打開的文件的一個橋梁,通過這個橋梁,才可以在進程中對這個文件進行讀寫等操作。
在Linux環(huán)境下,每打開一個磁盤文件,都會在內(nèi)核中建立一個文件表項,文件表項中存儲著文件的狀態(tài)信息、存儲文件內(nèi)容的緩沖區(qū)和當前文件的讀寫位置。如果同一磁盤文件打開了3次,就會創(chuàng)建3個這樣的文件表項(a,b和c),讀寫文件時,只會改變該文件表項中的文件讀寫位置。這3個文件表項存儲在一個文件表數(shù)組table[3]中,在這里table[0]=a,table[1]=b,table[2]=c。這個文件表的下標就稱之為文件描述符,將這個文件描述符存儲在一個數(shù)組中des[3]={0,1,2},那么,在進程中就可以通過這個des數(shù)組下標引用文件表項。也就是說,通過文件描述符就可以訪問到這個磁盤文件。
10.1.2 數(shù)據(jù)流概述
從數(shù)據(jù)操作方式這個角度來說,Linux系統(tǒng)中的文件(無論是普通文件還是設(shè)備文件)可以看做是數(shù)據(jù)流。對文件進行操作之前,必須先調(diào)用標準I/O庫函數(shù)fopen()將數(shù)據(jù)流打開。打開數(shù)據(jù)流之后,就可以對數(shù)據(jù)流進行輸入和輸出的操作。
標準I/O庫函數(shù)是C語言中所特有的用于高級接口的函數(shù),這些庫函數(shù)存放在C語言的stdio.h頭文件中,因此這些用于數(shù)據(jù)流的I/O操作函數(shù)不僅適用于Linux系統(tǒng),還適用于其他的操作系統(tǒng)。由此可見,此庫函數(shù)的引用大大增加了程序的移植性。
要對數(shù)據(jù)流進行讀寫操作時,需要標準I/O庫函數(shù)和FILE類型的文件指針一起來實現(xiàn)。這個文件指針石達開數(shù)據(jù)流時返回的指針,該指針用來表示要操作的數(shù)據(jù)流。
當執(zhí)行程序時,有3個數(shù)據(jù)流不需要特定的函數(shù)進行打開的操作,他們會自動打開。這3個數(shù)據(jù)流是標準輸入、標準輸出和標準錯誤輸出。他們是自動打開的,當不使用時,也會自動關(guān)閉。
然而,調(diào)用標準I/O庫函數(shù)fopen()打開的數(shù)據(jù)流,在對數(shù)據(jù)流進行操作后,需要調(diào)用fclose()函數(shù)將其關(guān)閉。fclose()函數(shù)在關(guān)閉數(shù)據(jù)流之前,會清空在操作過程中分配的緩沖區(qū)并保存數(shù)據(jù)信息。
10.2 基于文件描述符的I/O操作
10.2.1 文件的打開與關(guān)閉
1)open()函數(shù)
#include
#include
#include
int open(const char *pathname, int flags)
int open(const char *pathname, int flags, mode_t mode)
int creat(const char *pathname, mode_t mode)
上述的兩個open()函數(shù)和一個creat()函數(shù)在調(diào)用成功時,都會返回其新分配的文件描述符;否則返值為-1,并設(shè)置適當?shù)膃rror。
2)close()函數(shù)
#incldue
int close(int fd)
當一個進程終止時,內(nèi)核對該進程的所有尚未關(guān)閉的文件描述符調(diào)用close()函數(shù)關(guān)閉,所以即使用戶程序不調(diào)用close()函數(shù),在終止時內(nèi)核也會自動關(guān)閉它打開的所有文件。但是,對于網(wǎng)絡(luò)服務(wù)器這種一直運行的程序,文件描述符一定要及時關(guān)閉,否則隨著打開的文件越來越多,會占用大量文件描述符和系統(tǒng)資源。
有函數(shù)open()返回的文件描述符一定是該進程尚未使用的最小描述符。由于程序啟動時自動打開標準輸入、標準輸出和標準錯誤輸出,因此文件描述符0,1,2會存在,那么第一次調(diào)用open()函數(shù)打開文件時返回的文件描述符通常會是3,再調(diào)用open()函數(shù)就會返回4.可以利用這一點在標準輸入、標準輸出或標準錯誤輸出上打開一個新文件,是想重定向的功能。例如,首先調(diào)用close()函數(shù)關(guān)閉文件描述符1,然后調(diào)用open()函數(shù)打開一個常規(guī)文件,則一定會返回文件描述符1,這是標準輸出就不再是終端,而是一個常規(guī)文件了,再調(diào)用printf()函數(shù)就不打印到屏幕上,而是寫到這個文件中了。在文件操作一章中講到的dup2()函數(shù)就是另外一種在指定的文件描述符上打開文件的方法。
10.2.2 文件的讀寫操作
1)read()函數(shù)
#include
ssize_t read(int fd, void *buf, size_t count)
2)write()函數(shù)
#include
ssize_t write(int fd, const void *buf, size_t count)
10.2.3 文件的定位
每個文件都記錄著當前讀寫位置,打開文件時讀寫位置是0,表示文件開頭,通常讀寫多少個自己就會將讀寫位置往后移多少個字節(jié)。
以O(shè)_APPEND方式打開文件,每次寫操作都會在文件末尾追加數(shù)據(jù),然后間讀寫位置移動到新的文件末尾。
1)lseek()函數(shù)
lseek()函數(shù)可以移動當前讀寫位置,通常稱為偏移量,該函數(shù)的定義形式如下:
#include
#include
off_t lseek(int fildes, off_t offset, int whence)
10.3 基于數(shù)據(jù)流的I/O操作
10.3.1 文件的打開與關(guān)閉
在操作文件之前要用fopen()函數(shù)打開文件,操作結(jié)束后,要用fclose()函數(shù)關(guān)閉文件。
1)fopen()函數(shù)
#include
FILE *foepn(cosnt char *path, cosnt char *mode)
2)fclose()函數(shù)
#include
int fclose(FILE *fp)
10.3.2 字符輸入/輸出
1)fgetc()函數(shù)
fgetc()函數(shù)從指定的文件中讀一個字節(jié),該函數(shù)的定義形式如下:
#include
int fgetc(FILE *stream)
在程序中,偶爾會遇到getchar()函數(shù),也是用于讀取一個字節(jié),但它是從標準輸入讀一個字節(jié)。在程序中調(diào)用getchar()函數(shù)相當于調(diào)動fgetc(stdin)
在使用fgetc()函數(shù)時需要注意一下幾點:
①調(diào)用fgetc()函數(shù)時,指定的文件的打開方式必須是可讀的。
②函數(shù)fgetc()調(diào)用成功時,返回的是讀到的字節(jié),應(yīng)該為unsigned char,但fgetc()函數(shù)在原型中返回值類型時int,原因在于函數(shù)調(diào)用出錯或讀到文件末尾時fgetc()會返回EOF,即-1,保存在int型的返回值是0xffffffff,如果讀到字節(jié)0xff,由unsigned char型轉(zhuǎn)換int 型時0x000000ff,只有規(guī)定返回值是int型才能把這種情況區(qū)分開,如果規(guī)定返回值是unsigned char型,那么當返回值是0xff時則無法區(qū)分到底是EOF還是字節(jié)0xff。
2)fputc()函數(shù)
#include
int fputc(int c, FILE *stream)
10.3.3 字符串輸入/輸出
1)fgets()函數(shù)
#include
char *fgets(char *s, int size, FILE *stream)
對于fgets()函數(shù)而言,'\n'是一個特別的字符,作為結(jié)束符;而'\0'并無任何特別之處,只用作普通字符串讀入。正因為'\0'作為一個普通的字符串,因此無法判斷緩沖區(qū)中的'\0'究竟是從文件讀上來的字符還是有fgets()函數(shù)自主添加的結(jié)束符,所以fgets()函數(shù)只用于讀文本文件而不提倡讀二進制文件,并且文本文件中的所有字符串不能有'\0'。
2)fputs()
#include
int fputs(const char *s, FILE *stream)
緩沖區(qū)s中保存的是以'\0'結(jié)尾的字符串,fputs()將該字符串寫入文件stream,但并不寫入結(jié)尾的'\0',且字符串中可以有'\n',也可以沒有'\n'。
10.3.4 數(shù)據(jù)塊輸入/輸出
1)fread()和fwrite()函數(shù)
#include
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
10.3.5 格式化輸入/輸出
所謂格式化輸入/輸出,就是按照一定的格式將數(shù)據(jù)進行輸入/輸出操作。在程序中經(jīng)常用到的printf()函數(shù)和scanf()函數(shù)是用于對終端設(shè)備文件的讀寫操作,這兩個函數(shù)被稱為格式化輸入/輸出,因為在使用這兩個函數(shù)時,需要制定讀寫數(shù)據(jù)的數(shù)據(jù)類型并按照一定的格式進行讀寫。
1)格式化輸入函數(shù)
#include
int printf(const char *format,...)
int fprintf(FILE *stream, const char *format)
int sprintf(char *str, size_t size, const char *format,...)
2)格式化輸出函數(shù)
#include
int scanf(const char *format,...)
int fscanf(FILE *stream, const char *format,...)
int sscanf(const char *str, const char *format,...)
10.3.6 操作讀寫位置的函數(shù)
1)fseek()函數(shù)
#inlcude
int fseek(FILE *stream, long offset, int whence)
函數(shù)fseek()的作用是用來移動文件內(nèi)部位置指針。
2)ftell()函數(shù)
#inlcude
long ftell(FILE *stream)
ftell()函數(shù)的作用是得到stream指定的流式文件中的位置。
3)rewind()函數(shù)
void rewind(FILE *stream)
rewind()函數(shù)的作用是使位置指針重新返回文件的開頭,該函數(shù)沒有返回值。
10.3.7 C標準的I/O緩沖區(qū)
C標準庫在調(diào)用fopen()函數(shù)時,都會給此文件分配一個I/O緩沖區(qū),可以加速讀寫操作,原因在于用戶程序需要調(diào)用C標準I/O庫函數(shù)(如fread()、fwrite()等基于文件流I/O操作)讀寫文件,當緩沖區(qū)裝滿后,再由系統(tǒng)調(diào)用的I/O函數(shù)(如read()、write()等基于文件描述符的I/O操作)把讀寫請求傳給內(nèi)核,最終由內(nèi)核驅(qū)動磁盤或設(shè)備完成I/O操作。
由此看來,為文件分配的內(nèi)存緩沖區(qū)大小,直接影響到實際操作外村設(shè)備的次數(shù),內(nèi)存中為未見分配的緩沖區(qū)越大,操作外存的次數(shù)會越小,因此讀寫數(shù)據(jù)的速度會越來越快,效率就會隨之增高。
然而,有時用戶程序等不及將緩沖區(qū)都裝滿之后再傳給內(nèi)核,進行I/O操作,而是希望把I/O緩沖區(qū)中的數(shù)據(jù)立刻傳給內(nèi)核,讓內(nèi)核寫回設(shè)備,這種行為叫做flush操作,對應(yīng)的庫函數(shù)是fflush()。
C標準庫的I/O緩沖區(qū)有全緩沖、行緩沖和無緩沖3種類型。
1)全緩沖:如果緩沖區(qū)寫滿了,就寫回內(nèi)核。普通文件通常是全緩沖的。
2)行緩沖:如果用戶程序?qū)懙臄?shù)據(jù)中有'\n',就把這一行寫回內(nèi)核,或者緩沖區(qū)寫滿后就寫回內(nèi)核。標準輸入和標準輸出對應(yīng)中斷設(shè)備時通常是行緩沖。
3)無緩沖:用戶程序每次調(diào)庫函數(shù)做寫操作都要通過系統(tǒng)調(diào)用寫回內(nèi)核。標準錯誤輸出通常是無緩沖的。這樣用戶程序產(chǎn)生的錯誤信息就可以盡快輸出到設(shè)備。
使用緩沖區(qū)時,會使用到如下兩類操作,一個是設(shè)置緩沖區(qū)屬性,另外一個是清空緩沖區(qū)。
4)設(shè)置緩沖區(qū)屬性
#include
void setbuf(FILE *stream, char *buf)
void setbuffer(FILE *stream, char *buf, size_t size)
void setlinebuf(FILE *stream)
int setvbuf(FILE *stream, char *buf, int mode, size_t size)
setbuf()函數(shù)主要實現(xiàn)了為參數(shù)buf所指定的緩沖區(qū)設(shè)置大小。此函數(shù)中,設(shè)定緩沖區(qū)大小的值只有兩個,一個是常數(shù)BUFSIZ,另一個是NULL。當定義值為BUFSIZ時,代表設(shè)置緩沖區(qū)為全緩沖;若為NULL,則代表設(shè)置緩沖區(qū)為無緩沖形式。
setbuffer()與setbuf()功能相同,只是setbuffer()函數(shù)可以任意指定緩沖區(qū)大小為size
setlinebuf()函數(shù)實現(xiàn)了將stream指向的緩沖區(qū)設(shè)置為行緩沖。
setvbuf()函數(shù)融合了上述3種函數(shù)的功能,既可以設(shè)置緩沖區(qū)的任意大小size,也可以設(shè)置緩沖區(qū)的任意類型,如mode參數(shù)取值為_IOFBF(全緩沖類型)、_IOLBF(行緩沖類型)或_IONBF(無緩沖類型)。
5)清空緩沖區(qū)
#include
int fflush(FILE *stream)
fflush()函數(shù)實現(xiàn)將緩沖區(qū)中的尚未寫入文件的數(shù)據(jù)強制性地寫進stream所指定的文件中,然后清空緩沖區(qū)。如果stream為NULL,此函數(shù)會將所有打開的文件數(shù)據(jù)更新。
10.4 小結(jié)
本章主要介紹了Linux系統(tǒng)下的文件I/O操作。在Linux系統(tǒng)下存在兩種文件I/O操作,一種是基于文件描述符的I/O操作,這里面的I/O操作都是Linux系統(tǒng)中提供并直接作用于內(nèi)核的,是非緩沖的I/O操作;另一種I/O操作是基于數(shù)據(jù)流的I/O操作,是由C語言的stdio庫所提供的,需要在內(nèi)存中開辟一塊緩沖區(qū),在緩沖區(qū)中進行快速地讀寫操作。本章主要結(jié)合典型實例介紹了上述兩種I/O操作方式對文件的打開、關(guān)閉、讀、寫、文件定位等操作。
注:感覺本文10.3.5之前的內(nèi)容對我有用,讓我大概明白了基于數(shù)據(jù)流的文件I/O和基于文件描述符的文件I/O操作之間的區(qū)別。但是如果在給出其中的從操作函數(shù)之后給出一些實例就更好了。
總結(jié)
以上是生活随笔為你收集整理的linux c文件操作,Linux C 文件的输入/输出操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 数组 1 开始,php数组使用1
- 下一篇: linux下常见生产脚本,不看后悔的Li