• Linux文件编程API的使用


    目录

    打开文件open( )函数

    文件写入write( )函数

    光标移动lseek( )函数

    文件操作原理简述

    文件操作实现CP指令

    文件编程修改程序的配置文件

    写一个整数,一个结构体,一个结构体数组到文件

    标准库c库对文件的操作

    linux文件权限查看和修改


    打开文件open( )函数

    函数原型:

    返回值:

    返回一个文件描述符,如果打开失败返回-1.

    参数说明:

    Pathname:要打开的文件名

    Flags:O_RDONLY 只读打开   O_WRONLY 只写打开   O_RDWR 可读可写打开

    当我们附带了权限后,打开的文件就只能按照这种权限来操作。

    以上这三个常数中应当只指定一个。下列常数是可选择的:

           O_CREAT 若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限。

           O_EXCL 如果同时指定了O_CREAT ,而文件已经存在,则出错。

           O_APPEND 每次写时都加到文件的尾端。

           O_TRUNC属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。

     Mode:一定是在flags中使用了O_CREAT标志,mode记录待创建的文件的访问权限

    代码示例:

    1. #include
    2. #include
    3. #include
    4. #include
    5. int main(void)
    6. {
    7. int fd;
    8. fd = open("./file1",O_RDWR); //打开当前路径下的file1文件,如果打开失败返回-1
    9. printf("fd = %d\n",fd);
    10. return 0;
    11. }
    1. #include
    2. #include
    3. #include
    4. #include
    5. int main(void)
    6. {
    7. int fd;
    8. fd = open("./file1",O_RDWR); //打开当前路径下的file1文件,如果打开失败返回-1
    9. if(-1 == fd)
    10. {
    11. printf("we failed to open file1!\n");
    12. }
    13. fd = open("./file1",O_RDWR|O_CREAT,0700);
    14. if(fd > 0)
    15. {
    16. printf("we create file1 successfully!\n");
    17. }
    18. return 0;
    19. }

    文件写入write( )函数

    函数原型:

    参数说明:

    fd:文件描述符

    buf:是你指定的缓存区,即指针,通常是一个字符串,需要写入的字符串

    count:写入文件指定的字节数

    返回值:

    写入成功返回写入 的字节数,写入失败返回-1.

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main ()
    8. {
    9. int fd;
    10. char *buf ="hello world";
    11. int n_write;
    12. /*打开当前路径下的file文件,如果文件file不存在,就以0600的权限创建*/
    13. fd = open("./file",O_RDWR|O_CREAT,0600);
    14. n_write = write(fd,buf,strlen(buf));
    15. printf("写入的字节数为:n_wirte=%d\n",n_write);
    16. close(fd);//关闭文件
    17. return 0;
    18. }

    光标移动lseek( )函数

    函数原型:

    lseek(int fd, off_t offset, int whence);
    参数说明:

    fd:文件描述符

    whence:

    有以下三个宏:

    SEEK_SET:文件起始位置

    SEEK_CUR:文件当前读写位置

    SEEK_END:文件末尾位置

    offset:

    从whence指定的位置,向前或者向后移动指定字节数

    offset为正数,向前移动指定字节数

    offset为负数,向后移动指定字节数

    返回值:lseek调用成功时返回目前的读写位置,也就是距离文件开头多少个字节。失败返回-1.

    可以用lseek计算文件的大小,whence为SEEK_END,同时offset的值为0。代码如下

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main ()
    8. {
    9. int fd;
    10. int size;
    11. fd = open("./file",O_RDWR);//打开当前路径file文件
    12. size = lseek(fd,0,SEEK_END);//光标定位在文件尾部,同时相对于尾部的偏移值为0
    13. printf("size = %d\n",size);
    14. close(fd);
    15. return 0;
    16. }

    文件操作原理简述

    文件描述符:

    1.对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。

    按照惯例,UNIX shell 使用文件描述符0与进程的标准输入相结合,文件描述符1与标准输出相结合,文件描述符2与标准错误输出相结合。STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO这几个宏代替了0,1,2这几个数。

    3.文件描述符,这个数字在一个进程中表示一个特定含义,当我们open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护的这个动态文件的这些数据结构绑定上了,以后我们应用程序如果要操作这个动态文件,只需要用这个文件描述符区分。

    3.文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main ()
    7. {
    8. char readbuf[128];
    9. read(0,readbuf,sizeof(readbuf));//从标准输入中读取数据到readbuf里面
    10. write(1,readbuf,strlen(readbuf));//把readbuf里面的数据写入标准输出
    11. // printf("\n");
    12. return 0;
    13. }

    1.在linux中要操作一个文件,一般时先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或者其他操作),最后是close关闭文件即可。

    2.强调一点:我们对文件进行操作时,一定要先打开文件,打开成功之后才能操作,如果打开失败,就不用进行后边的操作了,最后读写完成后,一定要关闭文件,否则会造成文件损坏。

    3.文件平时是存放在块设备中的文件系统文件中的,我们把这种文件叫静态文件,当我们去open打开一个文件时,linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核中特定地址管理存放(叫动态文件)。

    4.打开文件以后,以后对这个文件的读写操作,都是针对内存中的这一份动态文件的,而并不是针对静态文件的。当然我们对动态文件进行读写以后,此时内存中动态文件和块设备文件中的静态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件。

    5.为什么这么设计,不直接对块设备直接操作

    块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。比如:一块就有100个字节,如果想修改hello world中一个字节是做不到的,因为对磁盘来所最小的读取单位就是100个字节。

    文件操作实现CP指令

    思路:

    1.打开src源文件

    2.读取src源文件数据到buffer里面

    3.打开或者创建des目标文件

    4.将buffer里面  的数据写入des目标文件

    5.关闭src源文件和des目标文件

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main (int argc,char **argv)
    9. {
    10. int src_fd;
    11. int des_fd;
    12. int size;
    13. int n_read;
    14. int n_write;
    15. char *buffer = NULL;
    16. if(argc != 3)
    17. {
    18. printf("param error!\n");
    19. exit(-1);
    20. }
    21. src_fd = open(argv[1],O_RDWR);
    22. size = lseek(src_fd,0,SEEK_END);//获取文件的大小
    23. buffer = (char *)malloc(size+8);
    24. lseek(src_fd,0,SEEK_SET);//让光标复位
    25. /*读取数据*/
    26. n_read = read(src_fd,buffer,size);
    27. if(n_read == -1)
    28. {
    29. printf("读取失败\n");
    30. exit(-1);
    31. }
    32. des_fd = open(argv[2],O_RDWR|O_TRUNC|O_CREAT,0600);
    33. n_write = write(des_fd,buffer,strlen(buffer));
    34. if(n_write == -1)
    35. {
    36. printf("写入失败!\n");
    37. exit(-1);
    38. }
    39. close(src_fd);
    40. close(des_fd);
    41. return 0;
    42. }

    文件编程修改程序的配置文件

    思路:

    1.打开配置文件

    2.将数据读到buffer里面

    3.在buffer里面找到需要修改的子字符串

    4.指针偏移至我们需要修改的地方

    5.修改后重新将buffer里面的数据写入配置文件里面去

    6.关闭配置文件

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main (int argc,char **argv)
    8. {
    9. int config_fd;
    10. int size;
    11. int n_write;
    12. char *buffer = NULL;
    13. int n_read;
    14. char *substring = NULL;
    15. if(argc != 2)
    16. {
    17. printf("param error!\n");
    18. exit(-1);
    19. }
    20. /*打开配置文件*/
    21. config_fd = open(argv[1],O_RDWR);
    22. if(config_fd == -1)
    23. {
    24. printf("打开配置文件失败!\n");
    25. exit(-1);
    26. }
    27. /*计算文件的大小*/
    28. size = lseek(config_fd,0,SEEK_END);
    29. lseek(config_fd,0,SEEK_SET);//光标复位
    30. buffer = (char *)malloc(size+8);
    31. /*把config文件里面的数据读到buffer里面*/
    32. n_read = read(config_fd,buffer,size);
    33. if(n_read == -1)
    34. {
    35. printf("写入失败!\n");
    36. exit(-1);
    37. }
    38. /*查找需要修改的子字符串*/
    39. substring = strstr(buffer,"SPEED=");
    40. if(substring == NULL)
    41. {
    42. printf("查找失败!\n");
    43. exit(-1);
    44. }
    45. /*指针偏移至需要修改的位置并修改内容*/
    46. substring = substring + strlen("SPEED=");
    47. *substring = '9';
    48. substring++;
    49. *substring = '9';
    50. /*重新写入到文件里面*/
    51. lseek(config_fd,0,SEEK_SET);
    52. n_write = write(config_fd,buffer,size);
    53. if(n_write == -1)
    54. {
    55. printf("写入失败!\n");
    56. exit(-1);
    57. }
    58. /*关闭配置文件*/
    59. close(config_fd);
    60. return 0;
    61. }

    写一个整数,一个结构体,一个结构体数组到文件

    写一个整数到文件,wirte函数原型write(int fd, const void *buf, size_t count)中第二个参数是无类型的指针,写入一个整数data只需要把data的地址作为参数即可。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main ()
    7. {
    8. int fd;
    9. int data = 7878;
    10. int data2;
    11. /*打开当前路径的file1文件,如果不存在就以0600的权限创建他*/
    12. fd = open("./file1",O_RDWR|O_CREAT,0600);
    13. /*将data写入文件*/
    14. write(fd,&data,sizeof(int));
    15. lseek(fd,0,SEEK_SET);//光标复位
    16. /*将数据读取到data2*/
    17. read(fd,&data2,sizeof(int));
    18. printf("%d",data2);
    19. close(fd);
    20. }

    写一个结构体到文件,wirte函数原型write(int fd, const void *buf, size_t count)中第二个参数是无类型的指针,写入一个结构体只需要把结构体的地址作为参数即可。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. struct Test{
    7. int a;
    8. char b;
    9. };
    10. int main ()
    11. {
    12. int fd;
    13. struct Test t1 = {18, 'y'};
    14. struct Test t2;
    15. /*打开当前路径的file1文件,如果不存在就以0600的权限创建他*/
    16. fd = open("./file1",O_RDWR|O_CREAT,0600);
    17. /*将t1写入文件*/
    18. write(fd,&t1,sizeof(struct Test));
    19. lseek(fd,0,SEEK_SET);//光标复位
    20. /*将数据读取到t2*/
    21. read(fd,&t2,sizeof(struct Test));
    22. printf("%d,%c\n",t2.a,t2.b);
    23. close(fd);
    24. }

    写一个结构体数组到文件,同理即可

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. struct Test{
    7. int a;
    8. char b;
    9. };
    10. int main ()
    11. {
    12. int fd;
    13. struct Test t1[2] = {{18, 'y'},{19,'j'}};
    14. struct Test t2[2];
    15. /*打开当前路径的file1文件,如果不存在就以0600的权限创建他*/
    16. fd = open("./file1",O_RDWR|O_CREAT,0600);
    17. /*将t1写入文件*/
    18. write(fd,&t1,sizeof(struct Test)*2);
    19. lseek(fd,0,SEEK_SET);//光标复位
    20. /*将数据读取到t2*/
    21. read(fd,&t2,sizeof(struct Test)*2);
    22. printf("%d,%c\n",t2[0].a,t2[0].b);
    23. printf("%d,%c\n",t2[1].a,t2[1].b);
    24. }
    25. ~

    标准库c库对文件的操作

    fopen函数的使用:

    函数原型:

    FILE *fopen(const char *pathname, const char *mode);

    参数说明:

    filename 文件名称

    mode 打开模式:

    r      只读方式打开一个文本文件

    rb    只读方式打开一个二进制文件

    w     只写方式打开一个文本文件

    wb   只写方式打开一个二进制文件

    a      追加方式打开一个文本文件

    ab    追加方式打开一个二进制文件

    r+     可读可写方式打开一个文本文件

    rb+   可读可写方式打开一个二进制文件

    w+    可读可写方式创建一个文本文件

    wb+  可读可写方式生成一个二进制文件

    a+     可读可写追加方式打开一个文本文件

    ab+   可读可写方式追加一个二进制文件

    返回值:

    文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno 中。

    fread函数的使用:

    函数原型:

    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
    

    参数说明:

    • ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
    • size -- 这是要读取的每个元素的大小,以字节为单位。
    • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

    返回值:成功就返回读取元素的个数

    fwrite函数的使用:

    函数原型:

    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

    参数说明:

    • ptr -- 这是指向要被写入的元素数组的指针。
    • size -- 这是要被写入的每个元素的大小,以字节为单位。
    • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。

    返回值:成功就返回写入元素的个数

    fseek函数的使用:

    函数原型:

    int fseek(FILE *stream, long int offset, int whence)

    参数说明:

    • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
    • offset -- 这是相对 whence 的偏移量,以字节为单位。
    • whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
    常量描述
    SEEK_SET文件的开头
    SEEK_CUR文件指针的当前位置
    SEEK_END文件的末尾

    返回值:如果成功,则该函数返回零,否则返回非零值。

    1. #include
    2. #include
    3. int main ()
    4. {
    5. FILE *fd;
    6. char *p = "hello world";
    7. char readbuf[128];
    8. fd = fopen("./file1234","w+");
    9. fwrite(p,sizeof(char),strlen(p),fd);
    10. fseek(fd,0,SEEK_SET);//光标复位
    11. fread(readbuf,sizeof(char),strlen(p),fd);
    12. printf("readbuf:%s\n",readbuf);
    13. fclose(fd);
    14. return 0;
    15. }

    linux文件权限查看和修改

     查看文件权限指令  ls -l ,查看单个就加个文件名就行ls  -l  filename(filename代表你要查看的文件名)

    文件权限一共10位,如下图所示:

    rwx分表代表:

    r------可读,即read

    w-----可写,即write

    x------可执行,查了字典执行的单词是execute,不知道为啥是x而不是e。

    第一位代表类型:-代表文件,d代表文件夹。后面每三位一组。

    第一组---------代表用户------user

    第二组---------代表同组用户-----group

    第三组---------代表的是其他用户-------other

     修改文件的权限指令chmod(change mode的缩写)

      rwx也可以用数字代替:

    r ----------------4

    w----------------2

    x-----------------1

    例如:将权限为-rwxrwxrwx的文件改成权限为-rwxr-xr-x

    方法一:

    改变后的权限由777变成了755,修改权限操作如下图:

    方法二:

    如下图所示,usr组权限没变,group组权限减去了可写权限,other组权限减去了可写权限

    修改权限操作如下:

  • 相关阅读:
    QT-串口工具
    抗旱稳粮保秋收 国稻种芯-绥阳县:组织了93名农技人员指导
    Vue3+Element-Plus项目 el-table 拖拽排序实现,Vue3项目sortablejs的安装与使用
    【c语言】推箱子
    哈希表的实现(哈希捅)
    剑指 Offer 04. 二维数组中的查找
    如何解决跨域?
    vue 如何在 style 标签里使用变量(数据)
    C语言-汉诺塔问题
    基于Python的QQ音乐音频图片搜索系统
  • 原文地址:https://blog.csdn.net/qq_55299368/article/details/126045900