Linux中对文件的操作(二)

文件描述符

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

c 复制代码
#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进行参数拆解。代码如下:

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命令

c 复制代码
#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.返回子串的起始位置。

c 复制代码
#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

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

c 复制代码
#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;
}

写入一个结构体

c 复制代码
#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需要在用户态和内核态之间切换,效率相对较低
相关推荐
挥剑决浮云 -16 分钟前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记
一颗星星辰1 小时前
C语言 | 第十章 | 函数 作用域
c语言·开发语言
꧁༺❀氯ྀൢ躅ྀൢ❀༻꧂1 小时前
实验4 循环结构
c语言·算法·基础题
小O_好好学1 小时前
CentOS 7文件系统
linux·运维·centos
从0至12 小时前
力扣刷题 | 两数之和
c语言·开发语言
x晕x2 小时前
Linux dlsym符号查找疑惑分析
linux·运维·服务器
小比卡丘2 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
一个不知名程序员www2 小时前
leetcode第189题:轮转数组(C语言版)
c语言·leetcode
冷白白2 小时前
【C++】C++对象初探及友元
c语言·开发语言·c++·算法