02 Linux编程-文件

1、文件描述符

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

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

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

        文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了。open函数打开文件,打开成功返回一个文件描述符,打开失败,返回-1。

2、打开/创建文件

        要包含头文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcnt.h>
//函数原型
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
//pathname:要打开的文件名(含路径,缺path则为当前路径)
//flags:O_RDONLY只读打开 O_WRONLY只写打开 O_RDWR可读可写打开//当我们附带了权限之后,打开的文件就只能按照这种权限来操作//以上这三个常数中应当只指定一个,下列常数是可选择的//eg: open("./file1", O_RDWR | O_CREAT, 0600);//O_CREAT 若文件不存在,则创建它。使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限//O_EXCL 如果同时指定了O_CREATE,而文件已经存在,则出错//O_APPEND 每次写时都加到文件的尾端//O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或者只写成功打开,则将其长度截断为0
//mode:一定是在flags中使用了O_CREAT 标志,mode记录待创建的文件的访问权限

 3、写入文件

        要包含头文件

#include <unistd.h>
//函数原型
ssize_t write(int fd, const void *buf, size_t count);
//fd 文件描述符,打开的文件
//
//

4、关闭文件

         要包含头文件

#include <unistd.h>
//函数原型
int close(int fd);
//fd 文件描述符,打开的文件
//
//

 5、读取文件

        要包含头文件

#include <unistd.h>
//函数原型
ssize read(int fd, void *buf, size_t count);
//fd 文件描述符,打开的文件
//
//

         注意,文件打开会有光标,写文件和读文件都是从光标所在处开始的,一开始打开文件,光标在文件开头,写完文件不关闭文件时,这时光标一般在文件的末尾,那么此时读取文件就是从末尾开始读了,会什么都读不到,那么在读之前可以将光标移动至开头或者将文件关闭重新打开。

6、移动文件光标位置

        要包含头文件

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//fd:文件描述符,打开的文件
//offset:偏移值//相对whence的一个偏移值
//whence://SEEK_SET:文件的头//SEEK_END:文件的尾巴//SEEK_CUR:当前光标位置

7、文件编程的一般步骤

        打开/创建文件--读取/写入文件--关闭文件

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

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

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

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

        (5)为什么这么设计,不直接对块设备直接操作?因为块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。

8、使用文件编程的例子

8.1 实现linux cp命令

#将a文件复制到b文件
cp a.c b.c    

        实现这个功能的前提要先理解参数,在上一个命令中,有3个参数,cp、a.c和b.c,在main函数中要把参数写完整(int argc, char **argv),这3个参数就是int型的argc,argv是个二级指针,是个数组的指针,这个指针里的每一项都是一个数组。

#include <stdio.h>int main(int argc, char **argv)
{printf("total params:%d\n", argc);printf("No.1 param:%s\n", argv[0]);printf("No.2 param:%s\n", argv[1]);printf("No.3 param:%s\n", argv[2]);return 0;
}#编译之后运行 ./a.out a.c b.c 指令可得以下结果
total params:3
No.1 param:./a.out
No.2 param:a.c
No.3 param:b.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;int fdDes;char *readBuf = NULL;if(argc != 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, 1024);fdDes = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0600);int n_write = write(fdDes, readBuf, strlen(readBuf));close(fdSrc);close(fdDes);return 0;
}

8.2 对配置文件的修改

//将下列配置进行修改
SPEED = 5;
LENG = 100;
SCORE = 90;
LEVEL = 95;
#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;int fdDes;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, 1024);//找到LENG=字符串第一次出现的位置char *p = strstr(readBuf, "LENG=");if(p == NULL){printf("not found\n");exit(-1);}//替换参数p = p + strlen("LENG=");*p = '5';lseek(fdSrc, 0, SEEK_SET);	//光标重新放到开头int n_write = write(fdSrc, readBuf, strlen(readBuf));close(fdSrc);return 0;
}

8.3 使用文件写入一个结构体

        写入一个结构体只需要按照文件函数的参数类型传入对应的参数即可,可参照将一个整形数写入文件。新写入的文件,人眼看着可能是乱码,但是程序读出来是正确的,如果想要看着也正常,可能需要一些别的操作。

#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 fd;int data = 100;int data2 = 0;fd = open('./file1', O_RDWR);int n_write = write(fd, &data, sizeof(int));int n_read = read(fd, &data2, sizeof(int));lseek(fd, 0, SEEK_SET);printf("read %d\n", data2);close(fd);return 0;
}

9、linux下的文件编程和标准库的文件编程区别

9.1 来源

        open是UNIX系统调用函数,包括LINUX等,返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。而fopen是C语言标准库函数,在不同的系统中应该调用不同的内核API,返回的是一个指向文件结构的指针。C语言的库函数还是需要调用系统API实现的。

9.2 移植性

        fopen是C标准函数,因此拥有良好的移植性,而open是UNIX系统调用,移植性有限。

9.3 适用范围

        open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作,如网络套接字。硬件设备等。在一些特殊情况下,如涉及驱动、内核等,只能使用open等函数。open和fopen都可以用来操纵普通正规文件。

9.4 文件IO层次

        open是属于低级IO函数,fopen是高级IO函数。低级和高级的简单区分标准就是:谁离系统内核更近,谁就低级。低级文件IO运行在内核态,高级文件IO运行在用户态。

9.5 缓冲

        缓冲文件系统的特点是在内存开辟一个“缓冲区”,为程序的每一个文件使用,对文件的操作都在缓冲区进行,内存缓冲区越大,操作外存的次数就少,执行速度就更快,效率更高。而非缓冲文件系统则是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,是基于操作系统的功能对文件进行读写,是系统级的输入输出。

        open无缓冲,与read、write等配合使用,而fopen有缓冲,与fread、fwrite等配合使用。在顺序访问文件时,使用fopen函数由于在用户态下有了缓冲,减少了在文件读写操作时在用户态和内核态之间的切换,比直接使用open函数效率要高;而若是随机访问文件则是相反。

10、使用fopen读写文件

#include <stdio.h>
#include <string.h>int main()
{//函数原型 FILE *fopen(const *path, const char *mode);//函数原型 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);//函数原型 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);FILE *fp;char *str = "hello go";char readbuf[120] = {0};fp = fopen("./file1.txt", "w+");fwrite(str, sizeof(char), strlen(str), fp);//fwrite(str, sizeof(char) * strlen(str), 1, fp);fseek(fp, 0, SEEK_SET);fread(readbuf, sizeof(char), strlen(str), fp);fclose(fp);printf("read data:%s\n", readbuf);return 0;
}

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

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

相关文章

n5.树(中)

1、二叉树的遍历 1.1先序、中序、后序遍历 先序遍历 根->左->右 先序遍历先访问根节点&#xff0c;再访问它的左子树&#xff0c;然后访问它的右子树。对于每次访问到的结点&#xff0c;都要递归地访问左子树、后右子树———递归。 创建 typedef struct TreeNode*…

点云体积计算方法之一 附python代码

一句话描述思路:通过统计计算点云所占用的体素的数量来计算点云的近似体积。这是一个粗略的近似值,对于复杂的形状可能不准确。 另外需要注意,这个只适合点云密集分布的场景来计算体积,比如树木扫描的体积;如果只是有表面积扫描的点云,该方法就不能计算整个物体的体积了…

飞跨电容型的三电平(FC-NPC)逆变器simulink仿真模型

本人搭建了飞跨电容型的三电平逆变器simulink仿真模型&#xff0c;相较于二极管钳位型三电平逆变器而言&#xff0c;钳位二极管变为飞跨的电容。采用SPWM调制和均流均压控制&#xff0c;通过搭建仿真模型得到三电平波形。 三电平拓扑中的飞跨电容是指在电路的输出端使用电容来实…

书生作业:LMDeploy

自己随便说几句。 关于模型部署&#xff0c;很有趣的一件事就是&#xff0c;它一路随着深度学习训练一起发展&#xff0c;尽管例如tensorrt等工具的出现&#xff0c;不断试图降低部署门槛&#xff0c;但是实际上&#xff0c;每一次AI的升级&#xff0c;似乎让这个细分领域没有…

C++面向对象

面向对象的三大特征 封装 目的:隐藏实现细节,实现模块化。特性: 访问权限 public:对所有对象开放。protected:对子类开放。private:只对自己开放。可以通过友元类打破 private 限定。对属性和方法进行限定。class A {friend class B; // B 可以访问 c public:int a;void …

图片格式不对怎么转换?推荐几个图片转换的高效处理方法

在日常使用电脑或处理图片的过程中&#xff0c;我们经常会遇到图片格式不兼容的问题&#xff0c;例如&#xff0c;我们可能收到了一个无法打开的图片文件&#xff0c;或者想将图片转换为其他格式以便在不同的应用程序中使用&#xff0c;这时候就需要将图片转格式&#xff0c;所…

如何让组织充满活力?你需要做好这七步

组织活力&#xff0c;通俗点说就是&#xff1a; 从竞争对手角度看&#xff0c;组织活力强的组织能做到竞争对手做不到的事情&#xff1b; 从客户角度看&#xff0c;组织活力强的组织&#xff0c;客户感受好&#xff1b; 从员工角度看&#xff0c;组织活力强的组织&#xff0c…

salesforce inactive user 和 deactived user 的区别

在Salesforce中&#xff0c;“inactive user”和“deactivated user”都指的是不再活跃或被停用的用户&#xff0c;但它们在某些情况下可能有不同的含义。 Inactive User&#xff08;非活跃用户&#xff09;&#xff1a;一个用户被标记为“非活跃”时&#xff0c;通常是因为他们…

算法题① —— 数组专栏

1. 滑动窗口 1.1 长度最小的子数组 力扣&#xff1a;https://leetcode.cn/problems/minimum-size-subarray-sum/description/ int minSubArrayLen(int s, vector<int>& nums) {int result INT32_MAX; int sum 0; // 子序列的数值之和int subLength 0; // 子序列…

基于单片机的直流电机检测与控制系统

摘要&#xff1a; 文章设计一款流电机控制系统&#xff0c;以 STC89C51 作为直流电机控制系统的主控制器&#xff0c;采用 LM293 做为驱动器实现 对直流电机的驱动&#xff0c;采用霍尔实现对直流电机速度的检测&#xff1b;本文对直流电机控制系统功能分析&#xff0c;选择确…

WAAP全站防护理念,发现和保护敏感数据

数据是现代企业的新石油&#xff1a;正确使用它可以促进公司的发展并帮助企业在竞争中领先。就像石油一样&#xff0c;原始数据和未被发现的数据是毫无用处的&#xff0c;企业将无法从中受益&#xff1b;在最坏的情况下&#xff0c;它可能会导致安全事件。这也是企业投资敏感数…

巩固学习4

python中函数逆置的几种方法 s input()for i in range(len(s)-1,-1,-1):#从最后一位开始&#xff0c;步长为-1print(s[i],end)用for语句循环逆置 s input() s list(s) n len(s) for i in range(n//2):s[i],s[n-1-i] s[n-1-i],s[i]#从中间反转字符串 res "".j…

A计算机上的程序与B计算机上部署的vmware上的虚拟机的程序通讯 如何配置?

环境&#xff1a; 在A计算机上运行着Debian11.3 Linux操作系统&#xff1b;在B计算机上运行着Windows10操作系统&#xff0c;并且安装了VMware软件&#xff0c;然后在VMware上创建了虚拟机C并安装了CentOS 6操作系统 需求&#xff1a; 现在A计算机上的程序需要同虚拟机C上的软…

(十二)JSP教程——exception对象

exception对象用来发现、捕获和处理JSP页面中的异常&#xff0c;是JSP文件运行时产生的异常对象。如果要使用它&#xff0c;必须将对应的JSP的page指令的isErrorPage属性设置为ture&#xff0c;即&#xff1a;<% page isErrorPage”true”%>。 JSP文件在运行中有异常现象…

【负载均衡式在线OJ项目day6】源文件路由功能及文件版题库构建

一.前言 前文讲到了OJ模块的设计思路&#xff0c;毫无疑问这是一个网络服务&#xff0c;我们先使用httplib&#xff0c;将源文件的路由功能实现&#xff0c;先把框架写好&#xff0c;后续再更改回调方法。 随后计划编写Modify模块&#xff0c;提供增删查改题库的功能(主要是查…

【贪心算法】最小生成树Kruskal算法Python实现

文章目录 [toc]问题描述最小生成树的性质证明 Kruskal算法Python实现时间复杂性 问题描述 设 G ( V , E ) G (V , E) G(V,E)是无向连通带权图&#xff0c; E E E中每条边 ( v , w ) (v , w) (v,w)的权为 c [ v ] [ w ] c[v][w] c[v][w]如果 G G G的一个子图 G ′ G^{} G′是…

acer笔记本怎样进行系统还原?教你两招!

acer笔记本怎样进行系统还原&#xff1f;教你两招&#xff01; 作为笔记本用户&#xff0c;你在日常使用中可能会遇到各种各样的电脑问题。一般来说&#xff0c;对于一些小问题&#xff0c;我们可以通过一些简单的操作来解决&#xff0c;比如重新启动电脑或者长按电源键强制关机…

深入探讨布隆过滤器算法:高效的数据查找与去重工具

在处理海量数据时&#xff0c;我们经常需要快速地进行数据查找和去重操作。然而&#xff0c;传统的数据结构可能无法满足这些需求&#xff0c;特别是在数据量巨大的情况下。在这种情况下&#xff0c;布隆过滤器&#xff08;Bloom Filter&#xff09;算法就显得尤为重要和有效。…

MongoDB聚合运算符:$toLong

MongoDB聚合运算符&#xff1a;$toLong 文章目录 MongoDB聚合运算符&#xff1a;$toLong语法使用举例 $toLong聚合运算符将指定的值转换为长整数类型。如果指定的值为空或缺失&#xff0c;则返回null&#xff1b;如果值无法被转换为长整数&#xff0c;则报错。 语法 {$toLong:…

提高静态住宅代理稳定性妙招

在数字化时代的浪潮中&#xff0c;静态住宅代理因其独特的优势&#xff0c;如固定的IP地址、更高的隐私保护性等&#xff0c;逐渐成为网络爬虫、数据分析等领域不可或缺的工具。然而&#xff0c;静态住宅代理的稳定性问题一直是用户关注的焦点。本文将为您揭示提高静态住宅代理…