Linux系统函数之IO函数
技术交流 QQ 群:1027579432,欢迎你的加入!
欢迎关注我的微信公众号:CurryCoder的程序人生
1.标准C库IO函数工作流程
- IO缓冲区的作用?
- 大部分硬盘都是机械硬盘,读取寻道时间和写入寻道时间都是在毫秒级ms;
- 相对来说,内存读写速度都非常块,因为内存属于电子设备,读写速度是纳秒级ns;
- 两者之间的读写速度相差一百万倍;
2.标准C库函数与Linux系统函数之间的关系
3.虚拟地址空间
- 程序运行以后,首先,每个进程都会创建各自独立的虚拟地址空间。接着,CPU执行代码时(实质是CPU中的MMU将虚拟地址空间中的数据映射到物理内存中,然后在物理内存中进行数据处理),其实是在物理内存中进行数据处理的。
- 虚拟地址空间的优点:在虚拟地址空间中的堆空间中申请了20M堆空间。为了能在物理内存中进行数据处理,需要将虚拟地址空间中的数据映射到物理内存中。但是,物理内存中没有连续的20M内存空间。然而,使用了这种映射机制后,可以将物理内存中不连续的20M内存空间连接到一起。例如:C++的STL中的vector内存地址是连续的,但是deque的内存地址是不连续的,却可以通过映射机制能够保证内存地址是连续的。
4.文件描述符表
- 标准输入stdin文件描述符0、标准输出stdout文件描述符1、标准错误stderr文件描述符2。
- 文件描述符的作用:通过文件描述符来寻找对应的磁盘文件。
- 进程控制块pcb:本质就是一个结构体。
- 一个进程有一个文件描述符表,前三个默认被占用了。
5.Linux系统文件IO函数
open函数原型:
- int open(const char *pathname, int flags);
- int open(const char *pathname, int flags, mode_t mode);
参数:
flags参数为一个32位整数:必选参数O_RDONLY, O_WRONLY, O_RDWR
可选参数:
- 创建文件:O_CREAT
- 创建文件时检查文件是否存在:O_EXCL
- 如果文件存在,返回-1
- 必选与O_CREAT一起使用
- 追加文件:O_APPEND
- 文件截断:O_TRUNC
- 设置非阻塞:O_NONBLOCK
- 创建文件:O_CREAT
mode: mode & ~umask(0777 & ~0002)
/************************************************************************ > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月04日 星期六 21时08分31秒 ************************************************************************/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h>
int main(int argc, const char* argv[]){ // 打开一个文件hello int fd = open("hello", O_RDWR | O_CREAT, 0777); if(fd == -1){ printf("打开失败\n"); } close(fd); return 0; } ```
read函数原型:
- ssize_t read(int fd, void *buf, size_t count);
- 参数:
- fd:open函数的返回值
- buf:缓冲区,存储要读取的数据
- count:缓冲区能存储的最大字节数sizeof(buf)
- 返回值:
- -1:失败
- 成功:
- >0:读出的字节数
- =0:文件读完了
write函数原型:
- ssize_t write(int fd, const void *buf, size_t count);
- 参数:
- fd:open函数的返回值
- buf:要写到文件中的数据
- count:strlen(buf)
- 返回值:
- -1:失败
- >0:写入到文件中的字节数
/************************************************************************ > File Name: read_write.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月04日 星期六 21时34分47秒 ************************************************************************/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> int main(int argc,const char* argv[]){ // 打开文件 int fd = open("english.txt",O_RDWR); printf("fd = %d\n",fd); // 打开另一个文件,写操作 int fd1 = open("temp", O_WRONLY | O_CREAT, 0664); printf("fd1 = %d\n", fd1); // read char buf[4096]; int len = read(fd, buf, sizeof(buf)); while(len > 0){ // 数据写入文件中 int ret = write(fd1, buf, len); printf("ret = %d\n", ret); // read len = read(fd, buf, sizeof(buf)); } close(fd); close(fd1); return 0; }
- lseek函数原型:
- off_t lseek(int fd, off_t offset, int whence);
- whence参数:
- SEEK_SET
- SEEK_CUR
- SEEK_END
- 使用:
- a.文件指针移动到头部;
- lseek(fd, 0, SEEK_SET);
- b.获取文件指针当前的位置;
- int len = lseek(fd, 0, SEEK_CUR);
- c.获取文件长度;
- int len = lseek(fd, 0, SEEK_END);
- a.文件指针移动到头部;
- 文件的拓展:
- 文件原大小为100K,现在括扩展为1100K:lseek(fd, 1000, SEEK_END);
- 最后,做一次写操作:write(fd, "a", 1);
/************************************************************************ > File Name: lessk.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 10时40分22秒 ************************************************************************/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> int main(int argc, const char* argv[]){ int fd = open("english.txt", O_RDWR); if(fd == -1){ perror("open error"); exit(1); } // 文件拓展 int len = lseek(fd, 1000, SEEK_END); write(fd, "a", 1); printf("len=%d\n", len); close(fd); return 0; }
6.perror和errno
- 全局变量:errno,不同的值,对应不同的错误信息。
- perror():打印错误的函数
```c
/****File Name: read_write.c
Author: CurryCoder
Mail: 1217096231@qq.com
Created Time: 2020年07月04日 星期六 21时34分47秒 - ***/
include <stdio.h>
include <unistd.h>
include <stdlib.h>
include <sys/types.h>
include <sys/stat.h>
include <string.h>
include <fcntl.h>
int main(int argc,const char* argv[]){
// 打开文件
int fd = open("english",O_RDWR);
printf("fd = %d\n",fd);
if(fd == -1){ perror("open error"); } // 打开另一个文件,写操作 int fd1 = open("temp", O_WRONLY | O_CREAT, 0664); printf("fd1 = %d\n", fd1); // read char buf[4096]; int len = read(fd, buf, sizeof(buf)); while(len > 0){ // 数据写入文件中 int ret = write(fd1, buf, len); printf("ret = %d\n", ret); // read len = read(fd, buf, sizeof(buf)); } close(fd); close(fd1); return 0;
}
#### 7.阻塞和非阻塞 - **阻塞读终端程序分析**:默认bash是前台程序,./a.out启动了一个程序,前台程序变成了./a.out,bash变成了后台程序。./a.out等待用户输入10个字符,实际输入的字符个数\>10,剩下的字符还在缓冲区中。read函数解除阻塞,读缓冲区数据,执行write函数,./a.out程序结束执行。bash从后台程序变成了前台程序,然后检查到了缓冲区中剩余的字符,将字符作为shell命令去做解析。 ```c /************************************************************************ > File Name: block_read.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 10时56分01秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> // 阻塞读终端 int main(void){ char buf[10]; int n; n = read(STDIN_FILENO, buf,10); if(n < 0){ perror("read STDIN_FIFLENO"); exit(1); } write(STDOUT_FILENO, buf, n); return 0; }
- 非阻塞读终端程序
```c
/****File Name: unblock_read.c
Author: CurryCoder
Mail: 1217096231@qq.com
Created Time: 2020年07月05日 星期日 11时15分32秒 - ***/
include <stdio.h>
include <unistd.h>
include <fcntl.h>
include <string.h>
include <errno.h>
include <stdlib.h>
define MSG_TRY "try again\n"
// 非阻塞读终端
int main(void){
char buf[10];
int fd, n;
// /dev/tty---->当前打开的终端设备
fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
if(fd < 0){
perror("open /dev/tty");
exit(1);
}
tryagain:
n = read(fd, buf,10);
if(n < 0){
// 如果write为非阻塞,但是没有数据可读,此时全局变量errno被设置为EAGAIN
if(errno == EAGAIN){
sleep(3);
write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
goto tryagain;
}
perror("read /dev/tty");
exit(1);
}
write(STDOUT_FILENO, buf, n);
close(fd);
return 0;
}
- 阻塞和非阻塞是文件的属性还是系统文件IO函数的属性?答案:**文件的属性**。 - 普通文件:例如:hello.c默认不阻塞 - 终端设备:/dev/tty,默认阻塞 - 管道/套接字:默认阻塞 #### 8.stat/lstat函数 - stat函数原型: - int stat(const char *pathname, struct stat *buf); - struct stat ```c struct stat { dev_t st_dev; // 文件的设备编号 ino_t st_ino; // 节点 mode_t st_mode; // 重点:文件的类型和存取的权限 nlink_t st_nlink; // 连接到该文件的硬链接数目,刚建立的文件值为1 uid_t st_uid; // 重点:用户ID gid_t st_gid; // 重点:用户组ID dev_t st_rdev; // 设备类型,若此文件为设备文件,则为其设备编号 off_t st_size; // 重点:文件字节数(文件大小) blksize_t st_blksize; // 块大小(文件系统的I/O缓冲区大小) blkcnt_t st_blocks; // 块数 struct timespec st_atim; // 最后一次访问时间 struct timespec st_mtim; // 重点:最后一次修改时间 struct timespec st_ctim; // 最后一次改变时间(指属性) }; ``` - 获取文件大小示例程序: ```c /************************************************************************ > File Name: stat.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 11时48分58秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> int main(int argc, const char* argv[]){ struct stat st; int ret = stat("english.txt",&st); if(ret == -1){ perror("stat error"); exit(1); } printf("file size=%ld\n", st.st_size); return 0; }
- st_mode[16位整数]
- 0-2bit--其他人权限
- S_IROTH 00004(八进制表示) 读权限
- S_IWOTH 00002 写权限
- S_IXOTH 00001 执行权限
- S_IRWXO 00007 掩码,过滤st_mode中除其他人权限以外的信息
- 3-5bit--所属组权限
- S_IRGRP 00040 读权限
- S_IWGRP 00020 写权限
- S_IXGRP 00010 执行权限
- S_IRWXG 00070 掩码,过滤st_mode中除所属组权限以外的信息
- 6-8bit--文件所有者权限
- S_IRUSR 00400 读权限
- S_IWUSR 00200 写权限
- S_IXUSR 00100 执行权限
- S_IRWXU 00700 掩码,过滤st_mode中除文件所有者权限以外的信息
- 12-15bit--文件类型
- S_IFSOCK 0140000 套接字
- S_IFLNK 0120000 符号链接(软链接)
- S_IFREG 0100000 普通文件
- S_IFBLK 0060000 块设备
- S_IFDIR 0040000 目录
- S_IFCHR 0020000 字符设备
- S_IFIFO 0010000 管道
- S_IFMT 0170000 掩码,过滤st_mode中除文件类型以外的信息
- 0-2bit--其他人权限
/************************************************************************ > File Name: stat.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 11时48分58秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> int main(int argc, const char* argv[]){ struct stat st; int ret = stat("english.txt",&st); if(ret == -1){ perror("stat error"); exit(1); } printf("file size=%ld\n", st.st_size); // 文件类型--判断是否为普通文件 if((st.st_mode & S_IFMT) == S_IFREG){ printf("这个文件是一个普通文件\n"); } // 文件所有者操作权限 if(st.st_mode & S_IRUSR){ printf(" r\n"); } if(st.st_mode & S_IWUSR){ printf(" w\n"); } if(st.st_mode & S_IXUSR){ printf(" x\n"); } return 0; }
- lstat函数原型:
- int lstat(const char *pathname, struct stat *buf);
- struct stat
- int lstat(const char *pathname, struct stat *buf);
struct stat { dev_t st_dev; // 文件的设备编号 ino_t st_ino; // 节点 mode_t st_mode; // 重点:文件的类型和存取的权限 nlink_t st_nlink; // 连接到该文件的硬链接数目,刚建立的文件值为1 uid_t st_uid; // 重点:用户ID gid_t st_gid; // 重点:用户组ID dev_t st_rdev; // 设备类型,若此文件为设备文件,则为其设备编号 off_t st_size; // 重点:文件字节数(文件大小) blksize_t st_blksize; // 块大小(文件系统的I/O缓冲区大小) blkcnt_t st_blocks; // 块数 struct timespec st_atim; // 最后一次访问时间 struct timespec st_mtim; // 重点:最后一次修改时间 struct timespec st_ctim; // 最后一次改变时间(指属性) };
- stat函数与lstat函数的区别:在于读取软链接文件时不同。
- lstat读取的是链接文件本身的属性
- stat读取的是链接文件指向的文件的属性(追踪、穿透)
/************************************************************************ > File Name: stat.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 11时48分58秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> int main(int argc, const char* argv[]){ struct stat st; int ret = lstat("s.s",&st); if(ret == -1){ perror("stat error"); exit(1); } printf("file size=%ld\n", st.st_size); // 文件类型--判断是否为普通文件 if((st.st_mode & S_IFMT) == S_IFREG){ printf("这个文件是一个普通文件\n"); } // 文件所有者操作权限 if(st.st_mode & S_IRUSR){ printf(" r"); } if(st.st_mode & S_IWUSR){ printf(" w"); } if(st.st_mode & S_IXUSR){ printf(" x"); } printf("\n"); return 0; }
9.文件属性相关的函数
- access()试当前用户指定文件是否具有某种属性
- 当前用户:使用哪个用户调用这个函数,这个用户就是当前用户。
- int access(const char *pathname, int mode);
- 参数:
- pathname:文件名
- mode:4种权限
- R_OK 读
- W_OK 写
- X_OK 执行
- F_OK 文件是否存在
- 返回值:
- 0:有某种权限或文件存在
- -1":没有或文件不存在
```c
/****File Name: access.c
Author: CurryCoder
Mail: 1217096231@qq.com
Created Time: 2020年07月05日 星期日 15时40分48秒
- 参数:
- ***/
include <stdio.h>
include <stdlib.h>
include <unistd.h>
int main(int argc, const char* argv[]){
if(argc < 2){
printf("a.out filename\n");
exit(1);
}
int ret = access(argv[1],W_OK ); if(ret == -1){ perror("access"); exit(1); } printf("you can write this file.\n"); return 0;
}
- chmod()修改文件权限 - int chmod(const char *pathname, mode_t mode); - 参数: - pathname:文件名 - mode:文件权限,八进制数 - chown()修改文件所有者和所属组 - int chown(const char *pathname, uid_t owner, gid_t group); - 参数: - pathname:文件名 - owner:整型值,用户ID - 用户ID的查看:/etc/passwd - group:整型值,用户组ID - 用户组ID的查看:/etc/group ```c /************************************************************************ > File Name: chmod.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 15时50分54秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> int main(int argc, const char* argv[]){ if(argc < 3){ printf("a.out filename mode\n"); exit(1); } int mode = strtol(argv[2], NULL, 8); int ret = chmod(argv[1], mode); if(ret == -1){ perror("chmod"); exit(1); } ret = chown(argv[1], 1001, 1002); if(ret == -1){ perror("chown"); exit(1); } return 0; }
- truncate()修改文件大小
- int truncate(const char *path, off_t length);
- 参数:
- path:文件名
- length:文件的最终大小
- 比原来小,删除后面的部分
- 比原来大,向后扩展
10.目录属性相关的函数
rename()文件重命名
- int rename(const char *oldpath, const char *newpath);
修改当前进程(应用程序)的路径,相当于cd命令
- int chdir(const char *path);
- 参数:切换的路径
获取当前进程的工作目录,相当于pwd命令
- char *getcwd(char *buf, size_t size);
- 返回值:
- 成功:当前的工作目录
- 失败:NULL
- 参数:
- buf:缓冲区,存储当前的工作目录
- size:缓冲区大小
创建目录,相当于mkdir命令
- int mkdir(const char *pathname, mode_t mode);
- 参数:
- pathname:创建的目录名
- mode:目录权限,八进制的数,实际权限:mode & ~umask
删除一个空目录
int rmdir(const char *pathname);
参数:空目录的名字
/************************************************************************ > File Name: chdir.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 16时07分20秒 ************************************************************************/ #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <unistd.h> int main(int argc, const char* argv[]){ if(argc < 2){ printf("a.out dir\n"); exit(1); } int ret = chdir(argv[1]); if(ret == -1){ perror("chdir"); exit(1); } int fd = open("chdir.txt", O_CREAT | O_RDWR, 0777); if(fd == -1){ perror("open"); exit(1); } close(fd); char buf[128]; getcwd(buf, sizeof(buf)); printf("current dir: %s\n", buf); return 0; }
11.目录遍历相关的函数
(1).打开一个目录opendir()
- DIR *opendir(const char *name);
- 参数:目录名
- 返回值:指向目录的指针
- DIR *opendir(const char *name);
(2).读目录
struct dirent { ino_t d_ino; // 此目录进入点的inode ff_t d_off; // 目录文件开头至此目录进入点的位移 signed short ind d_reclen; // d_name的长度,不包含NULL字符 unsigned char d_type; // 重点:d_name所指的文件类型 har d_name[256]; // 重点:文件名 };
d_type:
- DT_BLK:块设备
- DT_CHR:字符设备
- DT_DIR:目录
- DT_LNK:软链接
- DT_FIFO:管道
- DT_REG:普通文件
- DT_SOCK:套接字
- DT_UNKNOWN:未知
struct dirent* readdir(DIR* dirp);
- 参数:opendir的返回值
- 返回值:目录项结构体
(3).关闭目录
- int closedir(DIR *dirp);
/************************************************************************ > File Name: getfilenumber.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 21时24分32秒 ************************************************************************/ #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <stdlib.h> #include <dirent.h> // 读指定目录中的文件个数 int get_file_num(const char* root){ int total = 0; // 读目录 DIR* dir = NULL; dir = opendir(root); if(dir == NULL){ perror("opendir error"); exit(1); } // 循环读目录中的文件 struct dirent* ptr = NULL; while((ptr = readdir(dir)) != NULL){ // 不处理.和..目录 if(strcmp(".", ptr->d_name) == 0 || strcmp("..", ptr->d_name) == 0){ continue; } // 判断是否是普通文件 if(ptr->d_type == DT_REG){ total++; } // 如果是目录,则需要递归 if(ptr->d_type == DT_DIR){ // 求出子目录 char path[1024] = {0}; sprintf(path, "%s/%s", root, ptr->d_name); total += get_file_num(path); } } // 关闭目录 closedir(dir); return total; } int main(int argc, const char* argv[]){ if(argc < 2){ printf("./a.out path\n"); exit(1); } int total = get_file_num(argv[1]); printf("%s目录下的普通文件共有:%d个\n", argv[1],total); return 0; }
12.dup、dup2和fcntl函数
复制文件描述符
- int dup(int oldfd);
- 参数:oldfd要复制的文件描述符
- 返回值:取最小的且没被占用的文件描述符
- dup调用成功:有两个文件描述符指向同一个文件
- int dup2(int oldfd, int newfd);
- 假设:oldfd指向hello文件,newfd指向world文件
- a.假设newfd已经指向了一个文件,首先断开close与那个文件的链接,newfd指向oldfd指向的文件(文件描述符的重定向)
- b.newfd没有被占用,newfd指向oldfd指向的文件
- c.oldfd和newfd指向同一个文件,不做任何处理
- 假设:oldfd指向hello文件,newfd指向world文件
改变已经打开的文件的属性:fcntl
- 变参函数
- 复制一个已有的文件描述符:int ret = fcntl(fd, F_DUPFD)
- 获取/设置文件状态标志
- open的flags参数
- 获取文件状态标识:int flag = fcntl(fd, F_GETFL)
- 设置文件状态标识:
- flag = flag | O_APPEND;
- fcntl(fd, F_SETFL, flag)
- 可更改的几个标识:O_APPEND、O_NONBLOCK(常用)
int dup2(int oldfd, int newfd);
/************************************************************************ > File Name: dup.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 22时07分30秒 ************************************************************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> int main(void){ int fd = open("tmp", O_RDWR | O_CREAT, 0664); if(fd == -1){ perror("open"); exit(1); } // 复制文件描述符 int fd2 = dup(fd); // int fd2 = fcntl(fd, F_DUPFD); // 写文件 char* p = "代码改变世界..."; write(fd2, p, strlen(p)); close(fd2); char buf[1024]; lseek(fd, 0, SEEK_SET); read(fd, buf, sizeof(buf)); printf("buf = %s\n", buf); close(fd); return 0; } /************************************************************************ > File Name: dup2.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 22时07分30秒 ************************************************************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> int main(void){ int fd = open("tmp", O_RDWR | O_CREAT | O_APPEND, 0664); if(fd == -1){ perror("open"); exit(1); } int fd2 = open("tmp1", O_RDWR | O_CREAT | O_APPEND, 0664); if(fd2 == -1){ perror("open open"); exit(1); } // 复制文件描述符 dup2(fd, fd2); // 写文件 char* p = "code change the world..."; write(fd2, p, strlen(p)); close(fd2); char buf[1024]; lseek(fd, 0, SEEK_SET); read(fd, buf, sizeof(buf)); printf("buf = %s\n", buf); close(fd); return 0; } /************************************************************************ > File Name: fcntl.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 22时28分26秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main(void) { int fd; int flag; // 测试字符串 char *p = "我们是一个有中国特色的社会主义国家!!!!!!"; char *q = "呵呵, 社会主义好哇。。。。。。"; // 只写的方式打开文件 fd = open("test.txt", O_WRONLY); if(fd == -1) { perror("open"); exit(1); } // 输入新的内容,该部分会覆盖原来旧的内容 if(write(fd, p, strlen(p)) == -1) { perror("write"); exit(1); } // 使用 F_GETFL 命令得到文件状态标志 flag = fcntl(fd, F_GETFL, 0); if(flag == -1) { perror("fcntl"); exit(1); } // 将文件状态标志添加 ”追加写“ 选项 flag |= O_APPEND; // 将文件状态修改为追加写 if(fcntl(fd, F_SETFL, flag) == -1) { perror("fcntl -- append write"); exit(1); } // 再次输入新内容,该内容会追加到旧内容的后面 if(write(fd, q, strlen(q)) == -1) { perror("write again"); exit(1); } // 关闭文件 close(fd); return 0; } /************************************************************************ > File Name: fc.c > Author: CurryCoder > Mail: 1217096231@qq.com > Created Time: 2020年07月05日 星期日 22时30分16秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main(void) { int fd; int flag; // 测试字符串 char *p = "我们是一个有中国特色的社会主义国家!!!!!!"; char *q = "我无言以对,只能呵呵。。。。。。"; // 只写的方式打开文件 fd = open("test.txt", O_RDONLY); if(fd == -1) { perror("open"); exit(1); } // 使用 F_GETFL 命令得到文件状态标志 flag = fcntl(fd, F_GETFL, 0); if(flag == -1) { perror("fcntl"); exit(1); } flag = O_RDWR; if(fcntl(fd, F_SETFL, flag) == -1) { perror("fcntl -- append write"); exit(1); } // 再次输入新内容,该内容会追加到旧内容的后面 if(write(fd, q, strlen(q)) == -1) { perror("write again"); exit(1); } // 关闭文件 close(fd); return 0; }