1、在Linux系統中,幾乎一切都是文件。目錄(使用vi目錄名驗證),內存(查看/proc/進程號/maps文件驗證),硬盤(查看/dev文件可驗證)以及其他的各種硬件設備都可以看成文件。比如:文件/dev/tty可以看成鍵盤和顯示器。
2、在標準C中的文件操作:用FILE*代表fopen打開的一個文件;而在UC中用文件描述符(一個非負整數)代表打開一個文件。
3、文件描述符自身不存儲任何文件信息,信息都存在文件表(本身比較龐大)中。文件描述符對應文件表。就像用UID代表進程一樣。
4、在Linux來說,一個進程最多同時打開256個文件,描述符從3開始,0~2的描述符系統佔用,他們分別表示標準輸入,標準輸出和標準錯誤。
5、文件函數:open(),close(),read(),write(),ioctl()。
open() 打開一個文件,返回一個文件描述符
read() 讀一個文件
write() 寫一個文件
close() 關閉一個文件
ioctl() 控制文件的讀寫
6、函數原型int open(const char *pathname, int flags);和int open(const char *pathname, int flags, mode_t mode);創建成功返回文件描述符,失敗返回-1。
第一個參數:文件路徑包括文件名
第二個參數:文件描述符權限標記
flags取值:
O_RDONLY 只讀方式打開 \
O_WRONLY 只寫方式打開 --> 三種權限必選其一
O_RDWR 以可讀可寫方式打開 /
O_APPEND 從文件尾以追加方式打開。
創建標識:
O_CREAT 如果文件存在則打開,文件不存在就創建。
O_EXCL 如果文件文件不存在,創建文件;如果文件存在,返回-1,代表出錯。
O_TRUNC 清空文件內容後打開
多個描述符一起使用要用按位或"|"連接。
第三個參數:只有在創建文件時指定文件權限。該權限是指文件在硬盤上的操作權限(某些權限由於系統出於安全考慮會屏蔽某些權限)。
7、函數原型:ssize_t read(int fd, void *buf, size_t count);也可以爲int read(int fd, void* buf, size_t size);
參數:
fd文件描述符,就是open的返回值
buf是讀文件的首地址,任意類型都可
size是buf的大小(有可能讀不滿)
返回值:正數 真實讀到文件的字節數
0 什麼都沒讀取
-1 出現錯誤
8、函數原型:ssize_t write(int fd, const void *buf, size_t count);也可以爲int write(int fd, void* buf, size_t lenght)
參數:
參數:
fd文件描述符,就是open的返回值
buf是寫文件的首地址,任意類型都可
lenght是真實想要寫入的字節數
返回值:正數 真實寫入文件的字節數
0 什麼都沒寫
-1 出現錯誤
實例:
(1)文件寫入比較:
C語言版:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE * p_file = fopen("a.txt","wb");
if(!p_file){
perror("fopen"),exit(-1);
}
int i = 0;
for(i = 0; i < 100000; i++){
fwrite(&i,sizeof(int),1,p_file);
}
close(p_file);
return 0;
}
UC普通版:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(){
int fd = open("b.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
if(fd == -1){
perror("open"),exit(-1);
}
int i = 0;
for(i = 0; i < 100000; i++){
write(fd,&i,4);
}
close(fd);
return 0;
}
UC優化版:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(){
char buf[100000] = {}; //自定義緩衝區
int fd = open("c.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
if(fd == -1){
perror("open"),exit(-1);
}
int i = 0;
for(i = 0; i < 100000; i++){
buf[i%100000] = i;
if(i%100000 == 99999){
write(fd,buf,sizeof(buf)); //將緩衝區的內容寫入到文件
}
}
close(fd);
return 0;
}
執行時間對比:
原因:所有的標C函數都在用戶層定義了輸入/輸出緩衝區,作用就是累計到了一定數量以後再進入內核讀/寫一次。
所有的UC函數都沒有定義緩衝區,但是可以由程序員自定義緩衝區提升效率,更加靈活。
(2)文件拷貝:
/*
文件拷貝練習
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void){
//打開第一個文件,用於讀取裏面的內容
int fdr = open("1.png",O_RDONLY);
if(-1 == fdr){ //檢測文件打開是否失敗
perror("open1"),exit(-1);
}
//打開第二個文件,用於存儲複製第一個文件的內容
int fdw = open("2.png",O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(-1 == fdw){ //檢測文件打開是否失敗
perror("open2"),exit(-1);
}
char buf[4096] = {};
while(1){
//讀取文件內容
int res = read(fdr,buf,sizeof(buf)); //讀取第一個文件的內容
if(-1 == res){ //判斷是否讀取有誤
perror("read");
break;
}
if(!res){ //判斷是否讀到了文件末尾
break;
}
//寫入文件中
write(fdw,buf,res); //將第一個文件的內容寫到第二個文件中
}
//關閉文件
close(fdr);
close(fdw);
return 0;
}