【探索Linux】—— 强大的命令行工具 P.11(基础IO,文件操作)

在这里插入图片描述

前言

前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim 、gcc/g++ 使用、yum工具以及git 命令行提交代码也相信大家都掌握的不错,上一篇文章我们了解了关于进程的地址空间,今天博主带大家了解一下 —— 基础IO,文件操作, 下面话不多说坐稳扶好咱们要开车了!!!?

一、C语言的文件操作

⭕详细可见: C语言中的文件操作指南

C语言提供了标准库函数来进行文件操作,主要使用头文件 <stdio.h>

以下是常见的文件操作函数及其用途

函数 作用
FILE fopen(const char path, const char* mode) 打开文件并返回指向文件的指针
int fclose(FILE *stream) 关闭文件
int fputc(int c, FILE *stream) 将一个字符写入文件
int fgetc(FILE *stream) 从文件中读取一个字符
char *fgets(char *s, int size, FILE *stream) 从文件中读取一行内容,并存储到字符串 s 中
int fputs(const char *s, FILE *stream) 将字符串 s 写入文件
size_t fread(void *ptr, size_t size, size_t count, FILE *stream) 从文件中读取二进制数据
size_t fwrite(void *ptr, size_t size, size_t count, FILE *stream) 向文件中写入二进制数据
int fseek(FILE *stream, long offset, int whence) 设置文件指针偏移量,用于定位读写位置
long ftell(FILE *stream) 返回当前文件指针的位置
void rewind(FILE *stream) 将文件指针重置到文件开头
int feof(FILE *stream) 检测是否到达文件末尾

其中,path 是文件路径,mode 表示打开文件的模式,可以是以下值之一:

模式 含义
“r” 只读模式,打开文件用于读取
“w” 写入模式,打开文件用于写入(清除文件中的原有内容)
“a” 添加模式,打开文件用于追加数据
“rb” 二进制读取模式
“wb” 二进制写入模式

fputcfgetc 函数用于单个字符的读写,fgetsfputs 函数用于字符串的读写。freadfwrite 函数用于二进制数据的读写。

fseek 函数用于指定读写位置,ftell 函数用于获取当前文件指针的位置,rewind 函数用于将文件指针重置到文件开头。feof 函数用于检测是否到达文件末尾。

注意,在进行文件操作时,需要先打开文件,使用完毕后再关闭文件,否则可能导致资源泄漏或操作失败。

文件操作需要注意以下几点:

  1. 操作文件之前,需要先打开文件。在使用完文件后,必须关闭文件,释放资源。

  2. 文件指针可以用来读写文件中的内容。在进行读写操作时,需要根据文件指针指向的位置进行读写,可以使用 fseek 函数来进行定位。

  3. 在进行写操作时,如果文件不存在,则会创建一个新的文件。如果文件已经存在,那么文件将被打开,并覆盖原有的内容。

  4. 在进行读操作时,需要判断是否已经到达文件末尾,通常使用 feof 函数来进行判断。

二、C++的文件操作

C++提供了一组文件操作的标准库函数,可以用于打开、读取、写入和关闭文件。下面是一些常用的文件操作函数的介绍:

  1. 打开文件:
    可以使用std::ifstreamstd::ofstream来打开输入和输出文件流。例如:
#include <fstream>

std::ifstream inFile("input.txt"); // 打开输入文件
std::ofstream outFile("output.txt"); // 打开输出文件
  1. 读取文件内容:
    可以使用>>运算符从文件中读取数据。例如:
int num;
inFile >> num; // 从输入文件中读取一个整数到变量num中

也可以使用getline函数逐行读取文件内容。例如:

std::string line;
while (std::getline(inFile, line)) {
    // 处理每一行的内容
}
  1. 写入文件内容:
    可以使用<<运算符将数据写入文件。例如:
int num = 42;
outFile << "The answer is: " << num << std::endl; // 将内容写入输出文件
  1. 关闭文件:
    在完成文件的读写操作后,要记得关闭文件。可以使用close函数关闭文件流。例如:
inFile.close(); // 关闭输入文件
outFile.close(); // 关闭输出文件

这些只是文件操作中的一部分函数和用法,C++还提供了更多高级的文件处理功能,如文件定位、异常处理等。如果需要更详细的信息,建议参考C++的标准库文档或其他相关书籍。

三、Linux系统文件操作(I/O接口)

1. open()

open()是一个系统调用函数,用于打开文件或创建文件,可以在C语言、C++等编程语言中使用。该函数的声明如下:

#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);

pathname参数表示要打开的文件路径,可以是绝对路径或相对路径
flags参数表示打开文件时的访问方式,可能的取值有:

  • O_RDONLY: 只读模式,打开文件后只能读取,无法写入。
  • O_WRONLY: 只写模式,打开文件后只能写入,无法读取。
  • O_RDWR: 读写模式,打开文件后既可以读取也可以写入。
  • O_APPEND: 写入时追加到文件末尾。
  • O_CREAT: 如果文件不存在,则创建文件。

mode参数表示文件权限(即文件所有者、所有组和其他用户的访问权限),通常使用八进制数表示。当O_CREAT标志被设置时,mode参数才有效。

open()函数返回一个非负整数作为文件描述符,代表新文件的访问点。如果发生错误,则返回-1,并设置全局变量errno来指示错误类型。

在Linux系统中,open()是底层文件操作中最为基础和最常用的函数之一。通过它,我们可以实现文件的读取、写入、修改、删除等操作。了解这个函数的用法和参数对我们进行文件操作的开发和调试都非常有帮助。

⭕传入多个打开方式(按位或操作将不同的标志位组合在一起)

按位或操作是一种位运算操作,其原理是对两个操作数的每一个二进制位进行逻辑或(OR)运算。具体来说,如果两个操作数中的某一位至少有一个为1,则结果的相应位将置为1;否则,结果的相应位将置为0。

在使用按位或操作符|将不同的标志位组合在一起时,实际上是将各个标志位的二进制表示进行按位或运算,从而得到一个组合了多个标志的结果值。

例如,假设有两个标志位常量:

#define FLAG_A 0b00000001   // 二进制表示的标志位A,第1位为1
#define FLAG_B 0b00000010   // 二进制表示的标志位B,第2位为1

当执行按位或操作FLAG_A | FLAG_B时,按位或操作会将二进制表示中的对应位进行按位或运算:

     00000001   (FLAG_A)
  |  00000010   (FLAG_B)
  -------------
     00000011   (结果:FLAG_A | FLAG_B)

由于标志位A和标志位B的二进制表示在第1位和第2位都为1,因此按位或操作的结果中,第1位和第2位都被置为1。

这样,通过不断使用按位或操作|将多个标志位进行组合,可以将多个标志位的信息合并在一起,得到一个表示多个标志的结果值。

要传入多个打开方式,可以通过按位或(bitwise OR)操作将不同的标志位组合在一起。使用按位或操作符|可以将不同的标志位进行逻辑或运算。

下面的代码,展示了如何传入多个打开方式:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    int fileDescriptor;
    char buffer[100];

    // 打开文件,以读写和追加方式打开
    fileDescriptor = open("example.txt", O_RDWR | O_APPEND);
    if (fileDescriptor == -1) {
        perror("打开文件失败");
        exit(EXIT_FAILURE);
    }

    // 读取文件内容
    ssize_t bytesRead = read(fileDescriptor, buffer, sizeof(buffer));
    if (bytesRead == -1) {
        perror("读取文件失败");
        exit(EXIT_FAILURE);
    }

    // 输出文件内容
    write(STDOUT_FILENO, buffer, bytesRead);

    // 关闭文件
    close(fileDescriptor);

    return 0;
}

上述代码中,使用了按位或操作符|O_RDWRO_APPEND两个打开标志位进行了逻辑或运算,表示同时以读写和追加方式打开文件。

2. write()

write()函数是Linux/Unix系统中一个用于向文件或文件描述符写入数据的系统调用函数。其声明如下:

#include <unistd.h>

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

其中,fd参数是要写入的文件描述符,buf参数是指向将要写入的数据缓冲区的指针,count参数是要写入的数据字节数。

write()函数的常见用法如下:

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

int fd = open("myfile", O_WRONLY);  // 打开文件
char *buf = "Hello, World!";        // 待写入的数据
ssize_t n = write(fd, buf, strlen(buf));  // 写入数据
close(fd);                          // 关闭文件

该程序打开名为"myfile"的文件,并将字符串"Hello, World!"写入该文件中,最后关闭文件。

write()函数的返回值为成功写入的字节数,如果发生错误则返回-1。

3. read()

read()函数是Linux/Unix系统中一个用于从文件或文件描述符读取数据的系统调用函数。其声明如下:

#include <unistd.h>

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

其中,fd参数是要读取的文件描述符,buf参数是指向读取数据缓冲区的指针,count参数是要读取的数据字节数。

read()函数的常见用法如下:

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

int fd = open("myfile", O_RDONLY);  // 打开文件
char buf[1024];                     // 缓冲区
ssize_t n = read(fd, buf, sizeof(buf));  // 读取数据到缓冲区
close(fd);                          // 关闭文件

该程序打开名为"myfile"的文件,并从该文件中读取数据到缓冲区中,最后关闭文件。

read()函数的返回值为实际读取的字节数,如果到达文件末尾则返回0,如果发生错误则返回-1。

4. close()

close()函数是一个系统调用函数,用于关闭先前打开的文件描述符。它会释放与该文件描述符相关的所有系统资源。

其函数原型如下:

#include <unistd.h>

int close(int fd);

其中,fd是要关闭的文件描述符。

close()函数的常见用法如下:

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

int fd = open("myfile", O_RDONLY);  // 打开文件
// 使用文件描述符进行读取或写入操作
close(fd);                          // 关闭文件

在上述示例中,首先使用open()函数打开了名为"myfile"的文件,并获得了文件描述符fd。在完成读取或写入操作后,可以使用close()函数关闭文件描述符fd,以释放与该文件描述符相关的系统资源。

在关闭文件时,close()函数会执行一些清理操作,例如刷新缓冲区、释放资源等。成功关闭文件时,close()函数返回0;如果发生错误,返回-1,此时可以通过检查全局变量errno来获取具体的错误信息。

需要注意的是,不正确地使用文件描述符,或者未正确关闭文件描述符,可能会导致资源泄漏或其他问题。因此,在不需要使用文件描述符时,及时调用close()函数关闭文件是一个良好的编程习惯。

5. lseek()

lseek()函数是一个系统调用函数,用于在文件中移动文件读写位置指针。它可以用于改变文件当前的偏移量。

其函数原型如下:

#include <unistd.h>

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

其中,fd是要操作的文件描述符;offset是相对于whence参数指定位置的偏移量;whence参数指定了计算偏移量的方式。

lseek()函数的常见用法如下:

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

int fd = open("myfile", O_RDONLY);  // 打开文件

off_t new_offset = lseek(fd, 0, SEEK_END);  // 将文件读写位置指针设置到文件末尾
// 进行读取或写入操作

close(fd);                                 // 关闭文件

在上述示例中,首先使用open()函数打开了名为"myfile"的文件,并获得了文件描述符fd。然后,使用lseek()函数将文件读写位置指针设置到文件末尾(通过将offset参数设置为0和whence参数设置为SEEK_END)。这样,我们就可以在末尾进行读取或写入操作。

通过使用不同的whence参数,可以实现不同的偏移量计算方式,常见的参数包括:

  • SEEK_SET:将位置指针设置为相对于文件开始位置的偏移量。
  • SEEK_CUR:将位置指针设置为相对于当前位置的偏移量。
  • SEEK_END:将位置指针设置为相对于文件末尾的偏移量。

lseek()函数返回新的文件偏移量,如果发生错误,则返回-1,并将错误信息存储在全局变量errno中。

温馨提示

感谢您对博主文章的关注与支持!如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于Linux以及C++编程技术问题的深入解析、应用案例和趣味玩法等。如果感兴趣的话可以关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索Linux、C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
在这里插入图片描述