文件IO
open函数
SYNOPSIS
#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);
创建文件最终权限:mode & ~umask
常用参数
O_RDONLY O_WRONLY O_RDWR
O_APPEND O_CREAT O_TRUNC
open 常见错误
- 文件不存在
- 操作权限不对
- 以只写方式打开目录
errno 错误码
使用方法:
#include <errno.h>
#include <string.h>
//错误的操作
char *strerror(int errnum);
read函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
size_t count为缓冲区的大小
返回-1时需要进一步判断,详见阻塞和非阻塞
write函数
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
size_t为待写入数据的大小
文件描述符
- 进程控制块PCB,本质是一个 结构体,其中有成员:文件描述符表,文件描述符本质为指针(键值对映射)
- struct file结构体,一个进程最多打开1024个文件,
阻塞和非阻塞
概念:阻塞和非阻塞指的是调用者(程序)在 等待返回结果(或输入)时的状态。 阻塞时,在调用结果返回前,当前线程会被 挂起 ,并在得到结果之后返回。 非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。
- 读取常规文件一般不会阻塞,因为不管其读取多少字节,read一定能在有限时间内得到返回结果。
- 产生阻塞的场景,读取网络、设备等文件
- 以O_NONBLOCK打开文件,可以为文件加上非阻塞属性,当一个阻塞文件被以非阻塞方式打开,并且文件无数据,read函数返回-1并且将errno = EAGIN或EWOULDBLOCK,不是read失败。
- demo:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
int fd1;
int len,tim;
char buf[512];
//以只读 非阻塞方式打开一个含有阻塞属性的文件
fd1 = open("/dev/tty",O_RDONLY | O_NONBLOCK);
if(fd1 < 0)
{
perror("open /dev/tty");
exit(1);
}
tryagain:
len = read(fd1, buf, 512);
if(len < 0)
{
if(errno != EAGAIN)
{
perror("read /dev/tty");
exit(1);
}
else
{
write(STDOUT_FILENO,"try again\n",strlen("try again\n"));
sleep(1);
goto tryagain;
}
}
write(STDOUT_FILENO,buf,len);
close(fd1);
return 0;
}
fcntl函数
SYNOPSIS
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
- 获取文件状态:F_GETFL
- 设置文件状态:F_SETFL
- 返回值:
- 返回值会有一个位图,每一位代表一个属性,可以通过按位操作来设置或获取文件对应属性
demo:
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
char buf[32];
int flags = 0;
int len;
flags = fcntl(STDIN_FILENO,F_GETFL); //获取文件的属性信息
if(flags == -1)
{
perror("fnctl error");
exit(1);
}
flags = flags | O_NONBLOCK; //按位或操作
int ret = fcntl(STDIN_FILENO,F_SETFL,flags);
if(ret == -1)
{
perror("fnctlset error");
exit(1);
}
tryagain:
len = read(STDIN_FILENO, buf, 512);
if(len < 0)
{
if(errno != EAGAIN)
{
perror("read /dev/tty");
exit(1);
}
else
{
write(STDOUT_FILENO,"try again\n",strlen("try again\n"));
sleep(1);
goto tryagain;
}
}
write(STDOUT_FILENO,buf,len);
return 0;
}
lseek函数
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
- fd 文件描述符
- offset 偏移量
- whence 起始偏移量
返回值:
成功:相较于起始位置偏移量
失败 -1
- 文件的读和写使用的同一个偏移量
- 可以使用lseek函数来获取,拓展文件大小
- 要使得文件大小被修改,必须使用文件IO操作
demo
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main(int argc,char* argv[])
{
char buf[] = "It is a test of lseek";
char rbuf[32];
int fd;
int len;
int set;
char ch;
fd = open("test.txt",O_CREAT | O_RDWR | O_TRUNC,0644);
if(fd < 0)
{
perror("open error");
exit(1);
}
write(fd,buf,strlen(buf));
lseek(fd,2,SEEK_SET);
while((len = read(fd,&ch,1)))
{
if(len < 0)
{
perror("read error");
exit(1);
}
write(STDOUT_FILENO,&ch,1);
}
close(fd);
return 0;
}