1. 文件I/O
1.1 打开和可能创建一个文件open()
帮助文档:
man 2 open
包含头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
函数原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
参数 | 说明 |
---|---|
pathname | 文件名 |
flags | 必选项:O_RDONLY|O_WRONLY|O_RDWR 可选项: O_APPEND|O_CREAT|O_EXCL|O_NONBLOCK|etc |
mode | 创建文件时的权限 |
return | 成功:返回最小的可用文件描述符 失败:-1,并设置errno |
注:Linux中一个进程最大文件描述符为1023;默认打开0:标准输入(STDIN_FIFENO);1:标准输出(STDOUT_FIFENO);2:标准错误(STDERR_FIFENO)
验证代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int num = 3;
char filename[128] = { 0 };
while(1)
{
sprintf(filename, "temp_%04d.txt", num++);
if(open(filename, O_RDONLY | O_CREAT, 0664) < 0)
{
perror("open error:");
break;
}
}
printf("num = %d", num - 1);
return 0;
}
1.2 关闭一个文件描述符close()函数
帮助文档:
man 2 close
包含头文件:
#include <unistd.h>
函数原型:
int close(int fd);
参数 | 说明 |
---|---|
fd | 文件描述符 |
return | 成功:0 失败:-1,并设置errno |
代码示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDONLY | O_CREAT, 0664);
if(fd == -1)
return -1;
close(fd);
return 0;
}
1.3 从一个文件描述符读取数据read()
帮助文档:
man 2 read
包含头文件:
#include <unistd.h>
函数原型:
ssize_t read(int fd, void* buf, size_t count);
参数 | 说明 |
---|---|
fd | 文件描述符 |
buf | 缓冲区 |
count | 缓冲区大小 |
return | 成功:返回读到的字节大小 失败:-1,设置errno 0表示读到文件尾 |
1.4 写入数据到一个文件描述符write()
帮助文档:
man 2 write
包含头文件:
#include <unistd.h>
函数原型:
ssize_t write(int fd, const void *buf, size_t count);
参数 | 说明 |
---|---|
fd | 文件描述符 |
buf | 缓冲区 |
count | 缓冲区大小 |
return | 成功:写入字节数 失败:-1,并设置errno 0:未写入 |
代码示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDONLY);
char buf[256] = { 0 };
int ret = 0;
while((ret = read(fd, buf, sizeof(buf))) > 0)
write(STDOUT_FIFENO, buf, ret);
close(fd);
return 0;
}
1.5 重新定位读/写文件偏移量lseek()
帮助文档:
man 2 lseek
包含头文件:
#include <sys/types.h>
#include <unistd.h>
函数原型:
off_t lseek(int fd, off_t offset, int whence);
参数 | 说明 |
---|---|
fd | 文件描述符 |
offset | 偏移量 |
whence | SEEK_SET :文件开始SEEK_CUR :当前位置SEEK_END :文件尾 |
return | 成功:当前位置到开始的字节数 失败:-1,设置errno |
代码示例1:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDONLY);
int fileSize = lseek(fd, 0, SEEK_END);
printf("%s size : %d\n", argv[1], fileSize);
close(fd);
return 0;
}
代码示例2:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDWR | O_CREAT, 0664);
int fileSize = lseek(fd, 1024, SEEK_END);
write(fd, "write at least once", 19);
close(fd);
return 0;
}
1.6 阻塞与非阻塞
read()
函数在读设备,读管道或读网络的时候,read()
函数会阻塞
输入输出设备:/dev/tty
由于read()
在非阻塞的情况下返回-1,所以当read()
返回-1时需要判断errno
的值
阻塞示例代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/tty", O_RDWR);
char buf[256] = { 0 };
int ret = 0;
while(1)
{
printf("blocked\n");
if(ret = read(fd, buf, sizeof(buf)));
printf("\t%s\n", buf);
}
close(fd);
return 0;
}
非阻塞示例代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/tty", O_RDWR|O_NONBLOCK);
char buf[256] = { 0 };
int ret = 0;
while(1)
{
printf("nonblocking\n");
if(ret = read(fd, buf, sizeof(buf)));
printf("\t%s\n", buf);
if(ret < 0)
{
perror("read error:"); # read error:Resource temporarily unavailable
printf("ret=%d\n", ret); # ret = -1
}
sleep(1);
}
close(fd);
return 0;
}
1.7 操作文件描述符fcntl()
帮助文档:
man 2 fcntl
包含头文件:
#include <unistd.h>
#include <fcntl.h>
函数原型:
int fcntl(int fd, int cmd, ... / * arg */ );
参数 | 说明 |
---|---|
fd | 文件描述符 |
cmd | F_GETFL|F_SETFD|etc |
代码示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/tty", O_RDWR);
// 通过fcntl()设置非阻塞
int flags = fcntl(fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
char buf[256] = { 0 };
int ret = 0;
while(1)
{
printf("nonblocking\n");
if(ret = read(fd, buf, sizeof(buf)));
printf("\t%s\n", buf);
sleep(1);
}
close(fd);
return 0;
}
1.8 复制文件描述符
1.8.1 dup()
帮助手册:
man 2 dup
包含头文件:
- `#include <unistd.h>
函数原型:
int dup(int oldfd);
参数 | 说明 |
---|---|
oldfd | 原文件描述符 |
return | 成功:新文件描述符 失败:-1,并设置errno |
1.8.2 dup2()
帮助手册:
man 2 dup2
包含头文件:
- `#include <unistd.h>
函数原型:
int dup2(int oldfd, int newfd);
参数 | 说明 |
---|---|
oldfd | 原文件描述符 |
newfd | 新文件描述符 |
return | 成功:新文件描述符 失败:-1,并设置errno |
主要用于重定向描述符
newfd
指向oldfd
示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int stdout_fifeno = dup(STDOUT_FILENO);
int fd = open("test.txt", O_WRONLY | O_CREAT, 0664);
dup2(fd, STDOUT_FILENO);
printf("hello world\n");
fflush(stdout);
dup2(stdout_fifeno, STDOUT_FILENO);
printf("Hello World\n");
close(fd);
return 0;
}