(1)打开一个存在的文件
#include
#include
#include
int main(int argc, char* argv[])
{
int fd = open("./leetcode.txt",O_RDONLY);
printf("fd = %d\n",fd);
close(fd);
return 0;
}
(2)打开一个不存在文件
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd = open("leetcode.123",O_RDONLY);
printf("fd = %d, errno = %d:%s\n",fd,errno,strerror(errno));
close(fd);
return 0;
}
(3)以写方式打开只读文件(权限问题)
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd = open("leetcode.123",O_WRONLY);
printf("fd = %d, errno = %d:%s\n",fd,errno,strerror(errno));
close(fd);
return 0;
}
(4)以只写方式打开目录
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd = open("myDir",O_WRONLY);
printf("fd = %d, errno = %d:%s\n",fd,errno,strerror(errno));
close(fd);
return 0;
}
ulimit -a
read函数
write函数
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
char buff[1024];
int n = 0;
// 以只读的方式打开argv[1]
int fd1 = open(argv[1], O_RDONLY);
if (fd1 == -1)
{
perror("open argv[1] error");
exit(1);
}
// 以读写的方式打开argv[2],如果不存在,则创建,文件权限为 -rw-rw-r--
int fd2 = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0664);
if (fd2 == -1)
{
perror("open argv[2] error");
exit(1);
}
// 从fd1中读数据存到到buff中,每次读1024个,并赋值给n,如果不足1024,读多少就是多少,当读的数据为0时,读完文件
while ((n = read(fd1, buff, 1024)) != 0)
{
if (n < 0)
{
perror("read error");
exit(1);
}
// 将读的数据以实际大小n从buff中取出,写到fd2中
write(fd2, buff, n);
}
// close
close(fd1);
close(fd2);
return 0;
}
阻塞、非阻塞: 是设备文件、网络文件的属性。
产生阻塞的场景。 读设备文件。读网络文件。(读常规文件无阻塞概念。)
/dev/tty -- 终端文件。
open("/dev/tty", O_RDWR|O_NONBLOCK) --- 设置 /dev/tty 非阻塞状态。(默认为阻塞状态)
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
char buff[10];
int n = read(STDIN_FILENO, buff, 10);
if (n < 0) {
perror("read STDIN_FILENO");
exit(1);
}
write(STDOUT_FILENO, buff, n);
return 0;
}
运行程序后,进入等待状态(阻塞),当有输入时,程序才会接着执行,将输入的数据读入,并输出。
#include
#include
#include
#include
#include
#include
#include
#define MSG_TRY "try again\n"
#define MSG_TIMEOUT "time out\n"
int main(void)
{
char buff[10];
int fd, n ,i;
// 设置非阻塞读
fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
if (fd < 0) {
perror("open /dev/tty");
exit(1);
}
printf("open /dev/tty ok..... %d\n", fd);
for (int i = 0; i < 5; i++) {
// 读入数据
n = read(fd, buff, 10);
// 有数据读入,跳出循环
if (n > 0) {
break;
}
if (errno != EAGAIN) {
perror("read /edv/tty");
exit(1);
} else {
// 没有数据输入,则输出提示
write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
sleep(2);
}
}
// i等于5时,循环5次,没有读到数据,等待超时
if (i == 5) {
write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));
} else {
// i != 5,即读到数据,将读到的数据输出
write(STDOUT_FILENO, buff, n);
}
close(fd);
return 0;
}
等待超时。
有数据读入,读入数据,并输出,结束程序。
文件的读写使用的是同一偏移位置。
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd, n;
char msg[] = "It's a test for lseek\n";
char ch;
// 以读写的方式打开文件,如果不存在,则创建,权限 -rw-rw-r-
fd = open("lseek.txt", O_RDWR|O_CREAT, 0664);
if (fd < 0) {
perror("open lseek.txt error");
exit(1);
}
// 向文件中写入数据,此时光标在最后
write(fd, msg, strlen(msg));
// 先注释这行
//lseek(fd, 0, SEEK_SET);
while ((n = read(fd, &ch, 1))) {
if (n < 0) {
perror("read error");
exit(1);
}
// 将读出的数据在标准输出显示
write(STDOUT_FILENO, &ch, n);
}
close(fd);
return 0;
}
执行后没有数据输出,因为光标在最后位置。放开注释lseek(fd, 0, SEEK_SET);
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDWR);
if (fd == -1) {
perror("read error");
exit(1);
}
int length = lseek(fd, 0, SEEK_END);
printf("file size is %d\n",length);
close(fd);
return 0;
}
这里要注意lseek函数返回值的意义
将7.2中的文件从2900填充为3000,查100字节。
修改代码如下:
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDWR);
if (fd == -1) {
perror("read error");
exit(1);
}
// 从文件结束位置再偏移100
int length = lseek(fd, 100, SEEK_END);
printf("file size is %d\n",length);
close(fd);
return 0;
}
下面再用ls命令查看
它的大小不是3000。
原因是,要使文件大小真正拓展,必须引起IO操作。
修改后的扩展文件代码如下:
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDWR);
if (fd == -1) {
perror("read error");
exit(1);
}
int length = lseek(fd, 99, SEEK_END);
printf("file size is %d\n",length);
write(fd, "$", 1);
close(fd);
return 0;
}
这里2999和3000是因为lseek读取到偏移差的时候,还没有写入最后的‘$’符号。
查看文件
末尾那一大堆^@,是文件空洞,如果自己写进去的也想保持队形,就写入“\0”。
7.4、补充
拓展文件直接使用truncate,简单粗暴
使用 truncate 函数,直接拓展文件。 int ret = truncate("robot.txt", 5000);
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int length = truncate("robot.txt", 5000);
return 0;
}
这个函数超复杂,这里知识简单学习
fcntl用来改变一个【已经打开】的文件的 访问控制属性
重点掌握两个参数的使用, F_GETFL,F_SETFL
fcntl:
int (int fd, int cmd, ...)
fd 文件描述符
cmd 命令,决定了后续参数个数
获取文件状态: F_GETFL
设置文件状态: F_SETFL
终端文件默认是阻塞读的,这里用fcntl将其更改为非阻塞读
#include
#include
#include
#include
#include
#include
#include
#define MSG_TRY "try again\n"
int main(int argc, char* argv[])
{
char buff[10];
int flags, n;
flags = fcntl(STDIN_FILENO, F_GETFL); // 获取stdin的属性信息
if (flags == 1) {
perror("fcntl error");
exit(1);
}
// 用或位运算符修改属性
flags |= O_NONBLOCK;
// 再将属性赋回去,此时stdin就是非阻塞
int ret = fcntl(STDIN_FILENO, F_SETFL, flags);
if (ret == -1) {
perror("fcntl error");
exit(1);
}
tryagain:
n = read(STDIN_FILENO, buff, 10);
if (n < 0) {
// 出错
if (errno != EAGAIN) {
perror("read /dev/tty");
exit(1);
}
sleep(3);
write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
goto tryagain;
}
write(STDOUT_FILENO, buff, n);
return 0;
}
可以看到,是非阻塞读取。