文件編程內容比較多,如文件系統原理及訪問機制文件在內核中的管理機制,什么是文件信息節點iNode、文件共享、文件權限、各種用戶對其權限等等。以下主要記錄如何用代碼操作文件,實現文件的創建、打開、編輯等自動化執行。
文件描述符介紹、其中標準輸入是從鍵盤獲取輸入寫到0(標準輸入文件),然后標準輸出是將1(標準輸出文件)內容輸出出來,2(標準錯誤)是可以將程序運行過程中的錯誤放到標準錯誤中。文件描述符的作用域就是當前進程,出了這個文件進程就沒有了意義。
文件分為靜態文件和動態文件:
- 文件存放在塊設備(磁盤)的文件系統中的文件中,我們稱之為靜態文件。文件存放在內存中,我們稱之為動態文件。
- 當程序open一個文件時linux內核會做以下操作:首先內核會建立一個打開文件的數據結構(包含文件描述符,節點信息等),記錄我們打開的文件。然后會向內存申請一段內存,并且將靜態文件里面的內容從塊設備讀取到內核中特定地址管理存放。
- 當打開文件后,對文件進行讀寫操作,都是在內存中這一份動態文件進行操作,而不是針對靜態文件。此時修改動態文件的內容,并不會影響靜態文件里面的內容,兩者是不同步的。當close文件時,close內部的內核會將動態文件里面的內容更新到塊設備的靜態文件中。
- 為什么要這樣設計?不直接對塊設備進行操作?
因為塊設備的讀寫速度相對內存慢,是按塊為單位進行操作,不靈活。而內存是按字節為單位進行操作的,而且可以隨機操作,很靈活。
操作系統提供了一系列的API
如Linux系統:
- 打開文件用open函數
- 讀寫文件用write/read函數
- 光標定位用lseek函數
- 關閉用close函數(如果不關閉,會造成文件的損壞)
文件的打開/創建(open函數):
在linux終端要善于使用man手冊,如果想要查找open函數如何使用,可在man手冊中查找(比如:man 2 open即可查找到open函數的用法):
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>
以上三個是使用open函數要包含的頭文件。int open(const char *pathname, int flags);這個函數第一個參數是要打開的文件名(含路徑,缺省為當前路徑)第二個參數Flags是對文件操作的權限1、O_RDONLY:只讀打開2、O_WRONLY:只寫打開3、O_RDWR:可讀可寫打開當我們附帶權限后,開開文件就只能按照這種權限來操作。以上三個權限應當指定一個。下列常量是可選用的的(用的時候要用或操作符):O_CREAT:若文件不存在則創建它,使用此選項時,需要同時說明第三個參數mode,用其說明該新文件的存取許可權限。O_EXCL:如果同時指定了O_CREAT,而文件已經存在則出錯返回值是-1。O_APPEND:每次寫時都加到文件的尾端。如果不加這個常量每次寫的時候就會將源文件內容覆蓋掉一定的字節數(寫入多少字節數就在源文件覆蓋多少字節)如果用或操作加上這個常量,會在原文件另起一行,將東西寫入O_TRUNC:屬性去打開文件時,如果這個文件中本來是有內容的,而且為只讀或只寫成功打開,則將其長度截短為0。 就是將源文件中的所有內容都干掉,就沒有內容了。open函數的返回值是文件描述符(整型數),是相當于對打開的這個文件的一個標記,后面可以用這個文件描述符對文件進行讀寫操作。int open(const char *pathname, int flags, mode_t mode);Mode:一定是在flags中使用了O_CREAT標志,mode記錄待創建文件的訪問權限位。對于 這種形式的open 函數來說,第三個參數僅當創建新文件時才使用,用于指定文件的訪問權限位
大佬博客:open函數、linux中的9個權限位
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd1;int fd2;fd1=open("./locallinuxfile1",O_RDWR);//"./locallinuxfile1"是字符串,而字符串本身就是指針,符合open函數對參數的要求printf("fd1=%d\n",fd1);//當文件存在時返回文件的描述符,不存在時返回-1if(fd1==-1){printf("打開失敗\n");//以下方式可以在文件不存在的時候創建文件//fd2=open("/home/fhn/linuxfiletest/linuxfile3",O_CREAT|O_RDWR,0600); 這個是不在當前路徑創建 fd2=open("./locallinuxfile1",O_CREAT|O_RDWR,0600);//在當前路徑創建文件printf("fd2=%d\n",fd2);if(fd2>0){printf("文件創建成功\n");}}return 0;
}
以上代碼當文件不存在的時候會自動創建文件,文件存在時會直接輸出打開文件的描述符。ls -l命令可查看文件的所有者和文件類型、文件最后修改時間等等
fhn@ubuntu:~/linuxfile$ ls -l
total 16
-rw------- 1 fhn fhn 0 Jun 26 16:54 locallinuxfile1
-rwxrwxr-x 1 fhn fhn 8392 Jun 26 16:54 makeopenfile
-rw-rw-r-- 1 fhn fhn 617 Jun 26 16:54 makeopenfile.c各個符號代表的意思,轉至上面的大佬博客:linux中的9個權限位fd2=open("./locallinuxfile1",O_CREAT|O_RDWR,0600);
這行代碼中的0600是什么意思?
一般地文件操作的權限就試一下幾種:
1、可讀 r 4
2、可寫 w 2
3、可執行 x 1
0600其中的6表示4+2就是可讀可寫的權限
通過ls -l也可以看出rw就是可讀可寫的權限。0600就是給文件所有者對創建文件的權限
6是表示給文件所有者的權限
第二個0表示同組的主用戶
第三個0表示其他組的
大佬博客:Linux文件權限4位數字含義、文件權限數字是什么意思
寫入文件(write函數)
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);第一個參數是文件描述符(就是一個文件的標識符),第二個參數是緩沖區(無指針),第三個參數是要寫入文件的字節數。
這個函數可以簡單理解為:將buf指向的緩沖區中的count個字節寫入到文件中。如果寫入成功返回整形數(寫入文件的字節數),寫入失敗則返回-1。
示例:
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{int fd;int returnbuf;char* name=NULL;name=(char*)malloc(128);printf("請輸入要寫入文件的姓名:\n");scanf("%s",name);fd=open("./loacallinuxfile",O_RDWR|O_CREAT,0600);if(fd==-1){printf("文件打開失敗\n");perror("open");}returnbuf=write(fd,name,strlen(name));//將內容寫入文件close(fd);//關閉文件printf("寫入文件的字節數是:%d\n",returnbuf);//sizeof(name)是計算指針的大小,而不是計算name指向地址的大小//而要計算字符串的長度則用strlen()return 0;
}
read函數:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
第一個參數是文件描述符,第二個參數是緩沖區,第三個參數是要從文件里面讀多少字節到緩沖區中。
read函數讀的時候是從光標向后讀指定的字節數。
示例:
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd;int readbuf;char* buf;buf=(char*)malloc(128);fd=open("./locallinuxfile",O_RDWR|O_CREAT);if(fd==-1){printf("文件打開失敗\n");perror("open");}readbuf=read(fd,buf,4);printf("從文件中讀取的字節是:%s,字節數是:%d\n",buf,readbuf);return 0;
}
lseek函數:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
第一個參數是文件描述符,第二個參數是偏移值,第三個參數是表示偏移量相對于哪個位置進行偏移。
返回值是相對文件頭的偏移量,可以間接的用lseek計算文件的大小,只需將光標指向文件尾部。通常第三個參數有以下幾個宏:
SEEK_SET:指向文件的頭
SEEK_CUR:指向文件的當前位置
SEEK_END:指向文件的尾
lseek(fd,0,SEEK_SET);
lseek(fd,0,SEEK_END);
write、read和lseek綜合使用:
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd;int n_write;int n_read;char* writebuf;char* readbuf;writebuf=(char*)malloc(128);printf("請輸入要寫入的姓名:\n");scanf("%s",writebuf);readbuf=(char*)malloc(strlen(writebuf)+1);fd=open("./locallinuxfile",O_CREAT|O_RDWR,0600);if(fd==-1){printf("文件打開失敗\n");perror("open");}n_write=write(fd,writebuf,strlen(writebuf));if(n_write==-1){printf("文件寫入失敗\n");perror("write");}lseek(fd,-n_write,SEEK_CUR); //read函數讀的時候是從光標向后讀指定的字節數,當寫完后光標在文件最后所以讀不到東西,所以要用lseek函數n_read=read(fd,readbuf,n_write);if(n_read==-1){printf("文件讀取失敗\n");perror("read");}close(fd);printf("文件中寫入了:%s,字節數是:%d\n",writebuf,n_write);printf("從文件中讀取了:%s,字節數是:%d\n",readbuf,n_read);return 0;
}
文件創建函數creat函數:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
第一個參數是要創建的文件名(包含路徑、缺省為當前路徑)
第二個參數是:創建模式 (針對三種用戶設置:所處用戶,所處用戶組,其他用戶權限:讀,寫,執行)//可讀可寫可執行常見的差創建模式:
宏表示 數字
S_IRUSR 4 可讀
S_IWUSR 2 可寫
S_IXUSR 1 可執行
S_IRWXU 7 可讀、寫、執行(也可以用數字代替,如0777)若創建成功返回創建文件的文件描述符,創建失敗返回-1,
demo:
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd;fd=creat("./file",S_IRWXU);if(fd==-1){printf("fail");perror("creat");}return 0;
}