Linux中对文件的操作(二)

文件描述符

文件描述符fd是通过open打开某一文件后返回的非负整数。在Linux系统中默认存在的文件描述符有0——标准输入,1——标准输出,2——标准错误

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

int main(){
        int fd;

        char readBuf[128];

        int n_read = read(0,readBuf,5);
        int n_write = write(1,readBuf,strlen(readBuf));

        printf("\ndone!\n");
        return 0;
}

上述代码的作用就是使用read基于标准输入通过键盘读取5个字符,之后使用write基于标准输出读取5个字符。
文件描述符只针对当前进程。

在linux中对文件操作需要注意的点

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

实现linux cp命令的代码

cp src.c des.c
思路:
首先要对参数进行拆解
1.打开src.c
2.读src中的内容到buf
3.打开/创建des.c
4.将buf写入到des.c
5.close两个文件

参数拆解

因为我们需要打开源文件和目标文件,因此需要对cp src.c des.c进行参数拆解。代码如下:

#include <stdio.h>

int main(int argc,char** argv)
{
        printf("total params:%d\n",argc);
        printf("No.1 params:%s\n",argv[0]);
        printf("No.2 params:%s\n",argv[1]);
        printf("No.3 params:%s\n",argv[2]);
        return 0;
}

此时需要补全main函数的参数argc和argv;

代码实现cp命令


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

int main(int argc,char** argv){
        int fdSrc,fdDes;
        char *readBuf=NULL;

        if(argc != 3){	//参数个数不为3时直接报错退出
                printf("params error\n");
                exit(-1);
        }

        fdSrc = open(argv[1],O_RDWR);	//打开源文件
        int size = lseek(fdSrc,0,SEEK_END);	//计算源文件大小
        lseek(fdSrc,0,SEEK_SET);        //将光标恢复到头
        readBuf = (char *)malloc(sizeof(char)*size+8);	//开辟空间

        int n_read = read(fdSrc,readBuf,size);	//从源文件中读取数据

        fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);	//打开目标文件,如果不存在就creat,如果已经存在了,就会根据O_TRUNC清空之前的数据。
        int n_write = write(fdDes,readBuf,strlen(readBuf));	//写入数据

        close(fdSrc);	//关闭文件,不要忘记了!
        close(fdDes);


        return 0;
}

运行代码gcc test4.c -o mycp
./mycp test4.c new.c
就可以实现对test4.c进行复制的操作

文件编程 修改配置文件

思路:
1.找到需要修改那一行的位置a
2.a往后移动到我们需要修改的参数之前的位置b
3.修改b位置的参数

可以利用strstr函数来找到a位置
**char *strstr(const char haystack, const char needle);
RETURN VALUE
These functions return a pointer to the beginning of the substring, or NULL if the substring
is not found.返回子串的起始位置。

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

int main(int argc,char** argv){
        int fdSrc;
        char *readBuf=NULL;

        if(argc != 2){
                printf("params error\n");
                exit(-1);
        }

        fdSrc = open(argv[1],O_RDWR);
        int size = lseek(fdSrc,0,SEEK_END);
        lseek(fdSrc,0,SEEK_SET);        //将光标恢复到头
        readBuf = (char *)malloc(sizeof(char)*size+8);

        int n_read = read(fdSrc,readBuf,size);

        char *p = strstr(readBuf,"LENG=");
        if(p == NULL){
                printf("not found\n");
                exit(-1);
        }else{
                printf("change success\n");
        }

        p=p+strlen("LENG=");
        *p = '5';	//考虑如果我们写入的是整型数5,会是什么情况

        lseek(fdSrc,0,SEEK_SET);
        int n_write = write(fdSrc,readBuf,strlen(readBuf));

        close(fdSrc);

        return 0;
}

原先的数据是:
SPEED=3
LENG=3
SCORE=9
LEVEL=5
修改后的数据为:
SPEED=3
LENG=5
SCORE=9
LEVEL=5

修改配置文件时,写入一个整数

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

int main(){
        int fd;

        int data1 = 10;
        int data2 = 0;

        fd = open("./file1",O_RDWR);

        int n_write = write(fd,&data1,sizeof(int));

        lseek(fd,0,SEEK_SET);	//使光标回到头

        int n_read = read(fd,&data2,sizeof(int));

        printf("read:%d\n",data2);	//输出read:10

        close(fd);

        return 0;
}

写入一个结构体


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

struct Test{
        int a;
        char c;
};

int main(){
        int fd;

        struct Test data1 = {10,'a'};
        struct Test data2;

        fd = open("./file1",O_RDWR);

        int n_write = write(fd,&data1,sizeof(struct Test));

        lseek(fd,0,SEEK_SET);

        int n_read = read(fd,&data2,sizeof(struct Test));

        printf("read:%d %c\n",data2.a,data2.c);

        close(fd);

        return 0;
}

总结:

不要陷入思维定势!!
*ssize_t write(int fd, const void buf, size_t count);
*ssize_t read(int fd, void buf, size_t count);
write和read的第二个参数,不一定非得是一个字符数组,只要求是一个指针即可,指针的本质就是地址,因此传入一个地址也是可以的,就像上面的两块代码一样,传入&data1也是可以的!

了解fopen和open的区别

  1. 来源:****open是UNIX系统调用函数(包括LINUX),返回的是文件描述符fd,它是文件在文件描述符表里的索引。fopen是标准C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。
    2.移植性fopen是C标准函数,因此有良好的移植性;而open是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数‘CreateFile’。
  2. 适用范围open的适用范围比fopen大,fopen适用于操纵普通正规文件,而UNIX下的一切设备都是以文件的形式操作,如网络套接字、硬件设备等。
  3. 文件IO层次open属于低级IO函数,fopen属于高级IO函数。低级和高级的简单区分标准是:谁离内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。
    5.缓冲fopen都在缓冲区中进行操作,操作外存的次数少,执行速度快,效率高;open需要在用户态和内核态之间切换,效率相对较低

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

今年做电商,视频号小店绝对是明智之举,未来风口就在这里

大家好&#xff0c;我是电商笨笨熊 电商一直是近几年的热门创业方向&#xff1b; 但是面对众多电商平台&#xff0c;对于普通玩家的我们来说&#xff0c;该怎么选择呢&#xff1f; 今年来说&#xff0c;我会更愿意选择视频号小店。 作为一个腾讯推出的电商项目&#xff0c;…

LeetCode例题讲解:移动044

给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0] 输出…

【STM32+HAL】DS18B20读取环境温度

一、准备工作 有关CUBEMX的初始化配置&#xff0c;参见我的另一篇blog&#xff1a;【STM32HAL】CUBEMX初始化配置 二、所用工具 1、芯片&#xff1a; STM32F407VET6 2、IDE&#xff1a; MDK-Keil软件 3、库文件&#xff1a;STM32F4xxHAL库 三、实现功能 串口打印当前温度值…

Day_3

1. HttpClient HttpClient是Apache的一个子项目&#xff0c;是高效的、功能丰富的支持HTTP协议的客户端编程工具包 作用&#xff1a;发送HTTP请求&#xff0c; 接受相应数据 <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>…

Deep Learn Part Six Gated RNN-24.5.1

本章核心一句话&#xff1a; 卸下包袱&#xff0c;轻装上阵。--尼采 总述&#xff1a;本章所学内容 0.引子&#xff1a; 上一章介绍的 RNN 之所以不擅长学习时序数据的长期依赖关系&#xff0c;是因为 BPTT 会发生梯度消失和梯度爆炸的问题。本节我们将首先回顾一下上一章介…

21物联1班shift五次

1.选择推荐选项 2.等待 3.点击取消 4.选择查看问题详细信息 5.点击txt文件 6.找到system文件夹&#xff0c;将sethc改为qqq&#xff0c;将cmd文件改为sethc文件 7.单击完成。重新启动虚拟机。连续按五次shift出现cmd框&#xff0c;修改密码

MySql#MySql安装和配置

目录 一、卸载不需要的环境 二、安装mysql yum 源 三、开始安装 四、如果保证安装成功呢&#xff1f; 五、MySql 启动&#xff01; 六、登录mysql 七、配置文件说明 八、设置开机启动&#xff01; 本次安装是在Linux环境在centos7中完成 首先先将自己切换成root 一、…

彻底搞懂大小端存储and调试中内存窗口如何使用?

定义 首先我们有一个常识&#xff0c;Windows采用小端存储方式。 探究Windows下vs2019是什么存储&#xff1f; 在小端存储方式中&#xff0c;低字节存储在内存的低地址处&#xff0c;高字节存储在内存的高地址处。这与大端存储方式恰好相反&#xff0c;大端存储方式中高字节存…

[图解]DDD领域驱动设计浮夸,Eric Evans开了个坏头

0 00:00:00,630 --> 00:00:02,790 今天我们要讲的是 1 00:00:03,930 --> 00:00:07,420 DDD领域驱动设计浮夸 2 00:00:07,700 --> 00:00:10,590 Eric Evans开了个坏头 3 00:00:14,790 --> 00:00:17,380 在《领域驱动设计》的 4 00:00:18,650 --> 00:00:22,59…

QT:小项目:登录界面 (下一章连接数据库)

一、效果图 登录后&#xff1a; 二、项目工程结构 三、登录界面UI设计 四主界面 四、源码设计 login.h #ifndef LOGIN_H #define LOGIN_H#include <QDialog>namespace Ui { class login; }class login : public QDialog {Q_OBJECTpublic:explicit login(QWidge…

暴露自己IP地址有什么危险

暴露自己的IP地址确实存在一定的危险性&#xff0c;以下是关于这一问题的详细探讨&#xff1a; 一、IP地址的重要性 IP地址是互联网通信中的关键标识&#xff0c;它使得网络中的设备能够相互识别并进行数据传输。在网络世界中&#xff0c;每台设备都需要一个独特的IP地址来确…

2024蓝桥杯CTF writeUP--packet

根据流量分析&#xff0c;我们可以知道129是攻击机&#xff0c;128被留了php后门&#xff0c;129通过get请求来获得数据 129请求ls Respons在这 里面有flag文件 这里请求打开flag文件&#xff0c;并以base64编码流传输回来 获得flag的base64的数据 然后解码 到手

C语言 举例说明循环嵌套

今天 我们来说循环的嵌套 如果一个循环体内 又包含了另一个循环结构 我们称之为循环的嵌套 我们之前学的 While do-while for 都可以进行相互的嵌套 如下图 在 While 循环语句中再嵌套一个 While 循环语句 do-while 中嵌套 do-while for中嵌套 for 例如 我们做一个九九乘法…

mysql中varchar与bigint直接比较会导致精度丢失以至于匹配到多行数据

在mysql中&#xff0c;我们都知道如果一个索引字段使用了函数或者计算那么查询的时候索引会失效&#xff0c;可是我相信在联表的时候我们只会关注两个表关联字段是否都创建了索引&#xff0c;却没有关注过这两个字段的类型是否一致&#xff0c;如果不一致的话索引是会失效的&am…

Redis 实战3

系列文章目录 本文将从跳跃表的实现、整数集合来展开 Redis 实战 Ⅲ 系列文章目录跳跃表的实现跳跃表节点层 前进指针跨度 整数集合的实现升级升级的好处提升灵活性节约内存 降级整数集合 API总结 跳跃表的实现 Redis 的跳跃表由 redis.h/zskiplistNode 和 redis.h/zskiplist…

面向初学者:什么是图数据库

当数据成为关键生产要素&#xff0c;许多企业开始面临利用海量数据辅助企业复杂决策的现实难题。而在数据爆发式增长&#xff0c;关联复杂度激增的趋势下&#xff0c;图数据库成为企业加工关联数据、挖掘隐藏价值、智能决策升级的关键技术之一&#xff0c;在全球范围内开始被使…

如何更快地执行 Selenium 测试用例?

前言&#xff1a; 当我们谈论自动化时&#xff0c;首先想到的工具之一是 Selenium。我们都知道Selenium WebDriver 是一个出色的 Web 自动化工具。实施Selenium 自动化测试的主要原因是加速 selenium 测试。在大多数情况下&#xff0c;Selenium 的性能比手动的要好得多。但是&…

(2024,DONN,OCNN,复数域,交替的非线性激活层与振荡器层,复值反向传播)深度振荡神经网络

Deep Oscillatory Neural Network 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 1. 简介 2. 方法 2.1 深度振荡神经网络&#xff08;DONN&#xff09; 2.2 振荡卷积神经网…

人物特效游戏玩法,门坎低,适合新手上手项目【揭密】

项目简介&#xff1a; 本项目涉及我们日常使用的美肤产品和效果维持&#xff0c;我们需要提交自己的作品&#xff0c;完成官方网站发布的任务。任务完成后&#xff0c;提交审核&#xff0c;一旦审批通过&#xff0c;收益就会到账。 项 目 地 址 &#xff1a; laoa1.cn/1961.…

Python-VBA函数之旅-round函数

目录 一、round函数的常见应用场景 二、round函数使用注意事项 三、如何用好round函数&#xff1f; 1、round函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://blog.csdn.net/ygb_1024?spm1010.2…
最新文章