在Linux系统编程中,文件IO操作是非常常见和重要的操作之一。通过文件IO操作,我们可以打开、读取、写入和关闭文件,对文件进行定位、复制、删除和重命名等操作。本篇博客将介绍一些常用的文件IO操作函数。
文章目录
- 1. open()
- 1.1 原型、参数及返回值说明
- 1.1.1 原型:
- 1.1.2 参数说明:
- 1.1.3 返回值:
- 1.2 函数示例
- 1.3 代码解释
- 2. close()
- 2.1 原型、参数及返回值说明
- 2.1.1 原型:
- 2.1.2 参数:
- 2.1.3 返回值:
- 2.2 函数示例
- 2.3 代码解释
- 3. read()
- 3.1 原型、参数及返回值说明
- 3.1.1 原型:
- 3.1.2 参数:
- 3.1.3 返回值:
- 3.2 函数示例
- 3.3 代码解释
- 4. write()
- 4.1 原型、参数及返回值说明
- 4.1.1 原型:
- 4.1.2 参数:
- 4.1.3 返回值:
- 4.2 函数示例
- 4.3 代码解释
- 5. lseek()
- 5.1 原型、参数及返回值说明
- 5.1.1 原型:
- 5.1.2 参数:
- 5.1.3 返回值:
- 5.2 函数示例
- 5.3 代码解释
- 6. stat()
- 6.1 原型、参数及返回值说明
- 6.1.1 原型:
- 6.1.2 参数:
- 6.1.3 返回值:
- 6.2 函数示例
- 6.3 代码解释
- 7. fcntl()
- 7.1 原型、参数及返回值说明
- 7.1.1 原型:
- 7.1.2 参数:
- 7.1.3 返回值:
- 7.2 函数示例
- 7.3 代码解释
- 总结
1. open()
1.1 原型、参数及返回值说明
1.1.1 原型:
open()函数是Linux系统编程中常用的文件IO操作函数之一。它用于打开文件并返回一个文件描述符,以便后续的文件读写操作。
open()函数的原型如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags, mode_t mode);
1.1.2 参数说明:
pathname
:要打开的文件路径名。flags
:打开文件的模式标志,可以是以下几种模式的组合:O_RDONLY
:只读模式打开文件。O_WRONLY
:只写模式打开文件。O_RDWR
:读写模式打开文件。O_CREAT
:如果文件不存在,则创建文件。O_EXCL
:与O_CREAT一同使用,如果文件已存在,则返回错误。O_TRUNC
:如果文件存在且以可写模式打开,则将文件截断为0。O_APPEND
:在文件末尾追加数据。
mode
: 创建文件时的访问权限,只有在使用O_CREAT时才有效。
可以使用如下几个宏来设置权限:- S_IRUSR:用户读权限。
- S_IWUSR:用户写权限。
- S_IXUSR:用户执行权限。
- S_IRGRP:组读权限。
- S_IWGRP:组写权限。
- S_IXGRP:组执行权限。
- S_IROTH:其他用户读权限。
- S_IWOTH:其他用户写权限。
- S_IXOTH:其他用户执行权限。
1.1.3 返回值:
- 成功:返回一个非负整数的文件描述符,用于后续的文件IO操作。
- 失败:返回-1,并设置errno变量来指示错误类型。
1.2 函数示例
下面是一个使用open()函数的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>int main() {int fd;// 打开文件fd = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);if (fd == -1) {perror("open");return errno;}// 写入数据char buffer[] = "Hello, world!";ssize_t ret = write(fd, buffer, sizeof(buffer) - 1);if (ret == -1) {perror("write");close(fd);return errno;}// 关闭文件close(fd);return 0;
}
1.3 代码解释
在上述示例中,我们首先使用open()函数以只写模式打开一个文件example.txt。如果文件不存在,则创建该文件,并设置访问权限为用户可读可写。如果打开文件失败,我们使用perror()函数打印错误信息,并返回errno变量。
接下来,我们使用write()函数向文件中写入数据。在本例中,我们写入了字符串"Hello, world!"。如果写入数据失败,我们同样使用perror()函数打印错误信息,并在关闭文件前返回errno变量。
最后,我们使用close()函数关闭文件。
2. close()
2.1 原型、参数及返回值说明
2.1.1 原型:
close()函数是Linux系统编程中用于关闭文件的函数。它接受一个文件描述符作为参数,并返回一个整数值来指示操作是否成功。
close()函数的原型如下:
#include <unistd.h>int close(int fd);
2.1.2 参数:
fd
:要关闭的文件描述符。
2.1.3 返回值:
- 成功:返回0。
- 失败:返回-1,并设置
errno
变量来指示错误类型。
2.2 函数示例
下面是一个使用close()函数的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>int main() {int fd;// 打开文件fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("open");return errno;}// 关闭文件int ret = close(fd);if (ret == -1) {perror("close");return errno;}return 0;
}
2.3 代码解释
在上述示例中,我们首先使用open()
函数以只读模式打开一个文件example.txt
,并将返回的文件描述符存储在变量fd
中。如果打开文件失败,我们使用perror()
函数打印错误信息,并返回errno
变量。
接下来,我们使用close()
函数关闭文件。如果关闭文件失败,我们同样使用perror()
函数打印错误信息,并返回errno
变量。
需要注意的是,关闭文件后,我们不应再对该文件描述符进行任何操作。
3. read()
3.1 原型、参数及返回值说明
3.1.1 原型:
read()函数是Linux系统编程中用于从文件中读取数据的函数。它接受一个文件描述符、一个缓冲区地址和一个读取的最大字节数作为参数,并返回实际读取的字节数。
read()函数的原型如下:
#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
3.1.2 参数:
fd
:要读取的文件的文件描述符。buf
:用于存储读取数据的缓冲区的地址。count
:要读取的最大字节数。
3.1.3 返回值:
- 成功:返回实际读取的字节数。
- 失败:返回
-1
,并设置errno
变量来指示错误类型。
3.2 函数示例
下面是一个使用read()函数的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>int main() {int fd;// 打开文件fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("open");return errno;}// 读取数据char buffer[100];ssize_t ret = read(fd, buffer, sizeof(buffer));if (ret == -1) {perror("read");close(fd);return errno;}// 输出读取的数据printf("Read %ld bytes: %s\n", ret, buffer);// 关闭文件close(fd);return 0;
}
3.3 代码解释
在上述示例中,我们首先使用open()
函数以只读模式打开一个文件example.txt
,并将返回的文件描述符存储在变量fd
中。如果打开文件失败,我们使用perror()
函数打印错误信息,并返回errno
变量。
接下来,我们使用read()
函数从文件中读取数据。我们定义一个长度为100的缓冲区buffer
,并将其作为参数传递给read()
函数。read()
函数将尽量读取count
个字节的数据,并将其存储在缓冲区中。如果读取数据失败,我们同样使用perror()
函数打印错误信息,并在关闭文件前返回errno
变量。
最后,我们使用printf()
函数输出读取的数据,并使用close()
函数关闭文件。
需要注意的是,read()函数是一个阻塞函数,如果文件中没有足够的数据可读,它将一直等待直到有足够的数据可读或者发生错误。如果需要非阻塞地读取数据,可以使用fcntl()函数设置文件描述符为非阻塞模式。
4. write()
4.1 原型、参数及返回值说明
4.1.1 原型:
write()函数是Linux系统编程中用于向文件中写入数据的函数。它接受一个文件描述符、一个数据缓冲区地址和要写入的字节数作为参数,并返回实际写入的字节数。
write()函数的原型如下:
#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);
4.1.2 参数:
fd
:要写入的文件的文件描述符。buf
:要写入的数据的缓冲区的地址。count
:要写入的字节数。
4.1.3 返回值:
- 成功:返回实际写入的字节数。
- 失败:返回
-1
,并设置errno
变量来指示错误类型。
4.2 函数示例
下面是一个使用write()函数的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>int main() {int fd;// 打开文件fd = open("example.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);if (fd == -1) {perror("open");return errno;}// 写入数据char buffer[] = "Hello, World!";ssize_t ret = write(fd, buffer, sizeof(buffer) - 1);if (ret == -1) {perror("write");close(fd);return errno;}// 关闭文件close(fd);return 0;
}
4.3 代码解释
在上述示例中,我们首先使用open()
函数以只写模式打开一个文件example.txt
,并将返回的文件描述符存储在变量fd
中。如果打开文件失败,我们使用perror()
函数打印错误信息,并返回errno
变量。
接下来,我们使用write()
函数将数据写入文件中。我们定义一个字符串buffer
,并将其作为参数传递给write()
函数。write()
函数将尽量写入count
个字节的数据到文件中。如果写入数据失败,我们同样使用perror()
函数打印错误信息,并在关闭文件前返回errno
变量。
最后,我们使用close()
函数关闭文件。
需要注意的是,write()函数是一个阻塞函数,如果文件无法立即接受写入的数据(例如,磁盘空间不足),它将一直等待直到可以写入数据或者发生错误。如果需要非阻塞地写入数据,可以使用fcntl()函数设置文件描述符为非阻塞模式。
5. lseek()
5.1 原型、参数及返回值说明
5.1.1 原型:
lseek()函数是Linux系统编程中用于在文件中定位读写位置的函数。它接受一个文件描述符、一个偏移量和一个起始位置作为参数,并返回新的读写位置。
lseek()函数的原型如下:
#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
5.1.2 参数:
fd
:要定位的文件的文件描述符。offset
:偏移量,可以是正数、负数或零。whence
:起始位置,可以取以下三个值:SEEK_SET
:从文件开头开始计算偏移量。SEEK_CUR
:从当前读写位置开始计算偏移量。SEEK_END
:从文件末尾开始计算偏移量。
5.1.3 返回值:
- 成功:返回新的读写位置。
- 失败:返回
-1
,并设置errno
变量来指示错误类型。
5.2 函数示例
下面是一个使用lseek()函数的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>int main() {int fd;// 打开文件fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("open");return errno;}// 定位读写位置off_t ret = lseek(fd, 5, SEEK_SET);if (ret == -1) {perror("lseek");close(fd);return errno;}// 读取数据char buffer[10];ssize_t n = read(fd, buffer, sizeof(buffer) - 1);if (n == -1) {perror("read");close(fd);return errno;}buffer[n] = '\0';printf("Data: %s\n", buffer);// 关闭文件close(fd);return 0;
}
5.3 代码解释
在上述示例中,我们首先使用open()
函数以只读模式打开一个文件example.txt
,并将返回的文件描述符存储在变量fd
中。如果打开文件失败,我们使用perror()
函数打印错误信息,并返回errno
变量。
接下来,我们使用lseek()
函数将读写位置定位到文件开头后的第5个字节。我们将文件描述符、偏移量和起始位置作为参数传递给lseek()
函数。如果定位读写位置失败,我们同样使用perror()
函数打印错误信息,并在关闭文件前返回errno
变量。
然后,我们使用read()
函数从文件中读取数据。我们定义一个缓冲区buffer
,并将其作为参数传递给read()
函数。read()
函数将尽量读取count
个字节的数据到缓冲区中。如果读取数据失败,我们同样使用perror()
函数打印错误信息,并在关闭文件前返回errno
变量。最后,我们在缓冲区末尾添加一个空字符,并使用printf()
函数打印读取到的数据。
最后,我们使用close()
函数关闭文件。
需要注意的是,lseek()函数可以用于定位读写位置,但并不会改变文件的大小。如果需要改变文件的大小,可以使用truncate()函数或ftruncate()函数。
6. stat()
6.1 原型、参数及返回值说明
6.1.1 原型:
stat()函数是Linux系统编程中用于获取文件信息的函数。它接受一个文件路径作为参数,并返回一个包含文件信息的结构体。
stat()函数的原型如下:
#include <sys/types.h>
#include <sys/stat.h>int stat(const char *pathname, struct stat *buf);
6.1.2 参数:
pathname
:要获取信息的文件路径。buf
:用于存储文件信息的结构体指针。
6.1.3 返回值:
- 成功:返回0。
- 失败:返回
-1
,并设置errno
变量来指示错误类型。
struct stat
结构体包含了文件的各种信息,包括文件类型、权限、大小、创建时间、修改时间等。
下面是struct stat结构体的定义:
struct stat {dev_t st_dev; // 文件所在设备的IDino_t st_ino; // 文件的inode号mode_t st_mode; // 文件的类型和权限nlink_t st_nlink; // 文件的硬链接数uid_t st_uid; // 文件的所有者IDgid_t st_gid; // 文件的所有者组IDdev_t st_rdev; // 如果文件是设备文件,则为设备的IDoff_t st_size; // 文件的大小(字节)blksize_t st_blksize; // 文件系统的块大小blkcnt_t st_blocks; // 分配给文件的块数time_t st_atime; // 文件的最后访问时间time_t st_mtime; // 文件的最后修改时间time_t st_ctime; // 文件的最后状态改变时间
};
6.2 函数示例
下面是一个使用stat()函数的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>int main() {const char *pathname = "example.txt";struct stat file_info;// 获取文件信息int ret = stat(pathname, &file_info);if (ret == -1) {perror("stat");return errno;}// 打印文件信息printf("File Size: %ld bytes\n", file_info.st_size);printf("File Permissions: %o\n", file_info.st_mode & 0777);printf("File Owner UID: %d\n", file_info.st_uid);printf("File Owner GID: %d\n", file_info.st_gid);return 0;
}
6.3 代码解释
在上述示例中,我们首先定义了一个文件路径pathname
和一个struct stat
结构体file_info
,用于存储获取到的文件信息。
然后,我们使用stat()
函数将文件信息存储到file_info
结构体中。我们将文件路径和file_info
结构体指针作为参数传递给stat()
函数。如果获取文件信息失败,我们使用perror()
函数打印错误信息,并返回errno
变量。
最后,我们使用printf()
函数打印获取到的文件信息,包括文件大小、文件权限、文件所有者的UID
和GID
等。
需要注意的是,stat()函数只能获取文件的信息,而不能修改文件的信息。如果需要修改文件的信息,可以使用chmod()函数来修改文件的权限。
7. fcntl()
7.1 原型、参数及返回值说明
7.1.1 原型:
fcntl()函数是Linux系统编程中用于对文件描述符进行控制操作的函数。它可以用于设置文件状态标志、获取文件状态标志、设置文件锁等。
fcntl()函数的原型如下:
#include <fcntl.h>int fcntl(int fd, int cmd, ... /* arg */ );
7.1.2 参数:
fd
:文件描述符,可以是打开文件的文件描述符,也可以是套接字的文件描述符。cmd
:控制命令,用于指定要执行的操作。arg
:可选参数,用于传递特定操作的参数。
7.1.3 返回值:
- 成功:根据不同的操作命令返回不同的值,一般为0或一个正整数。
- 失败:返回
-1
,并设置errno
变量来指示错误类型。
下面是fcntl()函数的一些常用命令:
F_DUPFD
:复制文件描述符,创建一个新的文件描述符,该描述符与原始描述符指向相同的打开文件。F_GETFD
:获取文件描述符的文件状态标志。F_SETFD
:设置文件描述符的文件状态标志。F_GETFL
:获取文件的打开方式和状态标志。F_SETFL
:设置文件的打开方式和状态标志。F_GETLK
:获取文件锁的信息。F_SETLK
:设置文件锁。F_SETLKW
:设置文件锁,如果无法获取锁,则阻塞等待。
7.2 函数示例
下面是一个使用fcntl()函数的示例:
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>int main() {int fd = open("example.txt", O_RDWR);if (fd == -1) {perror("open");return errno;}// 获取文件的打开方式和状态标志int flags = fcntl(fd, F_GETFL);if (flags == -1) {perror("fcntl");return errno;}// 设置文件的状态标志为非阻塞flags |= O_NONBLOCK;int ret = fcntl(fd, F_SETFL, flags);if (ret == -1) {perror("fcntl");return errno;}// 关闭文件描述符close(fd);return 0;
}
7.3 代码解释
在上述示例中,我们首先使用open()
函数打开一个文件,并将返回的文件描述符存储在变量fd中。如果打开文件失败,我们使用perror()
函数打印错误信息,并返回errno
变量。
然后,我们使用fcntl()
函数获取文件的打开方式和状态标志。将文件描述符和F_GETFL
命令作为参数传递给fcntl()
函数,获取到的文件状态标志存储在变量flags
中。如果获取文件状态标志失败,我们同样使用perror()
函数打印错误信息,并返回errno
变量。
接下来,我们将文件的状态标志设置为非阻塞,通过将O_NONBLOCK
标志位与flags
进行按位或操作。然后,我们使用fcntl()
函数将修改后的状态标志设置回文件描述符。将文件描述符、F_SETFL
命令和修改后的状态标志作为参数传递给fcntl()
函数。如果设置文件状态标志失败,我们同样使用perror()
函数打印错误信息,并返回errno
变量。
最后,我们使用close()
函数关闭文件描述符,释放资源。
需要注意的是,fcntl()函数的使用非常灵活,可以根据需要进行各种操作,如复制文件描述符、获取文件锁等。在使用fcntl()函数时,需要注意错误处理,并确保文件描述符的有效性。同时,需要在不再需要使用文件描述符时及时关闭文件描述符,以释放资源并避免资源泄漏。
总结
文件IO操作是Linux系统编程中的重要部分。通过open()
、close()
、read()
、write()
等函数,我们可以对文件进行打开、读取和写入操作。通过lseek()
函数,我们可以在文件中进行定位。而通过stat()
、fcntl()
、dup()
等函数,我们可以获取文件的状态信息,对文件描述符进行控制操作,复制文件描述符等。
除了上述的函数,还有许多其他的函数可以用于文件IO操作,如mkdir()
用于创建目录,rmdir()
用于删除目录,unlink()
用于删除文件,rename()
用于重命名文件等。