Linux下的C语言文件编程

概念引入


window ,linux如何修改一个文件,比如写一个word文档:

    打开/创建文件 -->编辑文件 -->保存文件 -->关闭文件


我们需要使用代码自动化完成以上操作: 


操作系统(linux)给我们提供了一系列的API:
打开: open
读写: read/write
光标定位: lseek
关闭: close

===========================================

文件描述符:


也就是文件的索引, 对于内核而言,所有文件都由文件描述符引用。 文件描述符是一个非负整数。
打开/创建文件-- 返回文件描述符
读写文件需要文件描述符作为参数传递

注意:  文件描述符的作用域是当前进程 ,出了这个进程文件,描述符没有任何意义

linux 系统默认文件描述符
 0 -- >标准输入(也就是键盘) 1-->标准输出   2 -->标准错误, so我们open文件的时候返回的fd从3开始 
 0  1  2对应的宏分别为:  STDIN_FILENO   STDOUT_FILENO  STDERR_FILENO

------------------
编程应用:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

int main()
{
 char readBuf[128];
 read(0,readBuf,5);
 write(1,readBuf,strlen(readBuf));


 puts("");
  return 0;
}
--------------------------------
 注意: 使用完文件后,要close() 关闭,防止文件损坏

存在磁盘中的文件  -- 静态文件
open 静态文件 后,在linux 内核产生结构体,来存放fd,buf(内存)等数据 -- 这时候就是动态文件
调用close() -- 会把缓冲区buf的所有东西写入磁盘中
// 为什么需要动态文件:磁盘的最小读取单位就是一个块。属于块设备
快设别十分的不灵活,是快读写,而内存是按字节单位操作的,而且可以随机操作,很灵活


打开/创建文件:

打开文件open()

返回值 --文件描述符,起到索引作用


需要头文件: 
<sys/types.h><sys/stat.h> <fcntl.h>

函数原型

int open(const char*pathname,int flags);
int open(const char*pathname,int flags,mode_t mode);


pathname --要打开的的文件路径,可省略--当前路径
flags 打开方式:O_RDONLY     只读打开           O_WRONLY   只写打开       O_RDWR 可读可写
以上常数只能指定一个 ,但是以下常数可选择:
flags|后续常数:
O_CREAT -- 若文件不存在就创建他
O_EXCK 如果同时指定了O_CRATE,文件已经存在,则返回值为-1 --> 判断文件是否存在
O_APPEND  -- 从文件的末尾写入数据 -- 如果不加 append 的话,原来的内容可能会被覆盖
O_TRUNC  属性去打开文件时,if这个文件是有内容的,而且为只读or只写成功打开。则将其长度截短为0
 --意识就是清空文件,然后重写写入内容

mode: 文件权限:
常用 权限:
1.可读   r  --4
2.可写   w --2
3.执行:x  --1
比如6:  4+2 rw_

0600 -- 给文件所有者读写权限

-------------------------------------------------------

为了简化表达,我们还可以采取数字表示代替ugo,二进制0~7代表三种权限:
把rwx记为421 : r-4 w-2 x-1
0:无任何权限 000 ---
1: 只有x权限 000 --x 
2:只有w权限 010 -w-
3:011 -wx
4:100 r--
5: 101 r-x  
6: 110    rw-
7:全部权限:111 rwx
————————————————

文件权限详细理解和操作,建议移步 3 linux入门 -- 用户和权限-CSDN博客


创建文件:create()


需要头文件: 
<sys/types.h><sys/stat.h> <fcntl.h>

返回值也是  fd -- 文件描述符


函数原型:


int create(const char *filename,mode_t mode);
filename: 创建文件名,包含路径,省略就是当前路径
mode 创建模式//以什么权限创建

常见mode:
S_IRUSR  4  可读
S_IWUSR 2  可写
S_IXUSR  1  可执行
S_IRWXU 7  可读,写,执行

验证程序:

-------------------------

case1 -- open正常打开返回值

if 文件存在就放回 3,4,5等 非负整数,不存在放回-1



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


int main()
{
 int fd;
 fd=open("./file1",O_RDWR);
 printf("fd=%d\n",fd);

  return 0;
}

--------------------


case2:文件不存在,我们使用O_CREAT创建

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


int main()
{
 int fd;
 fd=open("./file1",O_RDWR);
 if(fd==-1){
   puts("open fail!!!");
   fd=open("./file1",O_RDWR|O_CREAT,0600);
   if(fd>0){
    printf("create succeed fd=%d\n",fd);
   }
 }


  return 0;
}
----------------------------------


case3: O_EXCL验证文件是否存在

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

int main()
{
 int fd;
 char *buf="mxdashuaibi";
 fd=open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
 if (fd==-1)
 {
  puts("文件已经存在。");
 }
 
 close(fd);
  return 0;
}


题外话 -怎么判断-1 ---位运算:  ~fd  --> -1 取反为0,-1 的补码是 11111111 反码就是 00000000

========================================


文件写入操作 write ()


函数原型:
ssize_t write(int fd,const void *buf,size_t count);
需要头文件: <unistd.h>

返回值:  写入成功返回写入大小 ,失败返回-1
fd--文件操作符 
buf -- 缓冲区
 count -- 需要向文件写入的大小
意思: buf指针指向的缓冲区拿出count的空间写入数据到fd指向的空间中(目标文件中)

注意:这里不要用sizeof 拿到buf 的大小 -- 因为buf是一个指针只能读取8个字节大小的数据

case: write 基本用法:

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


int main()
{
 int fd;
 char *buf="mxdashuaibi";
 fd=open("./file1",O_RDWR);
 if((~fd)){
   puts("open fail!!!");
   fd=open("./file1",O_RDWR|O_CREAT,0600);
   if(fd>0){
    printf("create success fd=%d\n",fd);
   }
 }
 puts("写操作。");
 ///write(fd,(void*)buf,sizeof(buf)); //错误示范
 write(fd,(void*)buf,strlen(buf));
 close(fd);
  return 0;
}
 

=============


关闭文件 -- close

头文件 <unistd.h>

int close(int fd);

返回值: 0 -- 成功  -1 -- 失败

===========================


读取文件 : read()

函数原型:
ssize_t read(int fd,const void *buf,size_t count);

头文件:<unistd.h>
返回值: 读到多少字节返回多少字节 -- 读到文件尾巴--返回0,读取失败 -1

注意

如果 在read之前进行了 写操作,我们的的光标位置应该在最后一次写的操作,一般就是文件末尾

这时候读取的数据是不准确的,我们需要将光标移动 到头: 两种方式
1.移动光标到头
2.重新打开文件

case: 基本读取操作


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

int main()
{
 int fd;
 char *buf="mxdashuaibi";
 fd=open("./file1",O_RDWR);
 if((~fd)){
   puts("open fail!!!");
   fd=open("./file1",O_RDWR|O_CREAT,0600);
   if(fd>0){
    printf("create success fd=%d\n",fd);
   }
 }
 puts("写操作。");
 ///write(fd,(void*)buf,sizeof(buf)); //错误示范
 int cnt_w=write(fd,(void*)buf,strlen(buf));
if(cnt_w!=-1){
 printf("Have writed %d byte to file1.\n",cnt_w);
}
 close(fd);
 fd=open("./file1",O_RDWR);
char *readBuf =(char*)malloc(sizeof(char)*(cnt_w+1));
int cnt_r=read(fd,readBuf,cnt_w);
 printf("Have read %d byte to file1.\n",cnt_r);
 close(fd);
  return 0;
}


================================


光标移动操作: lseek


函数原型: 
off_t lseek(int fd,off_t offset,int whence) -- 将文件读写指针相对whnece 移动  offset个字节


需要头文件:<sys/types.h> <unistd.h>


whence 包括三个宏:
SEEK_SET  -- 文件头
SEEK_END ---文件尾
SEEK_CNT--当前光标位置

offset -- 对whence 的一个偏移值

返回值: 针对文件头 偏移了多少个字节 -- 可以用来计算文件大小

case:怎么计算文件大小:

int FileSize=lseek(fd, 0,SEEK_END);

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

int main()
{
 int fd;
 char *buf="mxdashuaibi";
 fd=open("./file1",O_RDWR);

 ///write(fd,(void*)buf,sizeof(buf)); //错误示范
 int cnt_w=write(fd,(void*)buf,strlen(buf));
 int fileSize = lseek(fd,0,SEEK_END);
 printf("fileSize: %d\n",fileSize);

 close(fd);
  return 0;
}

命令应用实例:


实现linux cp命令的代码:

命令格式; 
cp src.c des.c

C语言参数:
int main(char  argc, char**argv);
argc -- 参数的总个数
argv -- 包含的参数,每一个参数都是一个数组  ./aout(cp)  src des


思路: 
1.打开 src.c
2.读取src.c的全部数据到buf
3.创建一个新文件 des.c
4.将buf里面的内容写入des.c
5.关闭两个 文件


gcc demo.c -o mycp // -o指定生成的可执行文件名字
./mycp
     
写自己的cp命令


#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char **argv)
{
    int fdSrc;
    int fdDes;
    char *readBuf=NULL;
    if (argc != 3)
    {
        puts("param error!");
        exit(-1);
    }


    fdSrc=open(argv[1],O_RDWR);
    int size = lseek(fdSrc,0,SEEK_END);
    lseek(fdSrc,0,SEEK_SET);//记把光标位置移动到头,不然下面的read读不到数据
    readBuf= (char *)malloc(sizeof(char)*size);
    int n_read=read(fdSrc,readBuf,size);
  
    fdDes=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);// 新文件设为读写权限,if文件不存在创建一个,if文件已经存在删除全部内容添加我们拷贝的内容
    int n_write=write(fdDes,readBuf,strlen(readBuf));

    close(fdDes);
    close(fdSrc);
    return 0;
}

==================================
 

编程实现修改文件里面的某一项:


把文件第二行 length = 3;  的3修改为4

涉及字符串的操作,比如我们的有几个常用API:
strstr() -- 在一个3母串里面去找一个子串,并返回子串的位置,没找到就返回NULL


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

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

    char *readBuf = NULL;
    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, "length=");
    if (p == NULL)
    {
        puts("not found");
        exit(-1);
    }
    p = p + strlen("length=");
    *p = '5';

    // close(fdSrc);
    // fdSrc = open(argv[1], O_RDWR|O_TRUNC);
    lseek(fdSrc,0,SEEK_SET);

    write(fdSrc,readBuf,strlen(readBuf));
    close(fdSrc);

    return 0;
}

================================


写入一个整数/结构体到文件: 

一个整数

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

int main()
{
     int fdSrc;
    int data={100,'b'};
    int data2;
   
    fdSrc = open("./file1", O_RDWR);
   int n_write = write(fdSrc,&data,sizeof(int));
    lseek(fdSrc, 0, SEEK_SET);
   int n_read=read(fdSrc,&data2,sizeof(int));
   printf("data2 = %d\n",data2);
    close(fdSrc);

    return 0;
}

一个结构体


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

struct Test
{
int a;
char b;
};

int main()
{
     int fdSrc;
     struct Test data={100,'b'};
     struct Test data2;
   
    fdSrc = open("./file1", O_RDWR);
   int n_write = write(fdSrc,&data,sizeof(struct Test));
    lseek(fdSrc, 0, SEEK_SET);
   int n_read=read(fdSrc,&data2,sizeof(struct Test));
   printf("data2 = %d,%c\n",data2.a,data2.b);
    close(fdSrc);

    return 0;
}

多个结构体:


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

struct Test
{
int a;
char b;
};


int main()
{
     int fdSrc;
     struct Test data[2]={{100,'b'},{101,'c'}};
     struct Test data2[2];
   
    fdSrc = open("./file1", O_RDWR);
    int n_write = write(fdSrc,&data,sizeof(struct Test)*2);
    lseek(fdSrc, 0, SEEK_SET);
    int n_read=read(fdSrc,&data2,sizeof(struct Test)*2);
    printf("data2[0] = %d,%c\n",data2[0].a,data2[0].b);
    printf("data2[1] = %d,%c\n",data2[1].a,data2[1].b);
    close(fdSrc);

    return 0;
}


 

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

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

相关文章

【攻防世界】mfw(.git文件泄露)

首先进入题目环境&#xff0c;检查页面、页面源代码、以及URL&#xff1a; 发现页面无异常。 使用 dirsearch 扫描网站&#xff0c;检查是否存在可访问的文件或者文件泄露&#xff1a; 发现 可访问界面/templates/ 以及 .git文件泄露&#xff0c;故使用 GItHack 来查看泄露的 …

C语言奇技淫巧之--用宏定义替换函数名的另外一种思路

时间有限&#xff0c;简要记录原理。 快速回忆要点&#xff1a; #if definde(FEATURE_A) #define myfunc _myfunc #endif int myfunc(int a, int b) 场景&#xff1a; 假设某个功能函数针对不同的makefile配置需要有不同的函数名字&#xff0c;通常做法如下&#xff1a; #if …

传统方法(OpenCV)_车道线识别

一、思路 基于OpenCV的库&#xff1a;对视频中的车道线进行识别 1、视频处理&#xff1a;视频读取 2、图像转换&#xff1a;图像转换为灰度图 3、噪声去除&#xff1a;高斯模糊对图像进行去噪&#xff0c;提高边缘检测的准确性 4、边缘检测&#xff1a;Canny算法进行边缘检测…

状态模式(行为型)

目录 一、前言 二、状态模式 三、总结 一、前言 状态模式(State Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许一个对象在其内部状态改变时改变它的行为。对象看起来好像修改了它的类&#xff0c;但实际上&#xff0c;由于状态模式的引入&#xff0c;行为的变…

Python单元测试pytest捕获日志输出

使用pytest进行单元测试时&#xff0c;遇到了需要测试日志输出的情况&#xff0c;查看了文档 https://docs.pytest.org/en/latest/how-to/capture-stdout-stderr.html https://docs.pytest.org/en/latest/how-to/logging.html 然后试了一下&#xff0c;捕捉logger.info可以用…

CentOS 7.9 额外安装一个Python3.x版本详细教程

Centos7默认的python版本是2.7&#xff0c;根据需要我们额外安装一个Python3.x版本。 1、安装基础环境 yum update -yyum -y groupinstall "Development tools"yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel psmisc …

ArchiveBo

目录 1、 ArchiveBo 2、 BackResponseBo 3、 RelationshipVoKey 3.1、 * 内容主键 3.2、 * 项目主键

大语言模型及提示工程在日志分析任务中的应用 | 顶会IWQoS23 ICPC24论文分享

本文是根据华为技术专家陶仕敏先生在2023 CCF国际AIOps挑战赛决赛暨“大模型时代的AIOps”研讨会闪电论文分享环节上的演讲整理成文。 BigLog&#xff1a;面向统一日志表示的无监督大规模预训练方法 BigLog: Unsupervised Large-scale Pre-training for a Unified Log Represen…

【azure笔记 1】容器实例管理python sdk封装

容器实例管理python sdk封装 测试结果 说明 这是根据我的需求写的&#xff0c;所以有些参数是写死的&#xff0c;比如cpu核数和内存&#xff0c;你可以根据你的需要自行修改。前置条件&#xff1a; 当前环境已安装python3.8以上版本和azure cli并且已经登陆到你的账户 依赖安…

学习java第三十八天

Spring事务传播行为&#xff1a; PROPAGATION_REQUIRED(默认) 如果当前没有事务&#xff0c;就新建一个事务&#xff0c;如果已经存在一个事务中&#xff0c;加入到这个事务中 PROPAGATION_SUPPORTS 支持当前事务&#xff0c;如果当前没有事务&#xff0c;就以非事务方式执行…

RocketMQ之Topic和Tag最佳实践

一、Topic是什么&#xff1f;它的作用&#xff1f; Topic即主题&#xff0c;是消息队列中用于对消息进行分类和组织的一种机制&#xff0c;它有以下三种作用&#xff1a; 标识消息分类&#xff1a;RocketMQ的主题用于对消息进行分类和组织。通过为不同类型的消息分配不同的主题…

Python八股文:基础知识Part1

1. 不用中间变量交换 a 和 b 这是python非常方便的一个功能可以这样直接交换两个值 2. 可变数据类型字典在for 循环中进行修改 这道题在这里就是让我们去回答输出的内容&#xff0c;这里看似我们是在for循环中每一次加入了都在list中加入了一个字典&#xff0c;然后字典的键值…

本地项目提交 Github

工具 GitIdeaGithub 账号 步骤 使用注册好的 Github 账号&#xff0c;登陆 Github&#xff1b; 创建 Repositories (存储库)&#xff0c;注意填写图上的红框标注&#xff1b; 创建完成之后&#xff0c;找到存储库的 ssh 地址或 https 地址&#xff0c;这取决于你自己的配置…

TiDB 组件 GC 原理及常见问题

本文详细介绍了 TiDB 的 Garbage Collection&#xff08;GC&#xff09;机制及其在 TiDB 组件中的实现原理和常见问题排查方法。 TiDB 底层使用单机存储引擎 RocksDB&#xff0c;并通过 MVCC 机制&#xff0c;基于 RocksDB 实现了分布式存储引擎 TiKV&#xff0c;以支持高可用分…

云服务运维

监控指标介绍 服务器监控 CPU状态&#xff1a;cpu使用率、负载 内存状态&#xff1a;应用内存使用率、物理内存使用量 磁盘状态&#xff1a;分区大小、使用趋势 IO状态&#xff1a;IOPS、MBPS、每秒读写速率、await 网卡状态&#xff1a;网络出入流量Bps、pps、丢包率、TCP状…

C语言-教案习题巩固(难度跟题目序号无关,选择性去练习)

1,将一个一位数组a[10]中的元素值按逆序重新存放.假定数组中原来元素顺序为:1,3,5,7,9,8,6,4,2,0,按逆序重新存放后元素的值位:0,2,4,6,8,9,7,5,3,1。要求&#xff1a;在程序中将数组初值初始化&#xff0c;输出逆序重新存放后元素的值。 2&#xff0c;给定2维数组如下&#x…

跨框架探索:React Redux 和 Vuex 对比分析快速掌握React Redux

React Redux 和 Vuex 都是前端状态管理库&#xff0c;分别用于 React 和 Vue.js 框架。 它们都提供了一套规范的状态管理机制&#xff0c;帮助开发者更好地组织和管理应用状态。下面是它们的一些异同点&#xff1a; 相同点&#xff1a; 中心化状态管理&#xff1a;两者都提…

好用的前端框架及插件!!!

jQuery 对原生JS进行了封装&#xff0c;我们主要使用AJAX&#xff0c;DOM元素的操作相关的方法 官网:https://jquery.com HTML&#xff0c;CSS&#xff0c;JavaScript&#xff0c;jQuery相关中文资料网上有很多&#xff0c;可自行搜索 Bootstrap 定义了HTML元素的样式&…

tailwindcss+vue3+vite+preline项目搭建

最近原子化样式比较火&#xff0c;用了一下确实还不错&#xff0c;也确实是用一些标准的样式能够使网页看起来比较统一&#xff0c;而且能够极大的减轻起名字的压力&#xff0c;有利有弊&#xff0c;就不一一细说了。 之前开发都是习惯于使用vitevue3来开发的&#xff0c;此次搭…

Rocky(Centos)数据库等高并发或高io应用,linux应调优系统

一、系统参数优化 默认的最大打开文件数是1024.不满足生产环境的要求。按照如下配置&#xff1a; 1、修改 systemctl管理的 servie 资源限制 编辑/etc/systemd/system.conf # 全局的打开文件数 DefaultLimitNOFILE2097152 # 全局打开进程数 DefaultLimitNPROC655352、调整系…