【Linux系统编程】第二十八弹---构建基础文件操作库与理解标准错误流(stderr)在C与C++中的应用

news2024/10/7 13:26:03

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、封装简单的库

1.1、定义文件结构

1.2、打开文件

1.3、刷新缓冲区

1.4、写文件

1.5、关闭文件

1.6、各文件代码 

2、stderr

2.1、C语言代码演示

2.2、C++代码演示


1、封装简单的库

1.1、定义文件结构

#define LINE_SIZE 1024
#define FLUSH_NOW  1 // 立即刷新
#define FLUSH_LINE 2 // 行刷新
#define FLUSH_FULL 4 // 全缓冲

typedef struct _myFILE  
{
  unsigned int flags;// 文件刷新方式
  int fileno;// fd
  // 缓冲区
  char cache[LINE_SIZE];
  int cap;// 容量
  int pos;// 下次写入的位置
}myFILE;// C语言创建结构体变量需要加struct关键字,因此使用typedef重命名

1.2、打开文件

打开文件本质是开辟一块存放文件数据的空间。

myFILE* my_fopen(const char* path,const char* flag)
{
  int flag1 = 0;// 系统调用的文件打开方式
  int iscreate = 0;// 文件是否被创建
  mode_t mode = 0666;// 默认权限设置
  // 读方式打开文件,只需设置flag1
  if(strcmp(flag,"r") == 0)
  {
    flag1 = O_RDONLY;
  }
  // 写方式打开文件,设置flag1 和 iscreate
  else if(strcmp(flag,"w") == 0)
  {
    flag1 = (O_WRONLY | O_CREAT | O_TRUNC);
    iscreate = 1;
  }
  // 追加方式打开文件
  else if(strcmp(flag,"a") == 0)
  {
    flag1 = (O_WRONLY | O_CREAT | O_APPEND);
    iscreate = 1;
  }
  else 
  {}

  int fd = 0;
  if(iscreate)
    fd = open(path,flag1,mode);// 创建新文件权限限制才有效,传三个参数
  else 
    fd = open(path,flag1);// 打开已经存在的文件不会修改文件权限,使用两个参数即可
  
  if(fd < 0) return NULL;// 打开文件失败返回NULL
  
  // 堆区开辟的空间出了函数不会销毁
  myFILE* fp = (myFILE*)malloc(sizeof(myFILE));
  if(fp == NULL) return NULL;

  fp->fileno = fd;
  fp->flags = FLUSH_LINE;// 设置行刷新

  fp->cap = LINE_SIZE;
  fp->pos = 0;

  return fp;
}

1.3、刷新缓冲区

刷新缓冲区实质是将缓冲区内容写入需要刷新的文件中。

void my_fflush(myFILE* fp)
{
  // 将缓冲区 pos 个字节的内容写入 fp 的文件中,并将pos置0
  write(fp->fileno,fp->cache,fp->pos);
  fp->pos = 0;
}

1.4、写文件

写文件的本质是将内容拷贝到缓冲区中,条件允许就刷新缓冲区。

ssize_t my_fwrite(myFILE* fp,const char* data,int len)
{
  // 写入的本质是拷贝,条件允许就刷新
  memcpy(fp->cache + fp->pos ,data,len);// 需要考虑扩容与越界问题,此处不做处理,从简
  fp->pos += len;
  
  // 刷新方式为行刷新且缓冲区遇到\n就刷新缓冲区
  if((fp->flags & FLUSH_LINE) && fp->cache[fp->pos-1] == '\n')
  {
      my_fflush(fp);
  }
  return len; 
}

1.5、关闭文件

先刷新缓冲区,在关闭文件并释放空间。

void my_fclose(myFILE* fp)
{
  my_fflush(fp);// 刷新缓冲区
  close(fp->fileno);// 关闭文件
  free(fp);// 释放空间
}

1.6、各文件代码 

mystdio.h

#pragma once 

#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define LINE_SIZE 1024
#define FLUSH_NOW  1
#define FLUSH_LINE 2
#define FLUSH_FULL 4

typedef struct _myFILE  
{
  unsigned int flags;
  int fileno;
  // 缓冲区
  char cache[LINE_SIZE];
  int cap;// 容量
  int pos;// 下次写入的位置
}myFILE;

myFILE* my_fopen(const char* path,const char* flag);
void my_fflush(myFILE* fp);
ssize_t my_fwrite(myFILE* fp,const char* data,int len);
void my_fclose(myFILE* fp);

mystdio.c

#include "mystdio.h"

myFILE* my_fopen(const char* path,const char* flag)
{
  int flag1 = 0;
  int iscreate = 0;
  mode_t mode = 0666;
  if(strcmp(flag,"r") == 0)
  {
    flag1 = O_RDONLY;
  }
  else if(strcmp(flag,"w") == 0)
  {
    flag1 = (O_WRONLY | O_CREAT | O_TRUNC);
    iscreate = 1;
  }
  else if(strcmp(flag,"a") == 0)
  {
    flag1 = (O_WRONLY | O_CREAT | O_APPEND);
    iscreate = 1;
  }
  else 
  {}

  int fd = 0;
  if(iscreate)
    fd = open(path,flag1,mode);
  else 
    fd = open(path,flag1);
  
  if(fd < 0) return NULL;
  
  myFILE* fp = (myFILE*)malloc(sizeof(myFILE));
  if(fp == NULL) return NULL;

  fp->fileno = fd;
  fp->flags = FLUSH_LINE;

  fp->cap = LINE_SIZE;
  fp->pos = 0;

  return fp;
}
void my_fflush(myFILE* fp)
{
  write(fp->fileno,fp->cache,fp->pos);
  fp->pos = 0;
}
ssize_t my_fwrite(myFILE* fp,const char* data,int len)
{
  // 写入的本质是拷贝,条件允许就刷新
  memcpy(fp->cache + fp->pos ,data,len);// 考虑扩容与越界问题
  fp->pos += len;
  
  if((fp->flags&FLUSH_LINE) && fp->cache[fp->pos-1] == '\n')
  {
      my_fflush(fp);
  }
  return len; 
}
void my_fclose(myFILE* fp)
{
  my_fflush(fp);
  close(fp->fileno);
  free(fp);
}

testfile.c

#include "mystdio.h"
#include <stdio.h>

#define FILENAME "log.txt"

int main()
{
  // 使用自己封装的函数以写方式打开文件
  myFILE* fp = my_fopen(FILENAME,"w");
  if(fp == NULL) return 1;

  const char* str = "hello linux";
  int cnt = 10;
  char buff[128];

  while(cnt)
  {
    // 将格式化数据转成字符串到buff中
    sprintf(buff,"%s - %d",str,cnt);
    // 将buff写入文件
    my_fwrite(fp,buff,strlen(buff));
    cnt--;
    sleep(1);
    my_fflush(fp);// 写完一组数据就刷新缓冲区
  }
  my_fclose(fp);// 关闭文件
  return 0;
}

运行结果

2、stderr

2.1、C语言代码演示

#include <stdio.h>

int main()
{
  perror("error:");
  fprintf(stdout,"hello fprintf stdout\n");
  fprintf(stderr,"hello fprintf stderr\n");
  return 0;
}

看现象

我们可以看到一部分数据存入了文件中,但是一部分数据没有存入文件中。

实质是 > 是标准输出重定向,修改1号fd里面的内容,其余的是2号fd里面的内容,因此直接打印到显示器上。 

为什么有了标准输出流还要有标准错误流呢???

因为我们在编写程序的时候不能保证一直都是正确的代码,当我们查错误的时候就可以通过标准错误流查询。标准输出流‌主要用于程序的正常输出信息,标准错误流‌则用于输出程序的错误信息,两者共同确保了程序的运行状态可以被正确地监控和理解。

如果想让2和1都重定向到文件中怎么做? 

1、将数据存入不同的文件

将1号的内容重定向到ok.txt 文件,将2号的内容存入err.txt文件。

命令行代码

[jkl@host file3]$ ./a.out
error:: Success
hello fprintf stdout
hello fprintf stderr
[jkl@host file3]$ ./a.out 1>ok.txt 2>err.txt
[jkl@host file3]$ cat ok.txt
hello fprintf stdout
[jkl@host file3]$ cat err.txt
error:: Success
hello fprintf stderr

运行结果 

2、将数据存入同一个文件 

命令行代码

[jkl@host file3]$ ./a.out 1>all.txt 2>&1
[jkl@host file3]$ cat all.txt
error:: Success
hello fprintf stderr
hello fprintf stdout

运行结果 

总结 

  • perror("open");本质是向2号打印。
  • printf("");本质是向1号打印。

2.2、C++代码演示

#include <iostream>

int main()
{
  std::cout<<"hello cout"<<std::endl;
  std::cerr<<"hello cerr"<<std::endl;
  return 0;
}

命令行代码 

[jkl@host file3]$ g++ test_stderr.cpp
[jkl@host file3]$ ./a.out 
hello cout
hello cerr
[jkl@host file3]$ ./a.out > log.txt
hello cerr
[jkl@host file3]$ cat log.txt
hello cout

运行结果 

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

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

相关文章

医院管理新趋势:Spring Boot技术引领

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

Github优质项目推荐 - 第五期

文章目录 Github优质项目推荐 - 第五期一、【localsend】&#xff0c;47.5k stars - 附近设备文件互传二、【Pake】&#xff0c;29.9k stars - 网页变成桌面应用三、【laravel-crm】&#xff0c;10.7k stars - CRM 解决方案四、【localstack】&#xff0c;55.7k stars - 本地 A…

【C++】二叉搜索树+变身 = 红黑树

&#x1f680;个人主页&#xff1a;小羊 &#x1f680;所属专栏&#xff1a;C 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 前言一、定义与性质二、红黑树节点的定义三、新增节点插入四、验证红黑树五、AVL树和红黑树比较 前言 本文仅适合了…

【算法】DFS系列之 FloodFill 算法

【ps】本篇有 7 道 leetcode OJ。 目录 一、算法简介 二、相关例题 1&#xff09;图像渲染 .1- 题目解析 .2- 代码编写 2&#xff09;岛屿数量 .1- 题目解析 .2- 代码编写 3&#xff09;岛屿的最大面积 .1- 题目解析 .2- 代码编写 4&#xff09;被围绕的区域 .1-…

allegro精确画圆形边框

1.显示原点位置&#xff1a; 2.class-subclass依次选择Board Geometry-Outline 3.菜单ADD---Circle,右侧option,依次设置如下&#xff0c;如图可设置为圆心&#xff08;0&#xff0c;0&#xff09;&#xff0c;半径为42mm的边框&#xff0c;不要忘了右键Done&#xff0c;完成绘…

海量数据去重的hash,布隆过滤器Bloom Filter,一致性hash

文章目录 一、⭐hash函数如何选取hash函数&#xff1f;冲突处理 二、⭐海量数据去重布隆过滤器**布隆过滤器介绍**布隆过滤如何应用 三、⭐一致性哈希基本原理&#xff1a; 四、⭐一道面试题 一、⭐hash函数 hash函数的作⽤&#xff1a;避免插⼊的时候字符串的⽐较&#xff0c…

怎么把店铺地址弄上高德地图?

随着互联网的高度普及&#xff0c;如今的营销方式也发生了巨大的变化。以前的商家要想提高店铺销售额&#xff0c;只需要在线下举办促销活动就可以吸引周边的顾客上门消费&#xff0c;但现在&#xff0c;商家如果想获取更多客流量&#xff0c;就必须在网上进行曝光&#xff0c;…

性能测试学习6:jmeter安装与基本配置/元件

一.JDK安装 官网&#xff1a;https://www.oracle.com/ 二.Jmeter安装 官网&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 下载zip包&#xff0c;zip后缀那个才是Windows系统的jmeter 三.Jmeter工作目录介绍 四.Jmeter功能 1&#xff09;修改默认配置-汉化 2&am…

市场价值99的likeyun付费进群插件

市场价值99的likeyun付费进群插件 这款是引流宝的付费插件 要搭配引流宝使用 多模版 最近发现好多人再倒卖大佬的付费插件 为了减少这种情况&#xff0c;在征得大佬的同意下决定免费发出来 此版本是付费进群最新1.0版本 不提供后续更新服务&#xff0c;有能力的还是建议支持…

每日OJ题_牛客_乒乓球筐_哈希_C++_Java

目录 牛客_乒乓球筐_哈希 题目解析 C代码 Java代码 牛客_乒乓球筐_哈希 乒乓球筐__牛客网 (nowcoder.com) 描述&#xff1a; nowcoder有两盒&#xff08;A、B&#xff09;乒乓球&#xff0c;有红双喜的、有亚力亚的……现在他需要判别A盒是否包含了B盒中所有的种类&#…

深入理解 Spring Cache 的工作原理及集成其它第三方缓存

目录 1、Spring Cache 简介2、常用注解2.1、常用注解介绍2.2、常用注解的主要参数 3、缓存注解上 SPEL 表达式可使用的元数据4、入门案例4.1、引入依赖4.2、开启缓存功能4.3、使用缓存4.3.1、新建一个 UserServiceImpl4.3.2、新建一个 UserController 5、工作原理5.1、缓存自动…

Java建筑行业智能化管理系统源码,PC端、手机端、大屏端源码,智慧工地管理平台源码,智慧建设平台 智慧住建平台

智慧工地平台全套源码合作 智慧工地是指运用现代信息技术&#xff0c;如物联网&#xff08;IoT&#xff09;、大数据、人工智能&#xff08;AI&#xff09;、云计算、移动互联网等&#xff0c;对传统建筑工地进行智能化改造和管理的新型工地。它通过高度集成的系统和设备&#…

GeoCue与Xer Technologies合作推动无人机测绘技术革新

GeoCue与Xer Technologies合作推动无人机测绘技术革新 近期,LiDAR测绘硬件和软件开发商GeoCue与瑞士长航时混合动力无人机制造商Xer Technologies AG携手合作,成功将GeoCue的TrueView 720 LiDAR和图像传感器集成至Xer X8无人机平台。这一里程碑式的合作不仅标志着无人机测绘技…

Python手绘五星红旗,庆75周年

环境 pip install matplotlib pip install numpy 代码 import matplotlib.pyplot as plt import numpy as np# 中国国旗的标准尺寸比例是 3:2 width, height 300, 200 # 这里可以调整为任何满足3:2比例的尺寸# 创建一个新图形 fig, ax plt.subplots(figsize(width/100, h…

js 字符串下划线转驼峰 驼峰转下划线

一、下划线转驼峰 1、效果 2、示例 function underscoreToCamelCase(str) {return str.replace(/(_\w)/g, function(match) {return match[1].toUpperCase();}).replace(/^_/, ); }// 示例 let snakeCaseStr "hello_world"; let camelCaseStr underscoreToCamelC…

【Diffusion分割】Cold SegDiffusion:医学图像分割的扩散模型

Cold SegDiffusion: A novel diffusion model for medical image segmentation 摘要&#xff1a; 随着深度学习的发展&#xff0c;扩散模型在医学图像分割任务中表现出了卓越的性能。然而&#xff0c;传统的分割扩散模型通常采用随机高斯噪声生成分割掩膜&#xff0c;导致分割…

【华为HCIP实战课程七】OSPF邻居关系排错MTU问题,网络工程师

一、MTU MUT默认1500,最大传输单元,一致性检测 [R3-GigabitEthernet0/0/1]mtu 1503//更改R3的MTU为1503 查看R3和SW1之间的OSPF邻居关系正常: 默认华为设备没有开启MTU一致性检测! [R3-GigabitEthernet0/0/1]ospf mtu-enable //手动开启MTU检测 [SW1-Vlanif30]ospf mtu…

项目——超级马里奥——Day(2)

争取今天晚上能搞一半啊&#xff0c;啊啊啊啊&#xff0c;感觉事多的忙不过来 设计思路&#xff1a; 1&#xff09;创建并完成常量类 ------->一张图片的情况 先完成对图片的封装------>把图片加载一遍 &#xff08;老实说&#xff0c;我也不太知道为什么&#xff0…

Windows 开发工具使用技巧 QT使用安装和使用技巧 QT快捷键

一、QT配置 1. 安装 Qt 开发框架 1、下载 1、进入下载地址 下载地址1 (官方, 需注册账号)&#xff1a; https://www.qt.io/download下载地址2&#xff08;推荐&#xff09;&#xff1a; http://download.qt.io/http://download.qt.io/archive/qt/ &#xff08;或更直接的…