文件IO
//需要包含的头文件 #include <sys/types.h> //用于定义一些基本类型,如 mode_t #include <sys/stat.h> //用于定义文件权限 #include <fcntl.h> //包含 open()函数声明和一些常量,如 O_RDONLY int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
参数说明:
返回值:
错误值处理:
void perror(const char *s); char* strerror(int errnum);
#include<stdio.h> #include<string.h> //strerror 函数 #include<fcntl.h> //open 函数 #include<errno.h> //perror 函数 int main(int argc, char* argv[]) { int fd = open("log", O_RDWR | O_CREAT, 0764); if(fd == -1) { printf("open failed errno = %d\n", errno); perror("open"); printf("open failed: %s\n", strerror(errno)); return -1; } printf("open success fd = %d\n", fd); return 0; }
文件描述符为什么从 3 开始:
STDIN_FILENO 0 标准输入文件描述符 STDOUT_FILENO 1 标准输出文件描述符 STDERR_FILENO 2 标准错误文件描述符
进程的最大文件个数:
1 #include<stdio.h> 2 #include<fcntl.h> 3 4 int main(int argc, char** argv) 5 { 6 char pBuf[32] = "\0"; 7 int nCount = 0; 8 while(1) 9 { 10 sprintf(pBuf, "file%d", nCount++); 11 int fd = open(pBuf, O_RDONLY | O_CREAT, 0764); 12 if(fd == -1) 13 { 14 perror("open"); 15 break; 16 } 17 18 printf("open : %s\n", pBuf); 19 } 20 21 return 0; 22 }
open : file0
...
open : file1019
open : file1020
open: Too many open files
ulimit -a
core file size (blocks, -c) 0 ... open files (-n) 1024 ...
ulimit -n 2048
* soft nofile 2048 * hard nofile 2048
DefaultLimitNOFILE=2048 //user.conf DefaultLimitNOFILE=2048:524288 //system.conf
open : file0
...
open : file2043
open : file2044
open: Too many open files
O_CREAT 与文件权限:
1 #include<stdio.h> 2 #include<fcntl.h> 3 int main(int argc, char** argv) 4 { 5 int fd = open("log", O_RDONLY | O_CREAT); //no set permission 6 if(fd == -1) 7 { 8 perror("open"); 9 return -1; 10 } 11 printf("open success fd = %d\n", fd); 12 return 0; 13 }
--wsrwx--- 1 test test 0 10 月 29 15:46 log*
int fd = open("log", O_RDONLY | O_CREAT, 0777);
-rwxrwxr-x 1 test test 0 10 月 29 15:57 log*
#include <fcntl.h> int creat(const char *pathname, mode_t mode);
参数说明:
返回值:
1 #include<stdio.h> 2 #include<fcntl.h> 3 //#include<sys/stat.h> 4 int main(int argc, char** argv) 5 { 6 int fd1 = creat("log1", 0764); 7 int fd2 = creat("log2", S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP 8 | S_IWGRP | S_IROTH); 9 10 if(fd1 == -1) 11 { 12 perror("creat"); 13 return -1; 14 } 15 16 if(fd2 == -1) 17 { 18 perror("creat"); 19 return -1; 20 } 21 22 printf("creat success : fd1 = %d\n", fd1); 23 printf("creat success : fd2 = %d\n", fd2); 24 return 0; 25 }
-rwxrw-r-- 1 test test 0 10 月 29 17:08 log1* -rwxrw-r-- 1 test test 0 10 月 29 17:08 log2*
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<fcntl.h> 4 5 int main() 6 { 7 int fd0 = open("log", O_RDONLY); 8 if(fd0 == -1) 9 { 10 perror("open"); 11 return -1; 12 } 13 14 int fd1 = open("log", O_RDONLY); 15 if(fd1 == -1) 16 { 17 perror("open"); 18 return -1; 19 } 20 21 lseek(fd0, 10, SEEK_CUR); 22 23 printf("fd = %d, cur pos = %ld\n", fd0, lseek(fd0, 0, SEEK_CUR)); 24 printf("fd = %d, cur pos = %ld\n", fd1, lseek(fd1, 0, SEEK_CUR)); 25 }
fd = 3, cur pos = 10 fd = 4, cur pos = 0
#include <unistd.h> int dup(int oldfd);
参数说明:
返回值:
例子:
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<fcntl.h> 4 5 int main(int argc, char** argv) 6 { 7 int fd = open("log", O_RDONLY); 8 if(fd == -1) 9 { 10 perror("open"); 11 return -1; 12 } 13 14 int fd2 = dup(fd); 15 if(fd2 == -1) 16 { 17 perror("dup"); 18 return -1; 19 } 20 21 lseek(fd, 10, SEEK_CUR); 22 23 printf("fd = %d, cur pos = %ld\n", fd, lseek(fd, 0, SEEK_CUR)); 24 printf("fd = %d, cur pos = %ld\n", fd2, lseek(fd2, 0, SEEK_CUR)); 25 close(fd); 26 close(fd2); 27 }
fd = 3, cur pos = 10 fd = 4, cur pos = 10
#include <unistd.h> int dup2(int oldfd, int newfd);
参数说明:
返回值:
注意项:
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<unistd.h> 4 5 int main(int argc, char** argv) 6 { 7 int fd = open("log", O_RDWR); 8 if(fd == -1) 9 { 10 perror("open"); 11 return -1; 12 } 13 14 int nRet = dup2(fd, STDOUT_FILENO); //重定向 15 if(nRet == -1) 16 { 17 perror("dup2"); 18 return -1; 19 } 20 21 puts("Hello World!"); //将内容输出到log文件中 22 close(fd); 23 return 0; 24 }
#include <unistd.h> int close(int fd);
参数说明:
返回值:
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
参数说明:
返回值:
EINTR 标识:
1 int readn(int fd, void* pBuf, size_t n) 2 { 3 size_t nLeft = n; //剩余待读字节数 4 char* pTmpBuf = (char*)pBuf; 5 6 while (nLeft > 0) 7 { 8 int nRead = read(fd, pTmpBuf, nLeft); 9 if (nRead == -1) 10 { 11 if (errno == EINTR) 12 continue; //中断错误,继续执行循环 13 else 14 return -1; //其他错误 15 } 16 else if(nRead == 0) 17 break; //读到文件末尾 EOF 18 else 19 { 20 //读到数据 21 nLeft -= nRead; 22 pTmpBuf += nRead; 23 } 24 } 25 return n - nLeft; 26 }
read()函数是一个阻塞函数:
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<unistd.h> 4 5 int main(int argc, char** argv) 6 { 7 char pBuf[32]; 8 int nRet = read(STDIN_FILENO, pBuf, sizeof(pBuf) - 1); 9 if(nRet == -1) 10 { 11 perror("read"); 12 return -1; 13 } 14 pBuf[nRet] = '\0'; 15 printf("buf : %s, bytes : %d\n", pBuf, nRet); 16 return 0; 17 }
dhajkhd buf : dhajkhd , bytes : 8
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
参数说明:
返回值:
EINTR 标识:
1 ssize_t writeN(int fd, void* pUsrBuf, size_t n) 2 { 3 size_t nLeft = n; //剩余待写字节数 4 char* pBuf = pUsrBuf; 5 6 while(nLeft > 0) 7 { 8 int nWrite = write(fd, pBuf, nLeft); 9 if(nWrite == -1) 10 { 11 if(errno == EINTR) 12 continue; //中断出错,再写一次 13 else 14 return -1; //其他错误,直接退出 15 } 16 else 17 { 18 //写入成功,移动指针 19 nLeft -= nWrite; 20 pBuf += nWrite; 21 } 22 } 23 24 return n - nLeft; 25 }
案例:
1 #include<stdio.h> 2 #include<errno.h> 3 #include<fcntl.h> 4 #include<unistd.h> 5 #include<string.h> 6 7 int main(int argc, char** argv) 8 { 9 if(argc != 2) 10 { 11 printf("Usage: %s [string]\n", argv[0]); 12 return -1; 13 } 14 15 char pBuf[1024] = {0}; 16 sprintf(pBuf, "StdOut:%s\n", argv[1]); 17 int nRet = write(STDOUT_FILENO, pBuf, strlen(pBuf)); 18 19 sprintf(pBuf, "StdErr:%s\n", argv[1]); 20 nRet = write(STDOUT_FILENO, pBuf, strlen(pBuf)); 21 return 0; 22 }
$./a.out "Hello World!" StdOut:Hello World! StdErr:Hello World!
#include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
参数说明:
返回值:
例子:
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<unistd.h> 4 5 int main(int argc, char** argv) 6 { 7 if(argc != 2) 8 { 9 printf("Usage : %s [filename]\n", argv[0]); 10 return -1; 11 } 12 13 int fd = open(argv[1], O_RDONLY); 14 char pBuf[32] = {0}; 15 16 int nRead = read(fd, pBuf, 10); 17 int nPos = lseek(fd, 0, SEEK_CUR); 18 printf("pBuf : %s, readCount : %d, curPos : %d\n", pBuf, nRead, nPos); 19 20 nPos = lseek(fd, -5, SEEK_CUR); 21 nRead = read(fd, pBuf, 10); 22 printf("pBuf : %s, readCount : %d, curPos : %d\n", pBuf, nRead, nPos); 23 24 return 0; 25 }
$cat log 0123456789ABCDEFG $./a.out log pBuf : 0123456789, readCount : 10, curPos : 10 pBuf : 56789ABCDE, readCount : 10, curPos : 5
利用 lseek 获取文件大小:
int file_size = lseek(fd_lseek, 0, SEEK_END);
利用 lseek 产生空洞文件:
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<fcntl.h> 4 5 int main(int argc, char** argv) 6 { 7 int fd = open("log", O_WRONLY | O_CREAT | O_TRUNC, 0666); 8 if(fd == -1) 9 { 10 perror("open"); 11 return -1; 12 } 13 14 off_t offset = lseek(fd, 1024 * 1024 * 1024 - 1, SEEK_END); 15 printf("offset : %ld\n", offset); 16 write(fd, "\0", 1); 17 close(fd); 18 return 0; 19 }
$ ls -lh log -rw-rw-r-- 1 test test 1.0G 10月 30 17:28 log
#ifndef _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #endif
#include <unistd.h> int fsync(int fd);
参数说明:
返回值:
#include <unistd.h> int access(const char *path, int mode);
参数说明:
返回值:
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<fcntl.h> 4 #include<errno.h> 5 6 int main(int argc, char** argv) 7 { 8 if(argc != 2) 9 { 10 printf("Usage : %s [filename]", argv[0]); 11 return -1; 12 } 13 14 if(access(argv[1], F_OK | R_OK | W_OK | X_OK) == 0) 15 puts("F_OK | R_OK | W_OK | X_OK\n"); 16 else if(errno == EACCES) //权限不匹配 17 puts("EACCES\n"); 18 else if(errno == ENOENT) //给定路径错误或文件不存在 19 puts("ENOENT\n"); 20 else if(errno == ENAMETOOLONG) //文件名太长 21 puts("ENAMETOOLONG\n"); 22 23 return 0; 24 }
#include <fcntl.h> int fcntl(int fd, int cmd, ...);
参数说明:
返回值:
F_GETFL 与 F_SETFL标志:
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<unistd.h> 4 #include<string.h> 5 6 int main(int argc, char** argv) 7 { 8 int fd = open("log", O_RDONLY); 9 if(fd == -1) 10 { 11 perror("open"); 12 return -1; 13 } 14 char pBuf[32] = {0}; 15 int nRead = read(fd, pBuf, 10); 16 if(nRead == -1) 17 { 18 perror("read"); 19 return -1; 20 } 21 printf("pBuf : %s, read : %d\n", pBuf, nRead); 22 int nRet = fcntl(fd, F_SETFL, O_WRONLY); 23 printf("fcntl = %d\n", nRet); 24 if(nRet == -1) 25 { 26 perror("fcntl"); 27 return -1; 28 } 29 30 const char* pBuf2 = "C++ is best language!"; 31 int nWrite = write(fd, pBuf2, strlen(pBuf2)); 32 if(nWrite == -1) 33 { 34 printf("fd = %d\n", fd); 35 perror("write"); 36 return -1; 37 } 38 39 return 0; 40 }
$ ./a.out pBuf : HelloWorld, read : 10 fcntl = 0 fd = 3 write: Bad file descriptor
设置标准输入为非阻塞:
1 #include<stdio.h> 2 #include<errno.h> 3 #include<fcntl.h> 4 #include<unistd.h> 5 6 int main(int argc, char** argv) 7 { 8 char pBuf[32]; 9 int nRet = fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); 10 if(nRet == -1) 11 { 12 perror("fcntl"); 13 return -1; 14 } 15 16 AGAIN: 17 nRet = read(STDIN_FILENO, pBuf, sizeof(pBuf)); 18 if(nRet == -1) 19 { 20 perror("read"); 21 if(errno == EAGAIN) 22 { 23 sleep(1); 24 goto AGAIN; 25 } 26 else 27 { 28 return -1; 29 } 30 } 31 32 pBuf[nRet] = '\0'; 33 printf("pBuf : %s\n", pBuf); 34 35 return 0; 36 }
$ ./a.out read: Resource temporarily unavailable read: Resource temporarily unavailable read: Resource temporarily unavailable dhajkdaread: Resource temporarily unavailable pBuf : dhajkda
增加或移除标识:
1 int set_file_flag(int fd, int nflags, int on) 2 { 3 int fl = fcntl(fd, F_GETFL, 0); 4 if(fl == -1) 5 { 6 perror("fcntl"); 7 return -1; 8 } 9 10 if(!!on) 11 fl |= nflags; 12 else 13 fl &= ~nflags; 14 15 if(fcntl(fd, F_SETFL, fl) == -1) 16 { 17 perror("fcntl"); 18 return -1; 19 } 20 return 0; 21 }
#include <sys/stat.h> int stat(const char *path, struct stat *struct_stat); int lstat(const char *path,struct stat *struct_stat); int fstat(int fdp, struct stat *struct_stat);
参数说明:
返回值:
struct stat结构体:
struct stat { dev_t st_dev; // 文件所在设备 ID ino_t st_ino; // inode 号 mode_t st_mode; // 文件类型和访问权限 nlink_t st_nlink; // 硬链接数 uid_t st_uid; // 文件拥有者的用户 ID gid_t st_gid; // 文件所属组的组 ID dev_t st_rdev; // 对于特殊文件,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; // 最后一个状态更改时间 };
S_IFMT 0170000 文件类型的位遮罩 S_IFLNK 0120000 符号连接 S_IFREG 0100000 一般文件 S_IFBLK 0060000 区块装置 S_IFDIR 0040000 目录 S_IFCHR 0020000 字符装置 S_IFIFO 0010000 先进先出 S_ISUID 04000 文件的(set user‐id on execution)位 S_ISGID 02000 文件的(set group‐id on execution)位 S_ISVTX 01000 文件的sticky位(粘住位) S_IRUSR 00400 文件所有者具可读取权限 S_IWUSR 00200 文件所有者具可写入权限 S_IXUSR 00100 文件所有者具可执行权限 S_IRGRP 00040 用户组具可读取权限 S_IWGRP 00020 用户组具可写入权限 S_IXGRP 00010 用户组具可执行权限 S_IROTH 00004 其他用户具可读取权限 S_IWOTH 00002 其他用户具可写入权限 S_IXOTH 00001 其他用户具可执行权限
S_ISLNK (st_mode) 判断是否为符号连接
S_ISREG (st_mode) 是否为一般文件
S_ISDIR (st_mode) 是否为目录
S_ISBLK (st_mode) 是否是块设备
S_ISCHR (st_mode) 是否为字符设备文件
S_ISSOCK (st_mode) 是否为socket
粘住位(S_ISVTX):
chmod 1777 目录名 //使用数字形式设置粘住位 chmod +t 目录名 //使用符号形式设置粘住位
$ls -ld ./ drwxrwxrwt 2 test test 4096 10月 30 17:22 ./
SUID/SGID位:
chmod u+s file //设置SUID位 chmod g+s directory //设置SGID位
#include <sys/stat.h> int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode);
参数说明:
返回值:
例子:
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<sys/stat.h> 4 5 int main(int argc, char** argv) 6 { 7 if(argc != 3) 8 { 9 printf("Usage: %s [mode] [filename]", argv[0]); 10 return -1; 11 } 12 13 mode_t mode; 14 sscanf(argv[1], "%o", &mode); 15 int nchmod = chmod(argv[2], mode); 16 if(nchmod == -1) 17 { 18 perror("chmod"); 19 return -1; 20 } 21 22 return 0; 23 }
$ ./a.out 777 chmod.c $ ls -l chmod.c -rwxrwxrwx 1 test test 580 10月 30 20:07 chmod.c
#include <unistd.h> int chown(const char *path, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group); int lchown(const char *path, uid_t owner, gid_t group);
参数说明:
返回值:
#include <utime.h> int utime(const char *filename, const struct utimbuf *times);
参数说明:
返回值:
struct utimbuf结构体:
struct utimbuf { time_t actime; /* 新的访问时间 */ time_t modtime; /* 新的修改时间 */ };
#include <unistd.h> int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length);
参数说明:
返回值:
#include <unistd.h> int link(const char *oldpath, const char *newpath);
参数说明:
返回值:
注意项:
#include<unistd.h> int symlink( const char * oldpath,const char * newpath);
参数说明:
返回值:
#include<unistd.h> int readlink(const char * path ,char * buf, size_t bufsize);
参数说明:
返回值:
#include<unistd.h> int unlink(const char * pathname);
参数说明:
返回值:
注意项:
#include<stdio.h> int rename(const char * oldpath,const char * newpath);
参数说明:
返回值:
注意项:
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mode_t mode);
参数说明:
返回值:
案例-递归创建目录:
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<unistd.h> 4 #include<string.h> 5 #include<errno.h> 6 #include <sys/stat.h> 7 8 int main(int argc, char** argv) 9 { 10 if(argc != 2) 11 { 12 printf("Usage : %s [path]\n", argv[0]); 13 return -1; 14 } 15 16 char pBuf[1024]; 17 char* ptr = strtok(argv[1], "/"); 18 if(ptr != NULL) 19 strcpy(pBuf, ptr); 20 21 while(ptr) 22 { 23 int nRet = mkdir(pBuf, 0777); 24 if(nRet == -1) 25 { 26 if(errno != EEXIST) 27 { 28 perror("mkdir"); 29 return -1; 30 } 31 } 32 33 if(ptr = strtok(NULL, "/")) 34 { 35 strcat(pBuf, "/"); 36 strcat(pBuf, ptr); 37 break; 38 } 39 } 40 41 return 0; 42 }
#include <unistd.h> int rmdir(const char *pathname);
参数说明:
返回值:
#include <dirent.h> DIR *opendir(const char *name);
参数说明:
返回值:
#include <dirent.h>
int closedir(DIR *dirp);
参数说明:
返回值:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数说明:
返回值:
struct dirent结构体:
struct dirent { ino_t d_ino; // inode 号 off_t d_off; // 文件偏移量 unsigned short d_reclen; // dirent 结构体的长度 unsigned char d_type; // 文件类型 char d_name[]; // 文件名 };
字段含义:
#include <dirent.h>
void rewinddir(DIR *dirp);
参数说明:
#include <dirent.h>
long telldir(DIR *dirp);
参数说明:
返回值:
#include <dirent.h> void seekdir(DIR *dirp, long loc);
参数说明:
返回值:
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<fcntl.h> 4 #include<dirent.h> 5 6 int main(int argc, char** argv) 7 { 8 if(argc != 2) 9 { 10 printf("Usage : %s [directory]\n", argv[0]); 11 return -1; 12 } 13 14 DIR* dirp = opendir(argv[1]); 15 if(!dirp) 16 { 17 perror("opendir"); 18 return -1; 19 } 20 21 int nCount = 0; 22 long offset = 0; 23 struct dirent* _ptr = NULL; 24 while(_ptr = readdir(dirp)) 25 { 26 if(nCount++ == 2) 27 offset = telldir(dirp); 28 printf("name : %s\n", _ptr->d_name); 29 30 } 31 32 puts("==========seekdir============\n"); 33 34 seekdir(dirp, offset); 35 while(_ptr = readdir(dirp)) 36 { 37 if(nCount++ == 2) 38 offset = telldir(dirp); 39 printf("name : %s\n", _ptr->d_name); 40 } 41 42 closedir(dirp); 43 return 0; 44 }
#include <unistd.h> char* getcwd(char *buf, size_t size);
参数说明:
返回值:
案例:
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<string.h> 4 5 int main(int argc, char** argv) 6 { 7 char sPath[4096]; 8 memset(sPath, 0, sizeof(sPath)); 9 if(getcwd(sPath, sizeof(sPath)) != NULL) 10 { 11 printf("cur path : %s\n", sPath); 12 } 13 else 14 { 15 perror("getcwd"); 16 return -1; 17 } 18 19 return 0; 20 }
#include<unistd.h> int chdir(const char* path); int fchdir(int fd);
参数说明:
返回值: