Linux-C 文件操作
Linux-C 文件操作
一、簡述
二、系統I/O
三、標準I/O
四、標準輸入/輸出重定向
五、文件操作補充
六、上述文件操作函數代碼示例
一、簡述
**
基于Linux環境下C語言編程的文件操作。兩種操作文件的方式:1、系統I/O:系統調用接口,`open(), read(), write(), lseek(), close()`。是操作系統直接提供的編程接口(API)。2、標準/IO:標準庫的I/O函數,fopen(), fread(), fwrite(), fseek(), fclose(),是對系統調用接口進一步封裝。系統I/O常用于硬件級別,可以設置讀緩沖區,一般沒有寫緩沖區;標準I/O常用于軟件級別,自帶讀寫緩沖區。1、文件基本概念
C程序把文件分為ASCII文件和二進制文件,ASCII文件又稱文本文件,二進制文件和文本文件(也稱ASCII碼文件)二進制文件中,數值型數據是以二進制形式存儲的,
而在文本文件中,則是將數值型數據的每一位數字作為一個字符以其ASCII碼的形式存儲,因此,文本文件中的每一位數字都單獨占用一個字節的存儲空間,
而二進制文件則是把整個數字作為一個二進制數存儲的,并非數值的每一位數字都占用單獨的存儲空間,無論一個C語言文件的內容是什么,
它一律把數據看成是字節構成的序列,即字節流,對文件的存取也是以字節為單位的,輸入/輸出的的數據流僅受程序控制而不受物理符號(如回車換行符)的控制,所以說C語言文件為流式文件
C語言的文件存取有兩種方式:順序存取和直接存取
(C語言有緩沖型和非緩沖型兩種文件系統,緩沖型文件系統是指系統自動自動在內存中為每一個正在使用的文件開辟一個緩沖區,
作為程序與文件之間數據交換的中間媒介,也就是讀文件時,數據先送到緩沖區,再傳給C語言程序或則外存上,緩沖文件系統利用文件指針標識文件,
而非緩沖文件系統是不會自動設置文件緩沖區,緩沖區必須由程序員自己設定,緩沖型中的文件操作,也稱高級文件操作,
高級文件操作函數大多是ANSIC定義的可移植的文件操作函數,具有跨平臺和可移植能力,可解決大多數文件操作問題)
##二、系統I/O
**2.1 open()函數**功能 打開一個指定的文件并獲得文件描述符,或者創建一個新文件
頭文件 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> 原型int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode); ***參數*** pathname 要打開的文件路徑名稱 **flags** O_RDONLY 只讀方式打開文件 這三個參數互斥 O_WRONLY 只寫方式打開文件 O_RDWR 讀寫方式打開文件 O_CREAT 如果文件不存在,則創建該文件 O_TRUNC 如文件已經存在,則刪除文件中原有數據 O_APPEND 以追加方式打開文件 mode 如果文件被新建,指定其權限為mode(八進制表示法) 返回值 成功 大于等于0 的整數(即文件描述符) 失敗 -1,并且errno會被設置**補充說明:**1)flags 的各種取值可以用位或的方式疊加起來,例如創建文件的時候需要滿足這樣的 選項:讀寫方式打開,不存在要新建,如果存在了則清空。則flags 的取值應該是:O_RDWR | O_CREAT | O_TRUNC。 2)mode 是八進制權限,比如0644,或者0755 等。也可以是使用系統已定義的S_IRWXU 00700 user (file owner) has read, write, and execute permission //用戶可讀寫執行權限S_IRUSR 00400 user has read permission//用戶寫權限S_IWUSR 00200 user has write permission//用戶寫權限S_IXUSR 00100 user has execute permission//用戶執行權限 (更多選項可查詢man手冊:man 2 open)比如新創建的文件權限只需要讀寫權限:S_IRUSR | S_IWUSR **3)文件描述符**其實是一個數組的下標值,在內核中打開的文件是用 file 結構體來表示的,每一個結構體都會有一個 指針來指向它們,這些指針被統一存放在一個叫做 fd_array 的數組當中,而這個數組被存 放在一個叫做 files_struct 的結構體中,該結構體是進程控制塊 task_struct 的重要組成部分。**2.2 close()函數**功能:關閉文件并釋放相應資源頭文件
#include <unistd.h>
原型
int close(int fd);
**參數** fd 要關閉的文件的描述符返回值
成功
0
失敗
-1
頭文件
#include <unistd.h>
原型ssize_t read(int fd, void *buf, size_t count);參數fd
從文件 fd 中讀數據,(fd是某個文件的描述符)
buf 指向存放讀到的數據的緩沖區,(就是放數據的內存首地址)count
想要從文件 fd 中讀取的字節數
返回值
成功
實際讀到的字節數
失敗
-1
補充說明:
ssize_t :是類型重定義,為了跨平臺兼容。比如說long在32位系統可能是4字節,64位系統可能是8字節,嵌入式開發有的只有16位,那么int只有2個字節。但是在編程時往往需要根據類型大小來進行操作數據,例如在64位系統編程時8字節使用long類型,如果移植到32位系統時long只有4字節,那么就需要改動好多個地方,所以重定義一種類型,然后根據實際系統再指定,方便改動移植。例如:重定義ssize類型是8字節的,在32位系統,我可以將long long重定義為ssize類型,如果是64位系統可以定義為long類型,這樣只需改動一處。
**2.4 write()函數**功能將數據寫入指定的文件頭文件
#include <unistd.h>
**原型**ssize_t write(int fd, const void *buf, size_t count);**參數**fd
將數據寫入到文件fd 中 (fd是某個文件的描述符)
count
要寫入的字節數
備注
實際寫入的字節數小于等于 count
頭文件
#include <sys/types.h>
#include <unistd.h>
原型off_t lseek(int fd, off_t offset, int whence); **參數** fd要調整位置偏移量的文件的描述符offset
相對基準點的偏移大小
`
whence:基準點
SEEK_SET:文件開頭處
SEEK_CUR:當前位置
SEEK_END:文件末尾處
返回值 成功 新文件位置偏移量(相對于文件開頭的偏移)失敗 -1備注 可用 file-size= lseek(fd,0,SEEK_END);來測量文件大小示例代碼:#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
int fd;
int wr_ret;
int rd_ret;
unsigned long file_size;
char wr_buf[100] = “hello world”;
char rd_buf[100];
}
**2.5 mmap()函數**功能將物理內存映射為虛擬內存,為了提高效率。(比如將一個文件映射到虛擬內存,以操作內存的方式進行數據的讀寫,但是不會改變文件的大小,一般不用于普通文件) 頭文件#include <sys/mman.h> 原型void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);**參數**addr 從虛擬內存的哪個地址開始去映射這片內存NULL代表由系統決定映射起始地址 length 映射的內存長度(字節為單位) port決定這塊內存的操作權限,以下數值可以相或PROT_EXEC Pages may be executed. 執行權限PROT_READ Pages may be read. 讀權限PROT_WRITE Pages may be written. 寫權限PROT_NONE Pages may not be accessed. 無權限flags 操作標志MAP_SHARED:在多進程中把這塊內存共享給其他進程 MAP_PRIVATE:不共享內存 fd將數據寫入到文件fd 中 (fd是某個文件的描述符) offset基于文件頭偏移多少單位開始映射返回值 成功成功返回映射的虛擬地址 失敗失敗返回MAP_FAILED,其實就是個-1, errno會被設置備注取消映射 int munmap(void *addr, size_t length);addr:映射的起始地址length:取消的長度成功返回0,失敗返回-1更多請查看man手冊:man 2 mmap示例代碼:#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> //mencpy()
int main(void)
{
int fd;
char *map_ptr;
}
**三、標準I/O****3.1 fopen()函數**功能獲取指定文件的文件指針頭文件#include <stdio.h>原型FILE *fopen(const char *path, const char *mode);**參數**path要打開的文件的路徑名稱mode“r” : 以只讀方式打開文件,要求文件必須存在。 “r+” : 以讀寫方式打開文件,要求文件必須存在。“w” : 以只寫方式打開文件,文件如果不存在將會創建新文件,如果存在將會將其內容清空。“w+” : 以讀寫方式打開文件,文件如果不存在將會創建新文件,如果存在將會將其內容清空。“a” : 以只寫方式打開文件,文件如果不存在將會創建新文件,且文件位置偏移量被自動定位到文件末尾(即以追加方式寫數據)。“a+” : 以讀寫方式打開文件,文件如果不存在將會創建新文件,第一次用于寫數據則文件位置偏移量被自動定位到文件末尾(即以追加方式寫數據),如果第一次用于讀數據,文件位置偏移位置會定位到文件開始。返回值成功 文件指針失敗 NULL備注 返回的文件指針是一種指向結構體 FILE{}的指針,文件描述符就被封裝在FILE結構體里面程序一開始默認打開3個文件設備文件描述符(int)文件指針(FILE *)標準輸入設備(鍵盤)0STDIN_FILENOstdin標準輸出設備(屏幕)1STDOUT_FILENOstdout標準出錯設備(屏幕)2STDERR_FILENOstderr**3.2 fclose()函數**功能關閉指定的文件并釋放其資源頭文件#include <stdio.h>原型int fclose(FILE *fp);**參數**fp即將要關閉的文件返回值成功0失敗EOF備注fclose( )不能對一個文件重復關閉**3.3 fread()函數**功能從指定文件讀取若干個數據塊頭文件#include <stdio.h>原型size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);**參數**ptr自定義緩沖區指針,(通俗的說就是要存放 讀取出來的數據 的地方)size 數據塊大小nmemb數據塊個數stream即將被讀取數據的文件指針 返回值成功讀取的數據塊個數,等于 nmemb失敗讀取的數據塊個數,小于 nmemb 或等于 0備注當返回小與 nmemb 時,文件 stream 可能已達末尾,或者遇到錯誤3.4 fwrite()函數功能將若干塊數據寫入指定的文件頭文件#include <sys/ioctl.h>原型size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);**參數**ptr:自定義緩沖區指針(要寫入的數據的首地址)size:數據塊大小nmemb:數據塊個數stream:即將被寫入數據的文件指針返回值成功寫入的數據塊個數,等于 sinmembze失敗寫入的數據塊個數,小于 nmemb 或等于 0備注無3.5 fseek()函數功能設置指定文件的當前位置偏移量頭文件#include <sys/ioctl.h>原型int fseek(FILE *stream, long offset, int whence);**參數**stream:需要設置位置偏移量的文件指針offset:新位置偏移量相對基準點的偏移whence:基準點SEEK_SET:文件開頭處SEEK_CUR:當前位置SEEK_END:文件末尾處返回值成功0失敗-1備注無3.6 ftell()函數功能獲取指定文件的當前位置偏移量頭文件#include <sys/ioctl.h>原型long ftell(FILE *stream);**參數**stream:需要返回當前文件位置偏移量的文件指針返回值成功當前文件位置偏移量失敗-1備注無3.7rewind()函數功能將指定文件的當前位置偏移量設置到文件開頭處頭文件#include <sys/ioctl.h>原型void rewind(FILE *stream);**參數**stream:需要設置位置偏移量的文件指針返回值無備注該函數的功能是將文件 strean 的位置偏移量置位到文件開頭處。簡單例子:#include <stdio.h>
int main(int argc,char* argv[])
{
int wr_ret;
int rd_ret;
FILE *fp;
unsigned long file_size;
char wr_buf[100] = “hello world”;
char rd_buf[100];
}
——————————————— #**四、標準輸入/輸出重定向** 實際上,對于終端設備,系統會自動打開3個標準文件:標準輸入、標準輸出和標準錯誤輸出,相應的,系統定義了3個特別的文件指針常數:stdin、stdout、stderr,分別指向標準輸入、標準輸出和標準錯誤文件,這3個文件都以標準終端設備作為輸入/輸出對象,在默認情況下,標準輸入設備時鍵盤,標注輸出設備是屏幕fprintf()是printf()的文件操作版,二者的差別在于fprintf()多了一個FILE *類型的參數fp,如果為其提供的第1個參數時stdout,那么它就和printf()完全一樣,同理可推廣到fputc()和putchar()等其他函數,例如:putchar(c);和fputc(c,stdout);等價
getchar();和fgetc(stdin);等價
puts(str)和fputs(str,stdout);等價
但函數fgets()與gets()不同,從如下函數原型可知其區別在于fgets()還多了一個參數sizechar *fgets(char *s,int size,FILE *stream);
char *gets(char *s)
;fgets()用其第二個參數size來說明輸入緩沖區的大小,使讀入的字符數不能超過限定緩沖區的大小,從而達到防止緩沖區溢出攻擊的目的,假如已定義一個有32字節的緩沖區buffer[32],那么在下面兩條讀字符串的語句中,后者的安全性更高gets(buffer);
fgets(buffer,sizeof(buffer),stdin);//安全性更高
雖然系統隱含的I/O是指終端設備,但其實標準輸入和標準輸出是可以重新定向的,操作系統可以重新定向它們到其他文件或具有文件屬性的設備,只有標準錯誤輸出不能進行一般的輸出重定向,例如,在沒有顯示器的主機上,把標準輸出定向到打印機,各種程序不用做任何改變,輸出內容就自動從打印機輸出這里用“<”表示輸入重定向,用“>”表示輸出重定向,例如:假設exefile時可執行程序文件名,執行該程序時,需要輸入數據,現在如果要從文件file.in中讀取數據,而非鍵盤輸入,于是exefile的標準輸入就被“<”重定向到了file.in,c此時程序exefile只會專心致志地從文件file.in中讀取數據,而不再理會你此后按下的任何一個按鍵,于是,exefile的標準輸出就被“>”重定向到了文件file.out中,此時程序exefile的所有輸出內容都被輸出到了文件file.out中,而屏幕上沒有任何顯示例:復制代碼1 #include <stdio.h>
2
3 main()
4 {
5 int c;
6
7 scanf_s("%d", &c);
8 printf("%d", c);
9
10 return 0;
11 }
1 FILE *fp;
2 errno_t err;
3 err = fopen(&fp,“E:\ww.txt”,“r”);
1 FILE *fp;
2 fp = fopen(“E:\ww.txt”, “r”);
1 errno_t err;
2 err = fopen_s(&fp, “E:\ww.txt”, “r”);
1 char ss[20];
2 fread(ss, sizeof(char), 4, fp);
1 char ss[20] = “aabb”;
2 fwrite(ss, sizeof(char), 4, fp);
1 char c = ‘a’;
2 fprintf(fp, “%c”, c);
1 fseek(fp, sizeof(char), SEEK_SET);
fgets()函數----fgets(內存首地址, 字符數, 文件指針);1 char ss[20];
2 fgets(ss, 20, fp);
1 char ss[20];
2 ss[0] = fgetc(fp);
3 printf("%c", ss[0]);
1 int c = ‘a’;
2 fputc(c, fp);
也可寫成
fputc(‘c’, fp);
fputs()函數----fputs(字符串, 文件指針)1 char ss[20] = “aaaa”;
2 fputs(ss, fp);
也可寫成
1 fputs(“aaaa”, fp);
總結
以上是生活随笔為你收集整理的Linux-C 文件操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iptv写代理php,苏州电信iptv用
- 下一篇: linux多线程调度设置