Linux系統程式設計入門
1.檔案IO
- 標準C庫IO函式:標準C庫IO函式可跨平臺,帶有緩衝區,降低與磁碟的互動次數,提高了效率。在進行磁碟讀寫時,應使用標準C庫的IO函式,但在進行網路通訊時,我們更希望立即把資料發出去,所以使用沒有緩衝區的LiunxIO函式更好。
- 標準C庫IO與Linux系統IO
2.虛擬地址空間
虛擬地址空間通過MMU轉換為實際的實體記憶體空間。
3.檔案描述符
4.open開啟檔案
//開啟一個已經存在檔案
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);、
引數:
- pathname:要開啟的檔案路徑
- flags:對檔案的操作許可權設定以及其它設定
- 必選項:O_RDONLY,O_WRONLY or O_RDWR,這三個設定互斥
- 可選項:O_CREAT等等
返回值:返回一個新的檔案描述符,如果呼叫失敗,會返回-1
errno:屬於Linux系統函式庫,庫裡面的一個全域性變數,記錄的是最近的錯誤號
#include <stdio.h>
void perror(const char *s);
s引數:使用者描述
//測試程式碼
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(){
int fd=open("a.txt",O_RDONLY);
if(fd==-1){
perror("error from open");
}
close(fd);
return 0;
}
5.open建立新檔案
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);
引數:
- pathname:要開啟的檔案路徑
- flags:對檔案的操作許可權設定以及其它設定,32位,每一位都是一個標誌位
- 必選項:O_RDONLY,O_WRONLY or O_RDWR,這三個設定互斥
- 可選項:O_CREAT等等
- mode:八進位制數,表示使用者對建立出的新的檔案的操作許可權,比如0775
函式執行後最終的許可權是:mode & ~unmask
例如:0777 & ~(0002)即111111111 & 111111101
umask的作用就是抹去某些許可權,使許可權更加合理
注意:-rwxrwxr-x,第1位表示檔案型別,後3位表示當前使用者對該檔案的許可權,
再後3位表示當前使用者所在組對該檔案的許可權,最後3位表示其它組使用者對該檔案的許可權
//示例程式碼
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(){
int fd=open("create.txt",O_RDWR|O_CREAT,0777);
if(fd==-1){
perror("error from open");
}
close(fd);
return 0;
}
6.read、write函式
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
引數:
- fd:檔案描述符,open得到,通過這個檔案描述符操作某個檔案
- buf:儲存讀取的資料,陣列的地址(傳出引數)
- count:指定的陣列的大小,以位元組為單位
返回值:
- 成功:大於0,實際讀取的位元組數;等於0,讀取完畢
- 失敗:-1,並設定errno
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
引數:
- fd:檔案描述符,open得到,通過這個檔案描述符操作某個檔案
- buf:需要往磁碟寫入的資料
- count:要寫的資料的實際的大小,以位元組為單位
返回值:
成功:返回實際寫入的位元組數
失敗:返回-1,並設定errno
//示例程式碼
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
// 1.通過open開啟english.txt檔案
int srcfd=open("english.txt",O_RDONLY);
if(srcfd==-1){
perror("open src");
return -1;
}
// 2.建立一個新的檔案(拷貝檔案)
int destfd=open("cpy.txt",O_WRONLY | O_CREAT,0664);
if(destfd==-1){
perror("open dest");
return -1;
}
// 3.頻繁的讀寫操作
char buf[1024]={0};
int len=0;
while((len=read(srcfd,buf,sizeof(buf)))>0){
write(destfd,buf,len);
}
// 4.關閉檔案
close(destfd);
close(srcfd);
return 0;
}
7.lseek函式
標準C庫中的
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
Linux系統函式
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
引數:
- fd:檔案描述符,通過open得到
- offset:偏移量
- whence:
SEEK_SET:設定檔案指標的偏移量
SEEK_CUR:設定偏移量,當前位置+offset
SEEK_END:設定偏移量,檔案大小+offset
返回值:返回檔案指標最終所在的位置
作用:
1.移動檔案指標到檔案頭部
lseek(fd,0,SEEK_SET);
2.獲取當前檔案指標的位置
lseek(fd,0,SEEK_CUR);
3.獲取檔案長度
lseek(fd,0,SEEK_END);
4.擴充檔案的長度,當前檔案10B,擴充為110B
lseek(fd,100,SEEK_END);
需要寫一次資料才會管用
//示例程式
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(){
int fd=open("hello.txt",O_RDWR);
if(fd==-1){
perror("open");
return -1;
}
int ret=lseek(fd,100,SEEK_END);
if(ret==-1){
perror("lseek");
return -1;
}
write(fd," ",1);
close(fd);
return 0;
}
8.stat函式和lstat函式
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
作用:獲取一個檔案的相關資訊
引數:
- pathname:需要操作的檔案的路徑
- statbuf:結構體變數,傳出引數,用於儲存獲取到的檔案的資訊
返回值:成功返回0,失敗返回-1並設定errno
stat結構體具體構成
注意結構體中的st_mode變數
//示例程式
int main(){
struct stat statbuf;
int ret=stat("a.txt",&statbuf);
if(ret==-1){
perror("stat");
return -1;
}
printf("size: %ld\n",statbuf.st_size);
return 0;
}
lstat函式的用法和stat函式幾乎相同,區別在於,lstat函式獲取的是軟連結檔案資訊。
使用下列命令建立一個軟連結檔案b.txt。
$ ln -s a.txt b.txt
這時,如果使用stat函式作用於b.txt,將得到a.txt的檔案資訊,如果使用lstat函式作用於b.txt,將得到b.txt這個軟連結本身的資訊。
9.模擬實現ls -l指令
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>
// 模擬實現 ls -l 指令
// -rw-rw-r-- 1 nowcoder nowcoder 12 12月 3 15:48 a.txt
int main(int argc, char * argv[]) {
// 判斷輸入的引數是否正確
if(argc < 2) {
printf("%s filename\n", argv[0]);
return -1;
}
// 通過stat函式獲取使用者傳入的檔案的資訊
struct stat st;
int ret = stat(argv[1], &st);
if(ret == -1) {
perror("stat");
return -1;
}
// 獲取檔案型別和檔案許可權
char perms[11] = {0}; // 用於儲存檔案型別和檔案許可權的字串
switch(st.st_mode & S_IFMT) {
case S_IFLNK:
perms[0] = 'l';
break;
case S_IFDIR:
perms[0] = 'd';
break;
case S_IFREG:
perms[0] = '-';
break;
case S_IFBLK:
perms[0] = 'b';
break;
case S_IFCHR:
perms[0] = 'c';
break;
case S_IFSOCK:
perms[0] = 's';
break;
case S_IFIFO:
perms[0] = 'p';
break;
default:
perms[0] = '?';
break;
}
// 判斷檔案的訪問許可權
// 檔案所有者
perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
// 檔案所在組
perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
// 其他人
perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
// 硬連線數
int linkNum = st.st_nlink;
// 檔案所有者
char * fileUser = getpwuid(st.st_uid)->pw_name;
// 檔案所在組
char * fileGrp = getgrgid(st.st_gid)->gr_name;
// 檔案大小
long int fileSize = st.st_size;
// 獲取修改的時間
char * time = ctime(&st.st_mtime);
char mtime[512] = {0};
strncpy(mtime, time, strlen(time) - 1);
char buf[1024];
sprintf(buf, "%s %d %s %s %ld %s %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);
printf("%s\n", buf);
return 0;
}
10.access函式
#include <unistd.h>
int access(const char *pathname, int mode);
作用:判斷某個檔案是否有某個許可權,或者判斷檔案是否存在
引數:
- pathname:檔案路徑
- mod:
R_OK(判斷檔案讀許可權)
W_OK(寫許可權)
X_OK(執行許可權)
F_OK(存在)
返回值:成功返回0,失敗返回-1
//示例程式
#include <unistd.h>
#include <stdio.h>
int main(){
int ret=access("a.txt",F_OK);
if(ret==-1){
perror("access");
return -1;
}
printf("檔案存在\n");
return 0;
}
11.chmod函式
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
修改檔案許可權
引數:
- pathname:檔案路徑
- mode:巨集值或八進位制的數
返回值:成功返回0,失敗返回-1
//示例程式
#include <sys/stat.h>
#include <stdio.h>
int main(){
int ret=chmod("a.txt",0777);
if(ret==-1){
perror("chmod");
return -1;
}
return 0;
}
12.chown函式
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
命令列檢視使用者id和使用者組的方式
1.$ id 使用者名稱
2.$ vim /etc/password
3.$ vim /etc/group
13.truncate函式
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
作用:縮減或者擴充套件檔案的尺寸至指定大小
引數:
- path:檔案路徑
- length:需要最終檔案變成的大小
返回值:成功返回0,失敗返回-1
//示例程式
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main(){
int ret=truncate("b.txt",20);
if(ret==-1){
perror("truncate");
return -1;
}
return 0;
}
14.目錄操作函式
小筆記:對於一個目錄,當前使用者必須具有對其的可執行許可權,才能進入該目錄。
mkdir函式
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
作用:建立一個目錄
引數:
- pathname:建立的目錄的路徑
- mode:許可權,巨集值或八進位制數
返回值:成功返回0,失敗返回-1
//示例程式
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
int main(){
int ret=mkdir("aaa",0777);
if(ret==-1){
perror("mkdir");
return -1;
}
return 0;
}
rmdir函式
//只有當目錄中沒有檔案時,才能刪除該目錄
#include <unistd.h>
int rmdir(const char *pathname);
rename函式
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
//示例程式
#include <stdio.h>
int main(){
int ret=rename("aaa","bbb");
if(ret==-1){
perror("rename");
return -1;
}
return 0;
}
chdir函式與getcwd函式
#include <unistd.h>
int chdir(const char *path);
作用:修改程式的工作目錄
引數:
-path:將當前工作路徑修改至path路徑下
#include <unistd.h>
char *getcwd(char *buf, size_t size);
作用:獲取當前工作目錄
引數:
- buf:儲存的路徑,指向一個陣列(傳出引數)
- size:陣列的大小
返回值:返回一個指標,指向的就是傳進去的那個陣列
//示例程式
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(){
//獲取當前工作目錄
char buf[128];
getcwd(buf,sizeof(buf));
printf("當前工作目錄是:%s\n",buf);
//修改工作目錄
int ret=chdir("/home/nowcoder/Linux/lesson13");
if(ret==-1){
perror("chdir");
return -1;
}
//建立一個新的檔案
int fd=open("chdir.txt",O_CREAT | O_RDWR,0664);
if(fd==-1){
perror("open");
return -1;
}
close(fd);
//獲取當前工作目錄
char buf1[128];
getcwd(buf1,sizeof(buf1));
printf("當前工作目錄是:%s\n",buf1);
return 0;
}
15.目錄遍歷函式
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
作用:開啟目錄
引數:
- name:需要開啟的目錄的名稱
返回值:成功返回DIR*型別,理解為目錄流資訊;失敗返回NULL
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
作用:讀取目錄中的資料
引數:
- dirp:是opendir返回的結果
返回值:struct dirent *,代表讀取到的檔案的資訊;讀取到末尾或失敗時,返回NULL
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
//示例程式碼,統計某一目錄下所有普通檔案的個數
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int getFileNum(const char* path);
int main(int argc,char * argv[]){
if(argc<2){
printf("%s path\n",argv[0]);
return -1;
}
int num=getFileNum(argv[1]);
printf("普通檔案的個數為:%d\n",num);
return 0;
}
//用於獲取目錄下所有普通檔案的個數
int getFileNum(const char* path){
//開啟目錄
DIR* dir=opendir(path);
if(dir==NULL){
perror("opendir");
exit(0);
}
//記錄個數
int total=0;
struct dirent *ptr;
while((ptr=readdir(dir))!=NULL){
//獲取名稱
char* dname=ptr->d_name;
//忽略掉.和..
if(strcmp(dname,".")==0 || strcmp(dname,"..")==0){
continue;
}
//判斷是否是普通檔案
if(ptr->d_type==DT_DIR){
//是目錄,需要繼續讀取這個目錄
char newpath[256];
sprintf(newpath,"%s/%s",path,dname);
total+=getFileNum(newpath);
}
if(ptr->d_type==DT_REG){
//普通檔案
total++;
}
}
//關閉目錄
closedir(dir);
return total;
}
16.dup與dup2
dup函式
#include <unistd.h>
int dup(int oldfd);
作用:The dup() system call creates a copy of the
file descriptor oldfd, using the lowest-numbered
unused file descriptor for the new descriptor.
返回值:成功返回新的檔案描述符,失敗返回-1
//示例程式
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main(){
int fd=open("a.txt",O_RDWR | O_CREAT,0664);
int fd1=dup(fd);
if(fd1==-1){
perror("dup");
return -1;
}
printf("fd : %d , fd1 : %d\n",fd,fd1);
close(fd);
char * str="hello,world";
int ret=write(fd1,str,strlen(str));
if(ret==-1){
perror("write");
return -1;
}
close(fd1);
return 0;
}
dup2函式
#include <unistd.h>
int dup2(int oldfd, int newfd);
作用:重定向檔案描述符
例如:oldfd指向a.txt,newfd指向b.txt
呼叫函式成功後:newfd對b.txt做close,newfd指向了a.txt
oldfd必須是一個有效的檔案描述符
若oldfd和newfd值相同,相當於什麼都沒有做
返回值:與newfd值相同
//示例程式
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(){
int fd=open("1.txt",O_RDWR | O_CREAT,0664);
if(fd==-1){
perror("open");
return -1;
}
int fd1=open("2.txt",O_RDWR | O_CREAT,0664);
if(fd1==-1){
perror("open");
return -1;
}
printf("fd : %d , fd1 : %d\n",fd,fd1);
int fd2=dup2(fd,fd1);
if(fd2==-1){
perror("dup2");
return -1;
}
//通過fd1去寫資料,實際操作的是1.txt,而不是2.txt
char * str="hello, dup2";
int len=write(fd1,str,strlen(str));
if(len==-1){
perror("write");
return -1;
}
printf("fd : %d , fd1 : %d, fd2 : %d\n",fd,fd1,fd2);
close(fd);
close(fd1);
return 0;
}
17.fcntl函式
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... );
引數:
- fd:表示需要操作的檔案描述符
- cmd:表示對檔案描述符需要進行何種操作
1.F_DUPFD:複製檔案描述符,得到新的檔案描述符
2.F_GETFL:獲取指定的檔案描述符檔案狀態flag(即open()函式中的那些flag)
3.F_SETFL:設定檔案描述符檔案狀態flag
- O_RDONLY,O_WRONLY,O_RDWR等等,不可以被修改
- O_APPEND(追加資料),O_NONBLOCK(非阻塞)等等,可以被修改
4.等等
//示例程式
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main(){
/*複製檔案描述符
int fd=open("1.txt",O_RDONLY);
int ret=fcntl(fd,F_DUPFD);
*/
int fd=open("1.txt",O_RDWR);
if(fd==-1){
perror("open");
return -1;
}
//獲取檔案描述符檔案狀態的flag
int flag=fcntl(fd,F_GETFL);
if(flag==-1){
perror ("fcntl");
return -1;
}
flag |= O_APPEND;
//修改檔案描述符檔案狀態的flag,給flag加入O_APPEND這個標記
int ret=fcntl(fd,F_SETFL,flag);
if(ret==-1){
perror ("fcntl");
return -1;
}
char * str="大家好啊";
write(fd,str,strlen(str));
close(fd);
return 0;
}
相關文章
- 【Linux】Linux系統程式設計入門Linux程式設計
- 程式設計入門之日誌聚合系統程式設計
- Linux入門---(三)Shell程式設計Linux程式設計
- Linux-shell程式設計入門基礎Linux程式設計
- Linux系統程式設計—有名管道Linux程式設計
- Linux系統程式設計基礎Linux程式設計
- Linux系統程式設計【4】——檔案系統Linux程式設計
- 【Linux系統程式設計】Linux訊號列表Linux程式設計
- Linux系統程式設計之程式介紹Linux程式設計
- Linux 利器- Python 指令碼程式設計入門(一)LinuxPython指令碼程式設計
- Linux系統程式設計:mmap使用技巧Linux程式設計
- Linux系統程式設計:訊號捕捉Linux程式設計
- Linux系統程式設計之匿名管道Linux程式設計
- Linux系統程式設計—訊號捕捉Linux程式設計
- Linux系統程式設計-檔案IOLinux程式設計
- Linux系統快速入門方法Linux
- 入門程式碼程式設計程式設計
- Linux系統程式設計——特殊程式之孤兒程式Linux程式設計
- Python程式設計入門Python程式設計
- Shell 程式設計入門程式設計
- 【Linux】關於Linux的系統程式設計總結Linux程式設計
- 程式設計和網路程式設計入門程式設計
- Linux系統——程式設計師跳槽必備Linux程式設計師
- Linux作業系統之Shell程式設計Linux作業系統程式設計
- Linux系統程式設計之檔案IOLinux程式設計
- linux系統程式設計CP小測試Linux程式設計
- 分享Linux系統快速入門法Linux
- Linux系統入門經歷分享Linux
- Number 1 — 程式設計入門程式設計
- Flink DataStream 程式設計入門AST程式設計
- java Swing程式設計入門Java程式設計
- 【Linux系統程式設計】libevent庫bufferevent與evconnlistenerLinux程式設計
- Linux系統程式設計【5】——stty的學習Linux程式設計
- Linux系統程式設計【3.1】——編寫ls命令Linux程式設計
- 【linux】系統程式設計-5-執行緒Linux程式設計執行緒
- 【linux】系統程式設計-1-程式、管道和訊號Linux程式設計
- Linux系統程式設計(七)檔案許可權系統呼叫Linux程式設計
- Linux 檔案系統之入門必看!Linux