Linux下的文件I/O(Input/Output,输入/输出)是指在Linux操作系统中进行文件读取和写入操作的过程。这是在计算机程序中常见的一项任务,用于与磁盘文件或其他I/O设备(如键盘、屏幕、网络套接字等)交互。文件I/O通常是通过文件描述符(file descriptor)来完成的,它是一个整数,用于标识打开的文件或其他I/O资源。以下是关于Linux文件I/O的详细解释:
文件描述符
在 Linux 中,文件 I/O 通过文件描述符来实现。文件描述符是一个非负整数,用于唯一标识一个打开的文件。通常,文件描述符 0 表示标准输入(stdin),文件描述符 1 表示标准输出(stdout),文件描述符 2 表示标准错误(stderr)。
通过系统调用函数 open(),可以打开或创建文件,并获得一个文件描述符来引用该文件。例如,int fd = open("example.txt", O_WRONLY | O_CREAT, 0644); 打开名为 "example.txt" 的文件以供写入,并返回文件描述符 fd。
open( )
描述:open() 函数用于打开文件或创建新文件,并返回一个文件描述符,以便后续对文件的操作。
参数:int open(const char *pathname, int flags, mode_t mode);
const char *pathname:要打开或创建的文件的路径和名称。
int flags:用于指定文件操作模式,如只读、只写、读写、追加等。可以使用位掩码进行组合。
mode_t mode:只有在创建新文件时才使用,用于指定文件的权限(例如,读、写、执行权限)。
返回值:成功时返回一个文件描述符(非负整数),表示已打开的文件。如果出现错误,返回值为 -1。如果 open() 返回 -1,可以使用 errno 全局变量来确定错误类型,并采取适当的措施。
示例:
打开已存在的文件:int fd = open("example.txt", O_RDONLY);
创建新文件:int fd = open("newfile.txt", O_WRONLY | O_CREAT, 0644);
附加写入文件:int fd = open("example.txt", O_WRONLY | O_APPEND);
同时读写文件:int fd = open("data.txt", O_RDWR);
设置文件权限:int fd = open("newfile.txt", O_WRONLY | O_CREAT, 0644);
close( )
描述:close() 函数用于关闭已打开的文件,释放与文件描述符相关的资源。
参数:int close(int fd);
int fd:要关闭的文件描述符。
返回值:成功时返回 0,失败时返回 -1。
示例:
关闭文件描述符:int result = close(fd);
read( )
描述:read() 函数用于从已打开的文件中读取数据。
参数:ssize_t read(int fd, void *buf, size_t count);
int fd:要从中读取数据的文件描述符。
void *buf:用于存储读取数据的缓冲区。
size_t count:要读取的字节数。
返回值:当 read() 返回值为 0 时,表示已经读取到文件的末尾。这是通常发生在读取到文件的最后一部分数据后。在使用 read() 函数时,应该检查其返回值以处理可能的错误情况。如果 read() 返回 -1,可以使用 errno 全局变量来确定错误类型。例如,常见的错误类型包括 EINTR(读操作被中断)、EIO(I/O 错误)、EAGAIN(非阻塞模式下没有数据可读)等。如果文件描述符处于非阻塞模式,并且没有可用的数据可读,read() 可能会立即返回 -1,并设置 errno 为 EAGAIN 或 EWOULDBLOCK。
示例:
从文件读取数据:char buffer[1024]; ssize_t bytesRead = read(fd, buffer, sizeof(buffer));
write( )
描述:write() 函数用于将数据写入已打开的文件。
参数:ssize_t write(int fd, const void *buf, size_t count);
int fd:要写入数据的文件描述符。
const void *buf:包含要写入的数据的缓冲区。
size_t count:要写入的字节数。
返回值:在使用 write() 函数时,应该检查其返回值以处理可能的错误情况。如果 write() 返回 -1,可以使用 errno 全局变量来确定错误类型。常见的错误类型包括 EINTR(写操作被中断)、EIO(I/O 错误)、ENOSPC(磁盘空间不足)等。如果文件描述符处于非阻塞模式,并且无法立即写入数据,write() 可能会立即返回 -1,并设置 errno 为 EAGAIN 或 EWOULDBLOCK。
示例:ssize_t write(int fd, const void *buf, size_t count);
向文件写入数据:char buffer[] = "Hello, World!"; ssize_t bytesWritten = write(fd, buffer, sizeof(buffer) - 1);
lseek( )
描述:lseek() 函数用于移动文件指针到指定位置,以便进行随机访问文件。
参数:off_t lseek(int fd, off_t offset, int whence);
int fd:要操作的文件描述符。
off_t offset:偏移量,表示要移动的字节数。
int whence:起始位置,可以是 SEEK_SET(文件开头)、SEEK_CUR(当前位置)、SEEK_END(文件末尾)之一。
返回值:当使用 lseek() 函数时,应该检查其返回值以处理可能的错误情况。如果 lseek() 返回 -1,可以使用 errno 全局变量来确定错误类型。常见的错误类型包括 EINVAL(无效的参数)、ESPIPE(不支持 lseek() 的文件描述符)等。
示例:
移动文件指针:off_t newOffset = lseek(fd, 0, SEEK_SET);
获取文件大小:off_t fileSize = lseek(fd, 0, SEEK_END);
fcntl( )
描述:用于获取文件描述符 fd 的状态标志。返回的标志可以包括 O_RDONLY、O_WRONLY、O_RDWR、O_APPEND、O_NONBLOCK 等。
参数:int fcntl(int fd, int cmd, ... /* arg */);
int fd:要操作的文件描述符。
int cmd:要执行的命令,用于指定操作类型。
...:可选参数,根据不同的命令可能需要额外参数。
返回值:根据不同的命令和操作类型,返回不同的值。
示例:
获取文件状态标志:int flags = fcntl(fd, F_GETFL);
设置文件状态标志:int result = fcntl(fd, F_SETFL, new_flags);
获取文件描述符标志:int fd_flags = fcntl(fd, F_GETFD);
设置文件描述符标志:int result = fcntl(fd, F_SETFD, new_fd_flags);
ioctl( )
描述:ioctl() 函数用于执行与设备或文件描述符相关的控制操作,通常在特殊设备文件上使用。
参数:int ioctl(int fd, unsigned long request, ...);
int fd:要操作的文件描述符。
int request:要执行的控制命令。
...:可选参数,根据不同的命令可能需要额外参数。
返回值:在使用 ioctl() 函数时,应检查其返回值以处理可能的错误情况。如果 ioctl() 返回 -1,可以使用 errno 全局变量来确定错误类型。
示例:ioctl() 函数的使用方式取决于所执行的具体命令和操作类型,因此示例的代码会因命令而异。
dup( )和dup2( )
描述:dup() 函数用于复制文件描述符,创建一个新的文件描述符,该新文件描述符引用与原始文件描述符相同的文件。dup2() 函数还允许指定新文件描述符的值。
参数:
int oldfd:要复制的文件描述符。
int newfd:dup2() 中的新文件描述符,可以指定。
返回值:成功时返回新的文件描述符,失败时返回 -1。
示例:
dup() 函数的作用是复制 oldfd 的文件描述符,然后返回一个新的文件描述符,这个新文件描述符和 oldfd 引用相同的文件或设备。新文件描述符是操作系统中未使用的最小文件描述符值。
dup2() 函数的作用是将 oldfd 的文件描述符复制到 newfd,如果 newfd 已经打开,那么它将首先关闭 newfd,然后将 oldfd 复制到 newfd。这可以用于将文件描述符重定向到指定的文件或标准输入/输出。
unlink( )
描述:unlink() 函数用于删除文件,即从文件系统中移除文件的目录项。文件将被删除,但如果有其他文件描述符仍然打开它,数据仍然可以被访问。
参数:int unlink(const char *pathname);
const char *pathname:要删除的文件的路径和名称。
返回值:unlink() 返回 -1,可以使用 errno 全局变量来确定错误类型。常见的错误类型包括 ENOENT(文件或目录不存在)、EACCES(权限不足)、EISDIR(试图删除目录而不是文件)等。
示例:
删除文件:要删除文件,可以使用 unlink() 函数并传递文件的路径名作为参数。
删除目录:在使用 unlink() 函数时,应该检查其返回值以处理可能的错误情况。
总之,文件I/O是Linux系统编程中的基础操作之一,它允许程序读取和写入文件,与文件系统进行交互,并且是许多应用程序和工具的核心部分。正确地处理文件I/O操作对于编写高效、可靠的Linux应用程序至关重要。
领取专属 10元无门槛券
私享最新 技术干货