- 文件IO (系統調用)
- 文件描述符
- open函數
- read函數
- write函數
- lseek函數
- close函數
- dup函數
- dup2函數
- stat函數
- getpwuid函數
- getgrgid函數
- 實例
- 目錄操作
- opendir函數
- readdir函數
- rewinddir函數
- closedir函數
- 實例
文件IO (系統調用)
文件IO就是系統調用,用戶空間進入內核空間的過程就是系統調用。
系統調用沒有緩沖機制,效率較低,可移植性也相對較差,實時性高。
文件描述符
文件描述符是使用open函數打開文件時的返回值
對文件的讀寫操作,就是通過文件描述符來完成的。
文件描述符是一個整數,在一個程序中文件描述符的范圍0-1023共計1024個,
使用 uilmit -a 可以查看一個程序中可以打開的文件的個數限制
(open files 后面對應的就是 這個值也可以使用命令 ulimit -n 2048來修改 但一般都是用默認值)
在一個程序啟動的過程中,默認就會打開三個描述符(0 1 2),
分別對應標準輸入、標準輸出、標準錯誤。
其他文件描述符需要通過open函數來打開文件,并獲得文件描述符。
文件描述符依次遞增,文件描述符遵循復用原則,文件描述符關閉后,這個符號就空閑了,可以被其他程序使用.
open函數
open函數用來打開文件,并返回文件描述符。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags, mode_t mode);
參數:
- pathname:要打開的文件的路徑名
- flags:打開文件的方式,可以是以下值:
-
O_RDONLY:只讀方式打開
-
O_WRONLY:只寫方式打開
-
O_RDWR:讀寫方式打開
-
O_CREAT:如果文件不存在,則創建文件
- 如果指定了這個宏,則第三個參數 mode 必須填
- 創建文件的權限還得涉及 掩碼 umask
- umask的值 默認為 0002 這個值也可以改的
- 最終的權限 = (mode & ~umask)
- 所以 即使給的是 0666 最終的權限也是 0664
-
O_APPEND:在文件尾部追加內容
-
O_TRUNC:如果文件存在,清空
-
O_EXCL:如果文件存在,則返回錯誤,錯誤碼:EEXIST
-
- mode:文件權限,一般八進制表示;
返回值:
- 成功:返回文件描述符
- 失敗:返回-1,并設置errno
read函數
read函數用來從文件中讀取內容。
#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
參數:
- fd:文件描述符
- buf:讀取到的數據存放的緩沖區
- count:要讀取的字節數
返回值:
- 成功:返回實際讀取的字節數
- 失敗:返回-1,并設置errno
write函數
write函數用來向文件中寫入內容。
函數原型:
#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);
參數:
- fd:文件描述符
- buf:要寫入的數據存放的緩沖區
- count:要寫入的字節數
返回值:
- 成功:返回實際寫入的字節數
- 失敗:返回-1,并設置errno
lseek函數
lseek函數用來移動文件讀寫指針的位置。
#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
參數:
- fd:文件描述符
- offset:相對于 whence 的偏移量
- whence:
- SEEK_SET:相對于文件開始位置
- SEEK_CUR:相對于當前位置
- SEEK_END:相對于文件結束位置
返回值:
- 成功:返回新的文件位置
- 失敗:返回-1,并設置errno
close函數
close函數用來關閉文件。
#include <unistd.h>int close(int fd);
參數:
- fd:文件描述符
返回值:
- 成功:返回0
- 失敗:返回-1,并設置errno
dup函數
dup函數用來復制文件描述符。
#include <unistd.h>int dup(int oldfd);
參數:
- oldfd:被復制的文件描述符
返回值:
- 成功:返回新的文件描述符
- 失敗:返回-1,并設置errno
dup2函數
dup2函數用來復制文件描述符并修改文件描述符。
#include <unistd.h>int dup2(int oldfd, int newfd);
參數:
- oldfd:被復制的文件描述符
- newfd:新的文件描述符
返回值:
- 成功:返回新的文件描述符
- 失敗:返回-1,并設置errno
- 注意:如果newfd已經打開,則先關閉它。
stat函數
stat函數用來獲取文件屬性信息。
函數原型:
#include <sys/stat.h>int stat(const char *pathname, struct stat *buf);
參數:
- pathname:文件路徑名
- buf:存放文件屬性信息的結構體
返回值:
- 成功:返回0
- 失敗:返回-1,并設置errno
結構體stat的定義如下:
struct stat {dev_t st_dev; //磁盤設備號ino_t st_ino; //inode節點號mode_t st_mode; //文件類型和權限st_mode & S_IFMT(0777) -> 文件權限獲取文件的類型的方式: st_mode & S_IFMT 文件的類型S_IFMT 0170000 獲取類型的掩碼S_IFSOCK 0140000 套接字文件S_IFLNK 0120000 軟鏈接文件S_IFREG 0100000 普通文件S_IFBLK 0060000 塊設備文件S_IFDIR 0040000 目錄文件S_IFCHR 0020000 字符設備文件S_IFIFO 0010000 管道文件例如:判斷文件是否是普通文件if((stat.st_mode & S_IFMT) == S_IFREG)或者:if(S_ISREG(stat.st_mode))nlink_t st_nlink; //鏈接數uid_t st_uid; //所有者用戶IDgid_t st_gid; //所有者組IDdev_t st_rdev; //設備號(若此對象為設備文件)off_t st_size; //文件大小(字節數)blksize_t st_blksize; //塊大小(字節數)blkcnt_t st_blocks; //塊數time_t st_atime; //最后訪問時間time_t st_mtime; //最后修改時間time_t st_ctime; //最后狀態改變時間#define st_atime st_atim.tv_sec//最后訪問時間#define st_mtime st_mtim.tv_sec//最后修改時間#define st_ctime st_ctim.tv_sec//最后狀態改變時間
};
函數: int lstat(const char *pathname, struct stat *statbuf);
可以獲取鏈接的屬性
getpwuid函數
getpwuid函數用來獲取用戶信息。
函數原型:
#include <pwd.h>struct passwd *getpwuid(uid_t uid);
參數:
- uid:用戶ID
返回值:
- 成功:返回指向passwd結構體的指針
- 失敗:返回NULL,并設置errno
passwd結構體的定義如下:
struct passwd {char *pw_name; //用戶名char *pw_passwd; //密碼uid_t pw_uid; //用戶IDgid_t pw_gid; //組IDchar *pw_gecos; //用戶信息char *pw_dir; //用戶主目錄char *pw_shell; //用戶登錄shell
};
getgrgid函數
getgrgid函數用來獲取組信息。
函數原型:
#include <grp.h>struct group *getgrgid(gid_t gid);
參數:
- gid:組ID
返回值:
- 成功:返回指向group結構體的指針
- 失敗:返回NULL,并設置errno
group結構體的定義如下:
struct group {char *gr_name; //組名char *gr_passwd; //組密碼gid_t gr_gid; //組IDchar **gr_mem; //組成員列表
};
實例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>int main()
{int fd;char buf[1024];struct passwd *pw;struct group *gr;struct stat st;//打開文件fd = open("test.txt", O_RDONLY, 0666);if (fd == -1) {perror("open");exit(1);}//讀取文件內容read(fd, buf, 1024);printf("%s\n", buf);//關閉文件close(fd);//獲取文件屬性if (stat("test.txt", &st) == -1) {perror("stat");exit(1);}//獲取文件所有者信息pw = getpwuid(st.st_uid);if (pw == NULL) {perror("getpwuid");exit(1);}printf("owner: %s\n", pw->pw_name);//獲取文件所屬組信息gr = getgrgid(st.st_gid);if (gr == NULL) {perror("getgrgid");exit(1);}printf("group: %s\n", gr->gr_name);return 0;
}
目錄操作
opendir函數
opendir函數用來打開目錄。
函數原型:
#include <dirent.h>DIR *opendir(const char *name);
參數:
- name:目錄路徑名
返回值:
- 成功:返回指向DIR結構體的指針
- 失敗:返回NULL,并設置errno
DIR結構體:
struct dirent {ino_t d_ino; //inode節點號off_t d_off; //目錄偏移量unsigned short d_reclen; //目錄項長度unsigned char d_type; //目錄項類型char d_name[NAME_MAX+1]; //目錄項名
};
readdir函數
readdir函數用來讀取目錄中的文件信息。
函數原型:
#include <dirent.h>struct dirent *readdir(DIR *dirp);
參數:
- dirp:指向DIR結構體的指針
返回值:
- 成功:返回指向dirent結構體的指針
- 失敗:返回NULL,并設置errno
dirent結構體的定義如下:
struct dirent {ino_t d_ino; //inode節點號off_t d_off; //目錄偏移量unsigned short d_reclen; //目錄項長度unsigned char d_type; //目錄項類型char d_name[NAME_MAX+1]; //目錄項名
};
rewinddir函數
rewinddir函數用來將目錄讀寫指針指向文件頭。
函數原型:
#include <dirent.h>void rewinddir(DIR *dirp);
參數:
- dirp:指向DIR結構體的指針
返回值:
- 無
closedir函數
closedir函數用來關閉目錄。
函數原型:
#include <dirent.h>int closedir(DIR *dirp);
參數:
- dirp:指向DIR結構體的指針
返回值:
- 成功:返回0
- 失敗:返回-1,并設置errno
實例
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>int main()
{DIR *dir;struct dirent *dp;struct stat st;//打開目錄dir = opendir(".");if (dir == NULL) {perror("opendir");exit(1);}//讀取目錄中的文件信息while ((dp = readdir(dir)) != NULL) {printf("%s\n", dp->d_name);//獲取文件屬性if (lstat(dp->d_name, &st) == -1) {perror("lstat");exit(1);}//判斷文件類型if (S_ISDIR(st.st_mode)) {printf("d");} else if (S_ISREG(st.st_mode)) {printf("-");} else if (S_ISLNK(st.st_mode)) {printf("l");} else if (S_ISFIFO(st.st_mode)) {printf("p");} else if (S_ISSOCK(st.st_mode)) {printf("s");} else {printf("?");}//獲取文件所有者信息printf(" %d/%d ", st.st_uid, st.st_gid);//獲取文件大小printf("%ld ", st.st_size);//獲取文件修改時間printf("%s ", ctime(&st.st_mtime));}//關閉目錄closedir(dir);return 0;
}