Linux中I/O函数 OpenFile 小结与树莓派上运行实践

2024-01-13 08:08

本文主要是介绍Linux中I/O函数 OpenFile 小结与树莓派上运行实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:树莓派的Rassbian系统就是基于Linux开发的,所以操作和Linux一样。没有树莓派的同学在Cgwin软件下也可以模拟Linux运行代码。我现在正在学习基于树莓派的RTP(Real Time Process)系统。主要内容是,OpenFile,fork函数,Pthread, Semepore,Timer, 进程流程图之类的。我也是小白级,哈哈哈,所以说每天学的就很傻瓜式,强迫自己必须死抠,真的不死抠跟不上。

废话少说,本文就是对OpenFile中的 Open, Close, Read, Write, Seek的一个小结,写的并不专业也不细致,但是够傻瓜式我觉得。毕竟我是立志于独立开发一套自己的树莓派智能之家的男人。。。666

在我的任何博文中欢迎大家沟通交流,批评指正,如果你也是彩笔,我们可以一起学。

参考了大佬的博文:https://blog.csdn.net/jinmie0193/article/details/79845316

建议大家先看看大佬写的介绍,再看我的代码。因为大佬写了介绍,我就不再写一遍了,注释都在程序中,几乎每行都备注了,有问题请在评论下方留言。

Open文件怎么写?

直接上代码,注释中有中英文对照,英文词对我来说一定要背下来呀。

/* Program to illustrate open and perror. */#include <stdio.h>
#include <fcntl.h> //声明系统调用 因为使用了flags
#include <errno.h>//通常,用一个负的返回值来表明错误,返回一个0值表明成功。错误信息存放在全局变量errno中,用户可用perror函数打印出错信息。/*文件描述符是非负整数。打开现存文件或新建文件时,系统(内核)会返回一个文件描述符。文件描述符用来指定已打开的文件。
程序运行起来后这三个文件描述符是默认打开的。      fd值#defineSTDIN_FILENO 0     //标准输入的文件描述符#defineSTDOUT_FILENO 1      //标准输出的文件描述符#defineSTDERR_FILENO 2        //标准错误的文件描述符原文:https://blog.csdn.net/jinmie0193/article/details/79845316 
*///int open(const char *pathname, int flags); pathname:文件的路径及文件名。  flags:open函数的行为标志。
//int open(const char *pathname,int flags,mode_t mode);  mode:文件权限(可读、可写、可执行)的设置。int main(int argc, char** argv) {//问题1,int argc, char** argv放这干啥用的???????这是“命令行”命令“./a.out c”int fd; char* path = "/home/pi/RTP1/OpenFile/text";//这是我树莓派里新创建的文件的保存路径printf("程序开始\n");// open file "test.c", creating the file and setting :// permissions to read/write/execute for user only : mode=0700// assigning the result to file descriptor fdif ( (fd = open(path,O_RDWR|O_CREAT,0700)) < 0){//声明系统调用 flagsperror("打开失败\n");return -1;}printf("打开文件:%s\n",path); printf("%d\n", fd);// print the file descriptorif (fd==-1) {fprintf (stderr, "Error Number %d\n", errno);perror("Program");}return 0;
}
/**********************************下文是老师给的作业要求(代码让补全)************************/
/* Program to illustrate open and perror. #include <stdio.h>
#include <fcntl.h>
#include <errno.h>int main(int argc, char** argv) {int fd;// open file "test.c", creating the file and setting // permissions to read/write/execute for user only// assigning the result to file descriptor fd//这里是问题,要在这里作答// print the file descriptorprintf("%d\n", fd);if (fd==-1) {fprintf (stderr, "Error Number %d\n", errno);perror("Program");}return 0;
}*/
/***************************************************************************/

然后连接树莓派,电源线,网线,连接SSH,输入密码,打开Putty(开着别关),然后连接WinSCP,把这.c文件从你的笔记本导入到(直接拖拽就行)你树莓派的目录下(path=/home/pi/RTP1/OpenFile)然后回到Putty窗口输入下面的命令行..........

仅需要输入三行命令行:

cd RTP1/Openfile//打开你的文件保存路径
gcc 你的文件名.c 
./a.out

然后就看见了输出结果:

 

Close 文件怎么写?

直接代码:

/* Program to illustrate file close. */#include <stdio.h>
#include <stdlib.h>//函数名: exit(),所在开头文件为:stdlib.h
#include <unistd.h>// int close(int fd);fd是调用open打开文件返回的文件描述符;返回值:成功返回0。失败返回-1,可以利用perror去查看原因
#include <fcntl.h>//声明系统调用,open,creat,
#include <errno.h>//通常,用一个负的返回值来表明错误,返回一个0值表明成功。错误信息存放在全局变量errno中int main(){//int close(int fd); 成功返回0。失败返回-1,可以利用perror去查看原因int fd;// open file "text.c" only for readingchar* path = "/home/pi/RTP1/OpenFile/text2";printf("开始\n");//Open and check only for reading, r--if ( (fd = open(path,O_RDONLY|O_CREAT,0400)) < 0){ // checking whether opening was successfulperror("Open failed\n");perror("text2.c");//printf errorreturn -1;}printf("Open file:%s \n",path);//Close fileif(close(fd)<0){perror("Close failed");perror("text.c");return -1;}printf("Close file: %s\n",path);printf("End\n");return 0;/*******************************以下是老师的********************************************//*if(){//open and checkperror("test.c");exit(1);//exit(x)(x不为0)都表示异常退出,这个x是返回给操作系统//退出整个程序,终止进程,并返回0给操作系统。由于返回0代表程序正常退出,返回1等其他数字通常代表异常终止,可通过返回的具体数值判断出错源。}// close file and check if () {//close and checkperror("test.c");exit(1);}printf("Closed the file descriptors.\n");return 0;*/}/********************结合老师的结构,我自己填的************************/
/*int main(){int fd;// open file "test.c" only for reading// checking whether opening was successfulchar* path = "/home/pi/RTP1/OpenFile/text";fd = open(path,O_RDWR|O_CREAT,0700);if(fd < 0){perror("test.c");exit(1);//让上一行程序结束}printf("opened the fd = %d\n",fd);// close file and check if (close(fd)<0) {perror("test.c");exit(1);}printf("Closed the file descriptors.\n");return 0;}*/
/***********************************************************************/

在树莓派上运行出结果(你去打开树莓派目录的话会看到text2.txt文件已经出来了)

 

Read 文件怎么写?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>int main()
{int fd;char* path = "/home/pi/RTP1/OpenFile/textR";int size = 7;//注意下面那行那么写,不对//char buff1[size] = "67890ab";//error: variable-sized object may not be initialized   //原因是	C语言中,当使用变量来定义数组长度的时候,不能同时进行初始化赋值。应该改为:char buff1[7] = "67890ab"; //size=7// allocate memory for buf为buf分配内存// and put some characters in (~7)printf("程序开始\n");//以可读可写方式打开文件,并赋予文件所有者rwx权限if ( (fd = open(path,O_RDWR|O_CREAT,0700)) < 0){perror("打开失败\n");return -1;}printf("打开文件:%s\n",path);if( read(fd,buff1,size) < 0 ){// (读buff1里面的前size=7个字母)<0就失败,>0就成功perror("读取失败\n");return -1;}printf("读取数据:%s\n",buff1);// 打印出那7个字母//关闭文件if(close(fd)<0){perror("关闭失败");return -1;}printf("关闭文件%s\n",path);printf("程序结束\n");return 0;
}

在树莓派中输入命令并得到结果:

WRITE 怎么写?

在上文READ的基础上添点东西。我们要定义两个Buffer(缓冲区,可理解为中转站)了,一个用来装你写的内容,另一个用来装你想读的内容。比如buf1[12]=‘abcdef123456’,你想查这个数组的从第一个到第3个是什么内容。就会把‘abc’的内容赋值给buf2[3]。然后buf2[0]的意思是让它里面装的东西清空。

下面的代码是先WRITE点字母,然后再READ一部分并显示。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>int main()
{int fd;char* path = "/home/pi/RTP1/OpenFile/textWR";int size = 3;//我想从头开始往后读三位char buff1[7]; //最多装7个字母,当然你只输入五个也行,小于等于7就行char buff2[3];//size = 3printf("程序开始\n");//以可读可写方式打开并创建文件textWR.txt,并赋予文件所有者rwx权限if ( (fd = open(path,O_RDWR|O_CREAT,0700)) < 0){perror("打开失败\n");return -1;}printf("打开文件:%s\n",path);printf("请输入要写入文件的字符:");//最多装7个字母,当然你只输入五个也行,小于等于7就行scanf("%s",buff1);//把写的字母装入buff1中//然后判断写成功了没if( write(fd,buff1,strlen(buff1)) < 0 ){//”strlen(buff1)“的功能是扫描 buff1中所含的字符数,比如我输入12345,那么buff1的字符数(size)就是5perror("写入文件失败");return -1;}printf("写入成功\n");printf("已装入buff1,你写的是:%s\n",buff1);lseek(fd,0,SEEK_SET);//定位到文件开头if( read(fd,buff2,size) < 0 ){perror("读取失败\n");return -1;}printf("读取数据:%s\n",buff2);buff2[0]='\0';//将buff2清空,为下次写的时候腾地方,大家可以试试删除这行会发生什么//关闭文件if(close(fd)<0){perror("关闭失败");return -1;}printf("关闭文件%s\n",path);printf("程序结束\n");return 0;
}/**************************************我之前写的,不对,你知道错哪了吗?************************/
/* Program to illustrate reading into a file. 
//Read: 把指定数目的数据读到内存(RAM)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>int main() {int fd;char* path = "/home/pi/RTP1/OpenFile/readtext";char buff1[20]= "67890abcde12345fghij";// allocate memory for buf为buf分配内存// and put some characters in (~20)int size = 12;char buff2[12];printf("Start \n");// open "readtext.txt" read onlyif ( (fd = open(path,O_RDONLY|O_CREAT,0400)) < 0){  // 只读权限,。没有该文件就创建一个,check whether file was opened correctly, make sure you first create the fileperror("打开或创建失败\n");return -1;}printf("已打开该路径文件 :%s\n",path);if( read(fd,buff2,size) < 0 ){// (读buff1里面的前12个字母)<0就失败,>0就成功perror("读取失败 \n");return -1;}printf("读取的数据是:%s\n",buff2);// 打印出12个字母buff2[0]='\0';//add '\0' to end string first! 结束字符串,也就是给buff2数组中的内容清零,为了下一次再用。//'\0';丢了,打印的时候不会停止,因为printf是遇到终止符才停止打印。// close file if(close(fd)<0){perror("关闭文件失败");return -1;}printf("关闭的文件的路径是 %s\n",path);printf("结束了 \n");return 0;}*/

如果把上文中的“    buff2[0]='\0';//将buff2清空,为下次写的时候腾地方,大家可以试试删除这行会发生什么”删除,那么如下

如果把那行去注释(添加上)会如下:

看起来结果是一样,但是啊,这是因为主程序只循环一次的结果呀。如果我们让他显示完,不关闭,继续问你输入新的字母,那么你需要给两个buf清零了,添加清零程序的位置在上一个代码中给出。

SEEK文件是啥?怎么用?

我们先看一下大佬博文中代码的例子,看看那个SEEK在那呢。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>int main()
{int fd;char* path = "/home/pi/RTP1/OpenFile/text6";char buff1[40],buff2[] = "-end:";//"-end:"的意思是从你写的第一个字母装到最后一个(就是完全抄袭的意思)printf("程序开始\n");//以可读可写方式打开文件,并赋予文件所有者rwx权限if ( (fd = open(path,O_RDWR|O_CREAT,0700)) < 0){perror("打开失败\n");return -1;}printf("打开文件:%s\n",path);printf("请输入要写入文件的字符:");scanf("%s",buff1);//strlen(buff1) buff1所含的字符数if( write(fd,buff1,strlen(buff1)) < 0 ){perror("写入文件失败");return -1;}printf("写入成功\n");buff1[0]='\0';//将buff1清空lseek(fd,0,SEEK_SET);//定位到文件开头if( read(fd,buff1,BUFSIZ) < 0 ){perror("读取失败\n");return -1;}printf("读取数据:%s\n",buff1);//关闭文件if(close(fd)<0){perror("关闭失败");return -1;}printf("关闭文件%s\n",path);printf("程序结束\n");return 0;
}//原文链接:https://blog.csdn.net/jinmie0193/article/details/79845316

他用了:

  lseek(fd,0,SEEK_SET);//定位到文件开头

所有文件都有一个与其关联的指针。 打开文件时,指针指向开头。 读取/写入 m 字节后,文件指针向前移动 m 字节。 可以显式移动此指针。

啥意思呢,看上面这行代码中的0,它的意思就是指针往结尾移动时没有增计数,就是一位一位的数:

这么说还是抽象,举个例子:

比如小学老师让我们从1数到10,大家会说1 2 3 4 5 6 7 8 9 10

如果这时候上文代码中的“0”改成3,那么就是4 5 6 7 8 9 10 8 9 10

如果这时候上文代码中的“0”改成6,那么就是7 8 9 10 5 6 7 8 9 10

 

offset:偏移量指定要移动的指针量。正数就是往结尾移动,负数就是往头位置移动。

whence: 指的是怎么偏移,是从开头到结尾呀,还是从结尾到开头,还是从中间的某一位开始到哪。。。

怎么偏移是有专门的名称:

SEEK_SET : 指针定位到开头
SEEK_CUR : 指针定位到当前指针位置
SEEK_END : 指针定位到结尾

如果成功完成,它将返回从文件开头以字节为单位的偏移位置。

所以说大佬那句:  lseek(fd,0,SEEK_SET); 的意思是:指针定位到文件开头

如果大家对这里还有不懂的,或者我说错,或者没说清楚的请在下方留言。遇到问题实在想不出来可以改下代码,试试嘛,看看改改  lseek(fd,0,SEEK_SET);这行中的变量,各种改各种试总会明白的。

好了,今天就到这里,我作业也写完了,感谢大佬的分析,祝大家学业有成!

 

这篇关于Linux中I/O函数 OpenFile 小结与树莓派上运行实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/600757

相关文章

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

Linux使用nohup命令在后台运行脚本

《Linux使用nohup命令在后台运行脚本》在Linux或类Unix系统中,后台运行脚本是一项非常实用的技能,尤其适用于需要长时间运行的任务或服务,本文我们来看看如何使用nohup命令在后台... 目录nohup 命令简介基本用法输出重定向& 符号的作用后台进程的特点注意事项实际应用场景长时间运行的任务服

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

Docker集成CI/CD的项目实践

《Docker集成CI/CD的项目实践》本文主要介绍了Docker集成CI/CD的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、引言1.1 什么是 CI/CD?1.2 docker 在 CI/CD 中的作用二、Docke

什么是cron? Linux系统下Cron定时任务使用指南

《什么是cron?Linux系统下Cron定时任务使用指南》在日常的Linux系统管理和维护中,定时执行任务是非常常见的需求,你可能需要每天执行备份任务、清理系统日志或运行特定的脚本,而不想每天... 在管理 linux 服务器的过程中,总有一些任务需要我们定期或重复执行。就比如备份任务,通常会选在服务器资

如何在一台服务器上使用docker运行kafka集群

《如何在一台服务器上使用docker运行kafka集群》文章详细介绍了如何在一台服务器上使用Docker运行Kafka集群,包括拉取镜像、创建网络、启动Kafka容器、检查运行状态、编写启动和关闭脚本... 目录1.拉取镜像2.创建集群之间通信的网络3.将zookeeper加入到网络中4.启动kafka集群

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET