Linux基础IO(一)

news2024/12/29 9:11:40

Linux基础IO

文章目录

      • Linux基础IO
        • C语言中的文件操作
          • c语言文件打开方式
          • C语言文件操作函数
        • 系统文件操作
          • stdin/stdout/stderr
          • opean
          • close
          • write
          • read
        • 文件描述符
        • 重定向
          • 什么是重定向
          • dup2

C语言中的文件操作

我们通过两个代码复习一下C语言中的文件操作:

int main()
{
    FILE* fp = fopen("log.txt", "w");
    if(fp == nullptr)   perror("fopen fail");
    fputs("hello world\n", fp);
    fclose(fp);
    return 0;
}

image-20230723094643909

int main()
{
    FILE* fp = fopen("log.txt", "r");
    if(fp == nullptr) perror("fopen fail");
    char buffer[64];
    fgets(buffer, sizeof(buffer), fp);
    cout << buffer << endl;
    return 0;
}

image-20230723094706268

第一个是文件的写操作,用w的格式打开一个文件进行写入。

第二个是文件的读操作,用r的格式打开一个文件进行读取。

c语言文件打开方式
  • r,以只读的方式打开文件,文件指针指向文件的首位置。
  • r+,以读写的方式打开文件,文件指针指向文件的首位置。
  • w,以只写的方式打开文件,清空文件内容,如果文件不存在就创建一个文件,文件指针指向文件的首位置。
  • w+,以读写的方式打开文件,如果文件不存在就创建一个文件,如果文件存在就清空文件内容,文件指针指向文件的首位置。
  • a,以追加写的方式打开文件,将内容追加在文件末尾,如果文件不存在就创建一个文件,文件指针指向文件的末尾位置。
  • a+,以读和写的方式打开,将内容追加到末尾位置,如果文件不存在就创建一个文件,文件指针指向文件的末尾位置。
C语言文件操作函数
  1. fopen
FILE* fopen(const char* path, const char* mode)
  • path:要打开的文件
  • mode:文件打开方式
  • 返回值:成功,返回文件流指针;失败,返回NULL
  1. fread
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
  • ptr:将从文件读到的内容保存在ptr指向的空间中
  • size:读文件时,一个块的大小,单位是字节
  • nmemb:期望读到的字节大小
  • stream:文件流指针
  • 返回值:读到的块的个数

一般我们将块大小定义为1字节,返回值就是我们读了多少字节。

例如:

int main()
{
    FILE *fp = fopen("log.txt", "r+");
    if (fp == nullptr)
        perror("fopen fail");
    fputs("hello world\n", fp);
    fseek(fp, 0, SEEK_SET);
    char buffer[64];
    memset(buffer, 0, 64);
    fread(buffer, sizeof(char), sizeof buffer, fp);
    printf("%s\n", buffer);
    fclose(fp);
    return 0;
}

image-20230723110224419

  1. fwrite
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
  • ptr:准备写入的内容
  • size:向文件写入块的大小,单位大小为字节
  • nmemb:期望写的块的大小
  • stream:文件流指针
  • 返回值:返回成功写入的块的个数
int main()
{
    FILE *fp = fopen("log.txt", "r+");
    if (fp == nullptr)
        perror("fopen fail");
    const char* buffer = "xxxxxxxxxxxxxxxxxx\n";
    fwrite(buffer, sizeof(char), strlen(buffer), fp);
    fclose(fp);
    return 0;
}

image-20230723104902469

  1. fseek
int fseek(FILE* stream, long offser, int whence)
  • stream:文件流指针
  • offset:偏移量
  • whence:文件指针偏移到的位置。SEEK_SET,把文件流指针定义到文件头部。

SEEK_CUR,把文件流指针定义到当前文件位置。SEEK_END,把文件流指针定义到文件末尾。

  1. ftell
long ftell(FILE* stream)
  • stream:文件流指针
  • 作用:获取文件指针当前位置
  1. rewind
void rewind(FILE* stream)
  • stream:文件流指针

  • 作用:让文件指针回到文件起始位置

  1. fclose
int fclose(FILE* fp)
  • 作用关闭文件

系统文件操作

在学校系统文件操作前,有这样一个问题需要补充:为什么我们向显示器输出数据,为什么不需要进行打开显示器操作呢?为什么可以直接使用键盘向电脑输入数据呢?

stdin/stdout/stderr

有这样一句话,Linux下一切皆文件,也就是说,在Linux系统下所有东西都可以看做文件。

系统会默认帮我们打开三个流:标准输入流0、标准输出流1和标准错误流2。

它们分别对应的外设是:键盘,显示器和显示器。

它们对应到C语言中就是:stdin、stdout和stderr。

当我们的C程序跑起来时,操作系统就会默认使用C语言的相关接口将这三个输入输出流打开,之后我们才能调用类似于scanf和printf之类的函数向键盘和显示器进行相应的输入输出操作。

我们还可以查到,它们三个都是FILE*类型(和我们之前说的Linux下一切皆文件相对应)。

image-20230723120800993

image-20230723120823430

image-20230723120845840

opean
int open(const char *pathname, int flags, mode_t mode);
  • pathname:表示要打开或创建的目标文件。

以路径给出,创建该文件时,在给出的路径下创建。

以文件名给出,创建该文件时,在当前路径下创建。

  • flags:表示文件的打开方式。

O_RDONLY:以只读的方式打开

O_WRNOLY:以只写的方式打开

O_APPEND:以追加的方式打开

O_RDWR:以读写的方式打开

O_CREAT:当文件不存在时,创建该文件

  • mode:表示创建文件的默认权限。

例如:设置读写权限0666(具体可以查看之前的文章Linux权限管理)

若想创建出来文件的权限值不受umask的影响,则需要在创建文件前使用umask函数将文件默认掩码设置为0。

int main()
{
    umask(0);
    int fd = open("log.txt", O_RDWR | O_CREAT, 0666);
    return 0;
}

image-20230723200037214

  • 返回值:失败则返回-1。

我们也可以看看文件描述符到底是不是从3开始的。(0,1,2默认打开)

int main()
{
    umask(0);
    int fd1 = open("log.txt", O_RDWR | O_CREAT, 0666);
    int fd2 = open("log.txt", O_RDWR | O_CREAT, 0666);
    int fd3 = open("log.txt", O_RDWR | O_CREAT, 0666);
    int fd4 = open("log.txt", O_RDWR | O_CREAT, 0666);
    cout << fd1 << endl << fd2 << endl << fd3 << endl << fd4 << endl;
    return 0;
}

image-20230723200437987

close
int close(int fd);

作用关闭文件。

  • fd : 文件描述符
write
ssize_t write(int fd, const void *buf, size_t count);

作用:向文件写入信息。

  • fd:文件描述符

  • buf:需要写入内容的起始位置

  • count:需要写入的字节数

  • 返回值:写入成功,返回实际写入的字节数;写入失败,返回-1。

示例:

int main()
{
    int fd = open("log.txt", O_RDWR | O_CREAT, 0666);
    if(fd < 0) perror("open fail");
    char buffer1[64] = "hello world\n";
    write(fd, buffer1, strlen(buffer1));
    close(fd);
    return 0;
}

image-20230723202518337

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

作用:读取文件中的信息。

  • fd:文件描述符

  • buf:需要读取内容的起始地址

  • count:需要读取的字节数

  • 返回值:读取成功,返回实际读取字节数;读取失败,返回-1。

示例:

int main()
{
    int fd = open("log.txt", O_RDWR | O_CREAT, 0666);
    if(fd < 0) perror("open fail");
    char buffer2[64];
    read(fd, buffer2, sizeof(buffer2));
    cout << buffer2 << endl;
    close(fd);
    return 0;
}

image-20230723202935471

文件描述符

我们都知道进程创建时同时会创建PCB、mm_struct和页表。其中task_struct中有一个指针,该指针指向一个名为files_struct的结构体,在该结构体当中就有一个名为fd_array的指针数组,该数组的下标就是我们所谓的文件描述符。

我们我们运行进程打开log.txt文件的时候 我们首先会将文件从磁盘加载到内存当中 并且形成对应的struct file结构体并且连入双链表中然后在file_array中找到一个未被使用的空间 让这个空间指向我们刚刚的struct file结构体。

最后将这个空间的下标返回给进程。所以说只要我们有一个文件的fd就能够对这个文件进行各种操作。

我们之前也测试过了,文件描述符是从3开始的。

image-20230723204526330

原因是:它是从file_array中找到未使用空间的最小下标开始分配,其中0、1、2已经在程序运行时自动打开了。

重定向

什么是重定向

重定向是把原本输出到一个文件的数据输出到另一个文件。

例如:

int main()
{
    close(1);
    int fd = open("log.txt", O_RDWR | O_CREAT, 0666);
    if(fd < 0) perror("open fail");
    fputs("hello worldxxxxxxxxxxxxxxxx\n", stdout);
    cout << endl;//刷新缓冲区
    close(fd);
    return 0;
}

image-20230723205510532

由于我们一开始关闭了stdout(1),我们把原本输出到stdout文件的输出到了log.txt文件中,所以显示器无法打印信息了,必须从log.txt中查看。

这就是一个重定向,我们也可以使用以下命令完成重定向:

  1. 清空重定向
[---@VM-8-4-centos day03]$ echo "xxxxxxxxxxxxxxxxx" > log.txt 
[---@VM-8-4-centos day03]$ cat log.txt 

image-20230723211740759

  1. 追加重定向
[---@VM-8-4-centos day03]$ echo "yyyyyyyyyyyyyyyy" >> log.txt 
[---@VM-8-4-centos day03]$ cat log.txt

image-20230723211935816

dup2

在上面使用重定向时需要首先使用close关闭文件,这样我们感觉总是十分麻烦。系统给我们提供了一个便捷的系统调用:

int dup2(int oldfd, int newfd);
  • oldfd:旧的文件描述符
  • newfd:新的文件描述符
  • 返回值:调用成功,返回newfd;调用失败,返回-1。

功能:将oldfd中的内容拷贝到newfd中。

ps:如果newfd和oldfd相同,则不做任何操作,返回newfd。

例如:

int main()
{
    int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
    if (fd < 0) perror("open fail");
    // close(1);
    dup2(fd, 1);
    printf("dup2 success\n");
    return 0;
}

image-20230723214634687

感谢您的阅读,欢迎指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/782939.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp-开发APP使用自定义插件

uniapp-开发APP使用自定义插件 需求背景&#xff1a; 项目组开发了一个APP需要使用到打印机的功能、所以需要通过打印机厂商提供的jdk包结合自己的业务融合到uniapp 中。 首先你需要一个懂开发android开发的同事、让他帮忙配合写一些调用方法&#xff08;调用打印机提供的一些…

态势标绘专题介绍

介绍 这个专栏是专门针对基于Cesium来实现态势标绘的专题专栏,专栏主要实现了30余种态势几何形状的标绘和编辑、文本的标绘和编辑、图片的标绘和编辑以及简单模型的标绘,同时支持标绘结果的导出以及导入。包括最终编写成的一个完整的Vue3.2+TS+Cesium1.107.2的标绘组件。专栏…

【STL】list用法试做_底层实现

目录 一&#xff0c;list 使用 1. list 文档介绍 2. 常见接口 1. list中的sort 2. list sort 与 vector sort效率对比 3. 关于迭代器失效 4. clear 二&#xff0c;list 实现 1.框架搭建 2. 迭代器类——核心框架 3. operator-> 实现 4. const——迭代…

c++11 标准模板(STL)(std::basic_filebuf)(二)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_filebuf : public std::basic_streambuf<CharT, Traits> std::basic_filebuf 是关联字符序列为文件的 std::basic_streambuf 。输入序…

基于AOP实现登录日志和操作日志(新手入门版)

基于AOP实现登录日志和操作日志 目录结构代码PostMan测试代码控制台查看输出解析成JSON如果你觉得对你有帮助的话&#xff0c;请点赞收藏 目录结构 代码 package com.demo.mymaintest.constants;import java.lang.annotation.Documented; import java.lang.annotation.ElementT…

在Debian 12 上安装 PHP 5.6, 7.4

环境&#xff1a;Debian 12 Debian 12 默认的PHP版本为 8.2 如果直接安装php7.4就出现下面的报错&#xff1a; sudo apt-get install libapache2-mod-php7.4 php7.4 php7.4-gd php7.4-opcache php7.4-mbstring php7.4-xml php7.4-json php7.4-zip php7.4-curl php7.4-imap p…

【人工智能】神经网络、前向传播、反向传播、梯度下降、局部最小值、多层前馈网络、缓解过拟合的策略

神经网络、前向传播、反向传播 文章目录 神经网络、前向传播、反向传播前向传播反向传播梯度下降局部最小值多层前馈网络表示能力多层前馈网络局限缓解过拟合的策略前向传播是指将输入数据从输入层开始经过一系列的权重矩阵和激活函数的计算后,最终得到输出结果的过程。在前向…

HarmonyOS/OpenHarmony应用开发-Stage模型UIAbility组件使用(六)

UIAbility组件间交互&#xff08;设备内&#xff09; UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时&#xff0c;会涉及到启动特定的UIAbility&#xff0c;该UIAbility可以是应用内的其他UIAbility&#xff0c;也可以是其他应用的UIAbility&#xff08;例如启…

unity 调用C++追踪物体后的位姿通过 dll,左右手坐标转化2

外参矩阵转四元数,左右手坐标系转化1_天人合一peng的博客-CSDN博客 在之前1的基础上更新 通过定位已经求得了物体的4*4的位姿矩阵&#xff0c;将其变化为四元数并从opengl的右手坐标转化为unity的左手坐标系。 body2world_pose().matrix()为计算得到的4*4的位姿矩阵 例 body…

Go语言之结构体

在实际开发中&#xff0c;我们可以将一组类型不同的、但是用来描述同一件事物的变量放到结构体中。例如&#xff0c;在校学生有姓名、年龄、身高、成绩等属性&#xff0c;学了结构体后&#xff0c;我们就不需要再定义多个变量了&#xff0c;将它们都放到结构体中即可。 在Go语言…

基于linux下的高并发服务器开发(第三章)- 3.7 线程属性

int pthread_attr_init(pthread_attr_t *attr);- 初始化线程属性变量int pthread_attr_destroy(pthread_attr_t *attr);- 释放线程属性的资源int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);- 获取线程分离的状态属性int pthread_attr_setdet…

【Redis】所以延迟双删有啥用

文章目录 1、何为延时双删2、常用缓存策略2.1、介绍2.2、先删缓存后更库2.3、先更库后删缓存2.4、使用场景 3、延时双删实现4、为什么要使用延时双删5、方案选择6、延时双删真的完美吗7、如何确定延时的时间 1、何为延时双删 延迟双删&#xff08;Delay Double Delete&#xf…

Jupyter 安装、简单操作及工作路径更换

一、Jupyter下载安装 pip install jupyterAnaconda是Python另一个非常流行的发行版&#xff0c;它之后有着自己的叫做“conda”的安装工具。用户可以使用它来安装很多第三方包。然而&#xff0c;Anaconda会预装很多包&#xff0c;包括了Jupyter Notebook,所以若已经安装了Anac…

VUE3 语法教程

vue3 起步 刚开始学习 Vue&#xff0c;我们不推荐使用 vue-cli 命令行工具来创建项目&#xff0c;更简单的方式是直接在页面引入 vue.global.js 文件来测试学习。 Vue3 中的应用是通过使用 createApp 函数来创建的&#xff0c;语法格式如下&#xff1a; const app Vue.crea…

cmder 使用简介

文章目录 1. cmder 简介2. 下载地址3. 安装4. 配置环境变量5. 添加 cmder 到右键菜单6. 解决中文乱码问题 1. cmder 简介 cmder 是一个增强型命令行工具&#xff0c;不仅可以使用 windows 下的所有命令&#xff0c;更爽的是可以使用 linux的命令, shell 命令。 2. 下载地址 …

机器学习深度学习——预备知识(下)

机器学习&&深度学习——预备知识&#xff08;下&#xff09; 4 微积分4.1 导数和微分4.2 偏导数4.3 梯度4.4 链式法则 5 自动微分5.1 简单例子5.2 非标量变量的反向传播5.3 分离计算5.4 Python控制流的梯度计算 6 概率6.1 基本概率论6.1.1 概率论公理 6.2 处理多个随机…

5.1 Bootstrap 插件概览

文章目录 Bootstrap 插件概览data 属性编程方式的 API避免命名空间冲突事件 Bootstrap 插件概览 在前面 布局组件 章节中所讨论到的组件仅仅是个开始。Bootstrap 自带 12 种 jQuery 插件&#xff0c;扩展了功能&#xff0c;可以给站点添加更多的互动。即使您不是一名高级的 Jav…

超参数优化 - 贝叶斯优化的实现

目录 1. 基于Bayes_opt实现GP优化 1.1 定义目标函数 1.2 定义参数空间 1.3 定义优化目标函数的具体流程 4. 定义验证函数&#xff08;非必须&#xff09; 5. 执行实际优化流程 2. 基于HyperOpt实现TPE优化 2.1 定义目标函数 2.2 定义参数空间 2.3 定义优化目标函数的…

Asp.Net WebForm ViewState

ViewState用于保存服务器控件(runat"server")状态便于在触发回调后&#xff08;PostBack&#xff09;恢复页面。 页面拖入一个Form id"form1" runat"server",里面添加一个<asp:Button id"Button1" Text"删除" OnClick&q…

python:对 GEDI 数据进行高斯滤波处理

作者:CSDN @ _养乐多_ 在本篇博客中,我们将学习如何使用 Python 对 GEDI(Global Ecosystem Dynamics Investigation)激光雷达数据进行高斯滤波处理。高斯滤波是一种平滑滤波方法,可以有效减少噪声和突变,提高数据的平滑性和连续性。我们将使用 pandas 和 scipy.signal 库…