Linux中对文件的操作(二)

本文详细解释了Linux系统中文件描述符fd的概念和使用,介绍了open,read,write的基本操作,强调了文件操作流程和注意事项,以及fopen与open的区别,包括它们的适用范围、移植性和IO层次。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件描述符

文件描述符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需要在用户态和内核态之间切换,效率相对较低
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值