目录
1.什么是底层文件I/O
2.底层文件I/O常用库函数
2.1 write函数
2.2 read函数
2.3 open函数
2.4 close函数
2.5 lseek函数
2.6 ioctl函数
2.7 fcntl()函数
2.8 pread()函数
2.9 pwrite()函数
1.什么是底层文件I/O
底层I/O指的是与硬件设备之间的直接输入输出操作。这些操作通常涉及文件系统和设备驱动程序,并且可以通过系统调用进行访问,如open()、read()、write()等。底层I/O允许程序直接与硬件设备进行通信,例如磁盘驱动器、网络接口卡、键盘、鼠标等
2.底层文件I/O常用库函数
(通常来说,我们学习一个函数就是从 参数,返回值,函数作用三个方面去学习一个函数。)
在Linux中当我们打开一个程序是一般来说将会打开三个文件,可以理解为终端上的控制台的输入输出,其中0,1,2即为文件描述符。
- 标准输入流:0
- 标准输出流:1
- 标准错误流:2
2.1 write函数
- 参数:
fd
:要写入的文件描述符。buf
:要写入的数据缓冲区。count
:要写入的字节数。
- 返回值:
- 若成功,则返回写入的字节数(非负整数)。
- 若失败,则返回-1,并设置errno。
- 作用:将缓冲区buf的count个字节写入文件描述符相关联的文件中。
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
例子
向终端控制台输出Hello world 错误则输出Write error
#include <stdio.h>
#include <unistd.h>int main()
{if(writr(1,"Hello world\n",12)!=18){write(2,"Write error.\n",13);}exit(0);
}
输出
2.2 read函数
- 参数:
fd
:要读取的文件描述符。buf
:用于存放读取数据的缓冲区。count
:要读取的字节数。
- 返回值:
- 若成功,则返回读取的字节数(非负整数)。
- 若已到达文件末尾,则返回0。
- 若失败,则返回-1,并设置errno。
- 作用:从文件中读取count个字节数存入到buf中。
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
例子
读取终端输入并将读到的数据打印在屏幕上
#include <unistd.h>
#include <stdio.h>int main()
{char buf[1024];int ret = read(0,buf,128);if(ret >1)write(1,"Read success\n",13);if(ret == 0)write(1,"End of file\n",12);if(ret =-1)write(1,"Read error\n",10);write(1,"Read data:",10);write(1,buf,ret);exit(0);
}
输出
2.3 open函数
- 参数:
pathname
:要打开的文件路径。flags
:打开文件的方式和标志,可以是以下常量的组合:O_RDONLY
、O_WRONLY
、O_RDWR
、O_CREAT
、O_TRUNC
等。mode
:创建文件时的权限,仅当O_CREAT
被指定时有效。
- 返回值:
- 若成功,则返回文件描述符(非负整数),表示打开的文件。
- 若失败,则返回-1,并设置errno。
- 作用:用于打开文件。
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
例子
创建一个可读可写文件;
#include <fcntl.h>
#include <unistd.h>
#inc;ude <stdio.h>int main()
{int fd = open("test.txt",O_RDWR|O_CREAT,S_IWUSR|S_IRUSR);write(fd,"Hello world\n",12);close(fd);exit(0);
}
输出
2.4 close函数
- 参数:
fd
:要关闭的文件描述符。
- 返回值:
- 若成功,则返回0。
- 若失败,则返回-1,并设置errno。
- 作用:用于关闭一个已打开的文件描述符
#include <unistd.h>
int close(int fd);
例子
#include <fcntl.h>
#include <unistd.h>
#inc;ude <stdio.h>int main()
{int fd = open("test.txt",O_RDWR|O_CREAT,S_IWUSR|S_IRUSR);write(fd,"Hello world\n",12);close(fd);exit(0);
}
2.5 lseek函数
- 参数:
fd
:要定位的文件描述符。offset
:偏移量。whence
:起始位置,可以是SEEK_SET
、SEEK_CUR
、SEEK_END
。
- 返回值:
- 若成功,则返回新的文件偏移量。
- 若失败,则返回-1,并设置errno。
- 作用:移动文件描述符的读写位置。
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
例子
当前位置偏移5个字节
#include<fcntl.h>
#include <unistd.h>
#include <stdio.h>int main()
{char buf[1024];int ret;int fd = open("test.txt",O_RDWR);lseek(fd,5,SEEK_CUR);if((ret = read(fd,buf,128))<1){write(2,"Read error\n",11);}write(1,"Data read after movement:",25);write(1,buf,ret);}
输出
2.6 ioctl函数
- 参数:
fd
:文件描述符。request
:请求代码。...
:根据请求代码可能需要的额外参数。
- 返回值:
- 根据不同的请求代码和操作可能返回不同的值。
- 作用:对设备进行各种控制操作,例如设置设备参数等。
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
例子
获取终端长宽
#include<stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>int main()
{struct winsize ws;if(ioctl(STDOUT_FILENO<TIOCGWINSZ,&WS)== -1){write(2,"Error\n",6);} printf("Terminal windows size: %d rows x %d columns\n",ws.ws_row,ws_col);return 0;
}
输出
2.7 fcntl()函数
- 参数:
fd
:文件描述符。cmd
:命令类型。arg
:根据不同的命令类型可能需要的额外参数。
- 返回值:
- 根据不同的命令类型和操作可能返回不同的值。
- 作用:提供了对文件描述符更加灵活的控制能力,可以用于实现各种高级的文件操作,如非阻塞IO、文件锁、文件描述符的异步通知。暂时先了解
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
2.8 pread()函数
- 参数和返回值同
read()
函数,但可以指定读取文件的偏移量。 - 作用:类似于read(),但可以指定读取文件的偏移量。
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
2.9 pwrite()函数
- 参数和返回值同
write()
函数,但可以指定写入文件的偏移量。 - 作用:类似于write(),但可以指定写入文件的偏移量。
#include <unistd.h>
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);