Linux系统编程之文件操作

概述

在Linux系统中,文件操作是一项基本而又重要的任务,主要依赖于系统调用。系统调用是操作系统提供的底层接口,允许用户程序直接与内核进行通信。常用的文件操作包括:打开文件、关闭文件、读取文件、写入文件、文件定位等。下面,我们分别进行介绍。

打开文件

open函数用于打开或创建文件,并设置相应的访问模式和权限。其函数原型如下。

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

pathname:文件路径,可以是绝对路径或相对路径。
flags:打开文件的模式,常见的标志位如下。
(1)O_RDONLY:只读模式。
(2)O_WRONLY:只写模式。
(3)O_RDWR:读写模式。
(4)O_CREAT:如果文件不存在,则创建文件。
(5)O_EXCL:与O_CREAT一起使用,如果文件已存在,则调用失败。
(6)O_TRUNC:如果文件已存在且为常规文件,则将其长度截断为0。
(7)O_APPEND:每次写入时,文件指针都会移动到文件末尾。
mode:文件权限,仅在创建新文件时使用。权限可以用八进制表示,常见的权限值包括:
(1)0644:所有者可读写,其他用户只读。
(2)0755:所有者可读写执行,其他用户可读执行。
返回值:成功时,返回一个非负整数,称为文件描述符,用于后续的文件操作。失败时,返回-1,并设置errno为适当的错误码。常见的错误码如下。
(1)EACCES:权限不足。
(2)EEXIST:文件已存在(当使用O_CREAT和O_EXCL 标志时)。
(3)ENOENT:文件或路径不存在。
(4)ENOMEM:内存不足。
(5)ENFILE:系统文件表已满。
(6)EMFILE:进程已达到文件描述符限制。

关闭文件

close函数用于关闭之前打开的文件,并释放系统资源。其函数原型如下。

int close(int fd);

fd:要关闭的文件描述符,通常为调用open或其他文件打开函数时返回的非负整数。
返回值:成功时,返回0。失败时,返回-1。
注意:打开的文件应及时关闭,以释放系统资源。忘记关闭文件可能会导致文件描述符耗尽,影响程序的性能和稳定性。

读取文件

read函数用于从文件描述符中读取数据,其函数原型如下。

ssize_t read(int fd, void *buf, size_t count);

fd:要读取的文件描述符。
buf:存放读取数据的缓冲区。
count:要读取的最大字节数。
返回值:成功时,返回实际读取的字节数。如果读取到文件末尾,返回0。失败时,返回-1,并设置errno为适当的错误码。常见的错误码如下。
(1)EBADF:文件描述符无效。
(2)EINTR:系统调用被信号中断。
(3)EIO:发生I/O错误。
(4)EFAULT:缓冲区地址无效。

写入文件

write函数用于将数据写入文件描述符,其函数原型如下。

ssize_t write(int fd, const void *buf, size_t count);

fd:要写入的文件描述符。
buf:指向要写入的数据缓冲区的指针。
count:要写入的字节数。
返回值:成功时,返回实际写入的字节数。失败时,返回-1,并设置errno为适当的错误码。常见的错误码如下。
(1)EBADF:文件描述符无效。
(2)EINTR:系统调用被信号中断。
(3)EIO:发生I/O错误。
(4)EFAULT:缓冲区地址无效。
(5)ENOSPC:磁盘空间不足。

文件定位

lseek函数用于移动文件指针到指定位置,移动后,可从该位置继续读写文件。其函数原型如下。

off_t lseek(int fd, off_t offset, int whence);

fd:要操作的文件描述符。
offset:相对于whence的偏移量。
whence:移动方式,常见的取值如下。
(1)SEEK_SET:从文件开头开始计算偏移量。
(2)SEEK_CUR:从当前文件指针位置开始计算偏移量。
(3)SEEK_END:从文件末尾开始计算偏移量。
返回值:成功时,返回新的文件指针位置,以字节为单位。失败时,返回-1,并设置errno为适当的错误码。常见的错误码如下。
(1)EBADF:文件描述符无效。
(2)EINVAL:无效的whence值。
(3)ESPIPE:文件描述符不支持定位操作。

实战代码

下面的实战代码展示了如何进行文件的基本操作,包括上面介绍的打开文件、关闭文件、读取文件、写入文件和文件定位。
首先,我们使用open函数以读写模式打开或创建文件hope_wisdom.txt。如果文件不存在,则创建,并设置文件权限为0644。如果打开文件失败,则使用perror输出错误信息并退出程序。
接下来,使用write函数将字符串写入文件,写入的字节数为字符串的长度。如果写入失败,使用perror输出错误信息并关闭文件后退出程序。成功写入后,输出写入的字节数。
然后,使用lseek函数将文件指针移动到文件开头。成功移动后,输出文件指针已移动到文件开头的信息。
紧接着,定义一个缓冲区buffer,并清空缓冲区。使用read函数从文件中读取数据到缓冲区,最多读取缓冲区大小 - 1个字节。成功读取后,输出读取的字节数和读取的内容。
最后,我们使用close函数关闭文件描述符。成功关闭文件后,输出文件已关闭的信息。

#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>

using namespace std;

int main()
{
    // 打开文件,读写模式,如果文件不存在则创建
    int fd = open("hope_wisdom.txt", O_RDWR | O_CREAT, 0644);
    if (fd == -1)
    {
        perror("open");
        return EXIT_FAILURE;
    }

    cout << "File opened: " << fd << endl;

    // 写入文件内容
    const char *pszContent = "Hello, World!\n";
    ssize_t bytes_written = write(fd, pszContent, strlen(pszContent));
    if (bytes_written == -1)
    {
        perror("write");
        close(fd);
        return EXIT_FAILURE;
    }

    cout << "Write " << bytes_written << " bytes to file" << endl;

    // 移动文件指针到文件开头
    off_t offset = lseek(fd, 0, SEEK_SET);
    if (offset == -1)
    {
        perror("lseek");
        close(fd);
        return EXIT_FAILURE;
    }

    cout << "File pointer moved to the beginning" << endl;

    // 读取文件内容
    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
    if (bytes_read == -1)
    {
        perror("read");
        close(fd);
        return EXIT_FAILURE;
    }

    cout << "Read " << bytes_read << " bytes from file: " << buffer << endl;

    // 关闭文件
    if (close(fd) == -1)
    {
        perror("close");
        return EXIT_FAILURE;
    }

    cout << "File closed" << endl;
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容