Linux系统编程之文件操作(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;
}
原文链接:,转发请注明来源!