【Linux系统编程(文件编程)】之复现cp指令、修改文件应用

news2025/1/18 8:59:33

文章目录

  • 一、文件操作原理
  • 二、文件操作步骤
  • 三、实现 cp 复制指令
  • 四、修改配置文件
  • 五、写一个整数到文件
  • 六、写结构体数组到文件
    • 01 结构体
    • 02 结构体数组

一、文件操作原理

文件描述符:

  1. 对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当进程打开一个文件或创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open或creat返回的文件描述符标识该文件,将其作为参数传递给read或write。
    按照惯例,UNIX shell使用文件描述符 0 与进程的标准输入相结合,文件描述符 1 与进程的标准输出相结合,文件描述符 2 与进程的标准错误输出相结合。STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO 这几个宏代替了 0 1 2 这几个魔数。
  2. 文件描述符,这个数字在一个进程中表示一个特定的含义,当我们open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回应用程序一个数字作为文件描述符,这个数字就和我们内存中维护的这个动态文件的这些数据结构绑定上了,以后我们应用程序如果向操作这个动态文件,只需要用这个文件描述符区分。
  3. 文件描述符的作用域是当前进程,出了这个进程文件描述符就没有意义了。

open函数打开文件,打开成功返回一个文件描述符,打开失败,返回-1。

标准输入、标准输出的例子:
在这里插入图片描述

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

int main()
{
        char readBuf[128]={0};
        int n_read = read(0, readBuf, 5);
        int n_write = write(1, readBuf, strlen(readBuf));
        printf("\ndone!\n");
        return 0;
}

二、文件操作步骤

打开/创建文件
读取/写入文件
关闭文件
  1. Linux中要操作一个文件,一般是先 open 一个文件,得到文件描述符,然后对文件进行读写操作(或其它操作),最后是 close 关闭文件。
  2. 强调一点:我们对文件进行操作时,一定要先打开文件,打开成功之后才能进行操作,如果打开失败,就不用进行后边的操作了,最后读写完成后,一定要关闭文件,否则会造成文件损坏。
  3. 文件平时是存放在块设备中的文件系统中的,这种文件叫做静态文件,当我们open一个文件时,Linux内核作大操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核中特定地址管理存放(叫动态文件)。
  4. 打开文件以后,以后都是对这个文件的读写操作,都是针对内存中这份动态文件的,而非静态文件。当对动态文件读写后,内存中的动态文件与块设备中的静态文件就不同步了,当close被进程调用关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)到块设备中的静态文件。
  5. why 这么设计,不直接对块设备直接操作?
    块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。

在这里插入图片描述

三、实现 cp 复制指令

在这里插入图片描述

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

int main(int argc, char **argv)
{
        if(argc != 3){
                printf("param error\n");
                exit(-1);
        }

        printf("argc=%d\n", argc);
        printf("argv[0]=%s\n",argv[0]);
        printf("argv[1]=%s\n",argv[1]);
        printf("argv[2]=%s\n",argv[2]);


        int fd_src, fd_des;
        char *readBuf=NULL;
        // 打开src
        fd_src = open(argv[1], O_RDWR);
        int size = lseek(fd_src, 0, SEEK_END);
        lseek(fd_src, 0, SEEK_SET);
        readBuf = (char *)malloc(size + 8);
        // 读取
        int n_read = read(fd_src, readBuf, size);


        // 创建或打开des
        fd_des = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0600); //无则创建 有则清空
        // 写入
        int n_write = write(fd_des, readBuf, strlen(readBuf));

        // 关闭
        close(fd_src);
        close(fd_des);

        return 0;
}

四、修改配置文件

修改配置文件

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

int main(int argc, char **argv)
{
        if(argc != 2){
                printf("param error\n");
                exit(-1);
        }


        int fd;
        char *readBuf=NULL;
        // 打开
        fd = open(argv[1], O_RDWR);

        /*
        int num = lseek(fd, 0, SEEK_CUR);
        printf("how many %d\n", num);//0
        */

        int size = lseek(fd, 0, SEEK_END);
        lseek(fd, 0, SEEK_SET);

        // 读取
        readBuf = (char *)malloc(size + 8);
        int n_read = read(fd, readBuf, size);

        // modify
        char *p = strstr(readBuf, "LENG=");//修改5为其他
        p = p + strlen("LENG=");
        *p = '9';

        // 写入
        lseek(fd, 0, SEEK_SET);
        int n_write = write(fd, readBuf, strlen(readBuf));
        // 关闭
        close(fd);

        return 0;
}

五、写一个整数到文件

在这里插入图片描述

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

int main()
{
        int fd;
        int data = 100;
        int data2;
        fd = open("./file", O_RDWR);

        //ssize_t write(int fd, const void *buf, size_t count);
        int n_write = write(fd, &data, sizeof(int));

        lseek(fd, 0, SEEK_SET); //重要

        //ssize_t read(int fd, void *buf, size_t count);
        int n_read = read(fd, &data2, sizeof(int));
        printf("read:%d\n", data2);

        close(fd);
        return 0;
}

六、写结构体数组到文件

01 结构体

结构体

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

struct Test
{
        int a;
        char c;
};


int main()
{
        int fd;
        struct Test data={2, 'c'};
        struct Test data2;
        fd = open("./file", O_RDWR);

        //ssize_t write(int fd, const void *buf, size_t count);
        int n_write = write(fd, &data, sizeof(struct Test));

        lseek(fd, 0, SEEK_SET);

        //ssize_t read(int fd, void *buf, size_t count);
        int n_read = read(fd, &data2, sizeof(struct Test));
        printf("read: %d %c\n", data2.a, data2.c);

        close(fd);
        return 0;
}
~              

02 结构体数组

在这里插入图片描述

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

struct Test
{
        int a;
        char c;
};


int main()
{
        int fd;
        struct Test data[2] = {{96, 'a'}, {97, 'b'}};
        struct Test data2[2];
        fd = open("./file", O_RDWR);

        //ssize_t write(int fd, const void *buf, size_t count);
        int n_write = write(fd, &data, sizeof(struct Test)*2);

        lseek(fd, 0, SEEK_SET);

        //ssize_t read(int fd, void *buf, size_t count);
        int n_read = read(fd, &data2, sizeof(struct Test)*2);
        printf("read: %d %c\n", data2[0].a, data2[0].c);
        printf("read: %d %c\n", data2[1].a, data2[1].c);

        close(fd);
        return 0;
}

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

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

相关文章

Docker:overlay2浅析以及解决overlay2 文件过大的问题

最近在学习docker的实现时看到这么一个概念&#xff1a;Union File System&#xff0c;先让我们来介绍介绍它。 Union File System 定义&#xff1a;联合文件系统&#xff08;UnionFS&#xff09;是一种分层、轻量级并且高性能的文件系统&#xff0c;它支持对文件系统的修改作…

VSCode 最全实用插件(VIP典藏版)

目录 一、必备插件 &#x1f33e;Chinese&#xff08;中文&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#xff09; &#x1f921;Settings Sync&#xff08;配置同步到云端&#xff09; &#x1f308;wakatime&#xff08;编程时间及行为跟踪统计&…

多目标跟踪数据关联算法

跟踪门 跟踪门的作用是将观测回波分配给已建立的目标轨迹或者新目标轨迹的一种粗略检验方法&#xff0c; 是机动目标跟踪中首当其冲的问题 。跟踪门是跟踪空间中的一块子空间 &#xff0c;中心位于被跟踪目标的预测状态 &#xff0c;其大小由接收正确回波的概率确定。设置的跟…

阿里云AliYun物联网平台使用-客户端API获取设备传感数据

一、前言 上一篇文章中&#xff0c;已经实现了虚拟数据上云&#xff0c;本文我们将进行上位机客户端的开发&#xff0c;即通过调用阿里云IOT物联网云平台的SDK&#xff0c;开发能获取传感器的遥感数据。 二、云平台操作 调用API需要用户的AccessKey Secret&#xff0c;这意味着…

使用IDEA的Run DashBoard

在微服务开发过程中&#xff0c;我们需要开启很多的服务&#xff0c;为了方便管理&#xff0c;我们可以使用IDEA的Run DashBoard来启动相关服务。 默认情况下&#xff0c;IDEA检测到你的项目中由SpringBoot项目时&#xff0c;会提示你开启Run DashBoard。如果没有开启的话&…

MySql5.6版本开启慢SQL功能

文章目录 1引言1.1目的1.2注意点说明1.3 操作步骤1.3.1 临时生效操作步骤1.3.2 永久生效操作步骤1.3.3 按日期生成日志文件1.3.4 执行成功后验证功能是否开启 1.4 慢SQL日志记录内容介绍1.5 Shell脚本 1引言 1.1目的 开启 MySQL 的慢查询日志&#xff08;Slow Query Log&…

【Spring core学习二】创建Spring 项目 Spring的存

目录 &#x1f31f;一、创建最原始的Spring-core项目。 &#x1f31f;二、怎么往Spring中存取对象&#xff1f; &#x1f337;1、在Spring中存对象 &#x1f337;2、通过getBean获取对象的三种方式 &#x1f337;3、通过factory方式获取对象 &#x1f31f;三、对存对象的…

3分钟了解Android中稳定性测试

一、什么是Monkey Monkey在英文里的含义是猴子&#xff0c;在测试行业的学名叫“猴子测试”&#xff0c;指的是没有测试经验的人甚至是根本不懂计算机的人&#xff08;就像一只猴子&#xff09;&#xff0c;不需要知道程序的任何用户交互方面的知识&#xff0c;给他一个程序&a…

TCP协议3次握手4次挥手

建立一个TCP连接时&#xff0c;需要客户端和服务端总共发送3个包以确认连接的建立&#xff0c;在socket编程中&#xff0c;这一过程由客户端执行connect来触发&#xff0c;在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。 TCP三次握手的过程如下:第一次握…

【编译之美】【5. 代码优化:数据流分析】

有些优化只能在全局优化中做&#xff0c;在本地优化中做不了&#xff0c;比如&#xff1a; 代码移动&#xff08;Code motion&#xff09;能够将代码从一个基本块挪到另一个基本块&#xff0c;比如从循环内部挪到循环外部&#xff0c;来减少不必要的计算。&#xff08;循环剥离…

【HarmonyOS】Stage模型二维码/条码生成与解析

HarmonyOS的官方API中提供了QRCode组件&#xff08;QRCode-基础组件-组件参考&#xff08;基于ArkTS的声明式开发范式&#xff09;-ArkTS API参考-HarmonyOS应用开发&#xff09;&#xff0c;这个组件有个缺点只能用于显示二维码&#xff0c;无法显示条码与解析码内容&#xff…

【hadoop】部署hadoop的伪分布模式

hadoop的伪分布模式 伪分布模式的特点部署伪分布模式hadoop-env.shhdfs-site.xmlcore-site.xmlmapred-site.xmlyarn-site.xml对NameNode进行格式化启动Hadoop 对部署是否完成进行测试免密码模式免密码模式的原理&#xff08;重要&#xff09;免密码模式的配置 伪分布模式的特点…

Linux离线环境Jenkins部署SpringBoot

Jenkins服务器 把Jar包上传到Linux服务器的/jenkins/目录下 Dashboard----》新建任务----》构建一个自由风格的软件项目----》test 修改jenkins工作空间 新建构建前执行命令stop.sh&#xff0c;停止SpringBoot并备份 &#xff08;这里是目标服务器&#xff0c;即部署项目的…

2.3 移动次数计算和静态链表

1. 元素移动次数计算问题 本问题针对顺序表, 因为链表不需要移动元素, 只需要重新连接指针即可. 题型一: 计算在某个位置上插入一个新元素会导致多少元素的移动. 题型二: 计算在每个位置上插入一个元素所导致的平均移动次数. 先计算每个位置上插入的概率, 一般是1/n, 平均移…

vue Router(v3.x) 路由传参的三种方式详解

文章目录 前言一&#xff0c;params 传参&#xff08;显示参数&#xff09;注意&#xff1a; 响应路由参数的变化 二&#xff0c;params 传参&#xff08;不显示参数&#xff09;注意&#xff1a;上述这种利用 params 不显示 url 传参的方式会导致在刷新页面的时候&#xff0c;…

【HCIA】10.VLAN间通信

VLAN间通信的解决方法 使用路由器的物理接口 路由器三层接口作为网关&#xff0c;转发本网段前往其它网段的流量。路由器三层接口无法处理携带VLAN Tag的数据帧&#xff0c;因此交换机上联路由器的接口需配置为Access。路由器的一个物理接口作为一个VLAN的网关&#xff0c;因此…

即视角|出海资本热土——印尼市场洞察(下)

即视角Insight 共享即构新洞察&#xff0c;共建行业新动能——ZEGO即构科技基于音视频技术领域的多年深耕&#xff0c;综合面向各行业的服务经验&#xff0c;在【即视角】栏目发布即构对行业的洞察。 在《即视角&#xff5c;出海资本热土——印尼市场洞察&#xff08;上&…

WIFI鉴权的过程

1.前言 当今手机连接WIFI热点普遍采用WPA2-PSK的方式。本文讨论这个方式的鉴权过程。 2. 鉴权过程 我们称需要连接的一方为station&#xff0c;简称STA。提供WIFI热点的一方为AP。 连接之前, station需要知道AP的名字&#xff08;ssid&#xff09;和密码(PSK)。 定义 &#x…

Openlayers实战:多地图底图切换

在实际的地图项目中,不管是我们看到的百度地图还是高德地图等,都会有地图切换这一项。 在Openlayers实战中,我们用三种地图做demo,分别是谷歌地图。Openstreetmap,stamen地图。 切换的主要原则是设置三个底图层,设定其显示状态,用到了visible这一个属性。 效果图 源代码…

更新补丁导致360随身wifi提示USB设备驱动异常

运行环境&#xff1a;Windows11 更新补丁版本&#xff1a;2023-适用于 Windows 11 的 07 累积更新&#xff0c;适合基于 x64 的系统 (KB5028182) 硬件版本&#xff1a;360随身wifi-3 错误提示&#xff1a;USB设备驱动异常&#xff0c;创建Wifi网络失败 采取措施&#xff1a;更新…