自学内容网 自学内容网

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;
}


 


原文地址:https://blog.csdn.net/mx_jun/article/details/137548114

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!