前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >day26-系统IO(2022.2.23)

day26-系统IO(2022.2.23)

作者头像
天天Lotay
发布2022-12-02 14:39:41
2660
发布2022-12-02 14:39:41
举报
文章被收录于专栏:嵌入式音视频

Linux中,一切皆文件!

=============== 1.文件IO ====================

浏览书本:《4.2.1系统IO》和《4.2.2标准IO》

问题:

  1. 两种IO操作方式有何相同点?不同点?关系?

相同点:两种方式都是用于操作文件。

不同点:

系统IO:在操作系统层面,由系统提供。

标准IO:在库函数层面,由标准C库提供。

(关系:标准IO函数,其本质也是调用系统IO)

  1. 他们的优缺点是什么?

系统IO:由系统提供,有最基本的操作函数。(简洁、精炼)(类似于菜市场)

好处:简洁单一,稳定,不需要消耗过多系统资源。

缺点:对于功能性要求较高的程序,更加繁琐。

标准IO:由标准C库提供,拥有多样化的操作函数。(功能多样)(类似于饭馆)

好处:复杂操作更为方便,函数接口更加多样化。

缺点:消耗系统资源更多,不适用于简单功能。

=============== 2.系统IO ====================

——》在操作系统层面,由系统提供。

常用的接口函数:

  1. 文件的打开 open();
  2. 文件的关闭 close();
  3. 文件的写入 write();
  4. 文件的读取 read();
  5. 文件的偏移 lseek();

备注:

  1. 查看函数的用法:
    1. 直接查看man手册
    2. 查阅相关函数资料(书籍、网络)
  2. open打开文件描述符范围:3 ~ 1023
  3. 文件描述符 0~2分别对应不同的设备,自行open只能分配3以上。
  4. 当不再使用某个文件时,记得close关闭文件,释放资源。
    1. (当程序结束时,所有资源也都会被释放)
  5. 文件偏移量:
  • 也称为读写偏移量,读写操作都会先后移动。
  • 每次重新打开一个文件,文件偏移量默认为0(位于文件开头)

=============== 3.主函数传参功能  ====================

主函数形式:

  1. 无参形式:
代码语言:javascript
复制
int main()

int main(void) //等同于上一个
  1. 带参形式:
代码语言:javascript
复制
int main(int argc, const char *argv[])

int main(int argc, const char **argv)

=============== 4.系统IO常用函数 ====================

  1. 控制硬件设备(绕过应用层,直接与驱动层通信)
代码语言:javascript
复制
       #include <sys/ioctl.h>

       int ioctl(int fd, unsigned long request, ...);

备注:

  1. 函数的形参个数最少2个,最多不限,由驱动程序决定。

比如6818开发板的蜂鸣器驱动有3个参数:

代码语言:javascript
复制
       int ioctl(蜂鸣器硬件文件描述符, 电平状态, 引脚号);

蜂鸣器设备:”/dev/beep”

电平状态: 低电平0,高电平1(分别控制蜂鸣器响/不响)

引脚号: 固定为1号引脚

2. 复制文件描述符:

dup和dup2

备注:

  1. dup函数由系统自动分配最小且未用的文件描述符
  2. dup2函数分配指定的文件描述符,如指定文件描述符已使用,会被替代。

3. 文件控制:(软件、硬件。。)

fcntl()

备注:

  1. 可实现类似于dup和dup2的功能。
  2. 打开文件后,仍然能够设置/获取文件描述符的属性,无需重新打开文件。

4. 内存映射 (作用:将文件与内存进行关联,提高操作效率!)

mmap()

空洞文件有什么用呢?空洞文件对多线程共同操作文件是及其有用的,有时候我们创建一个很大的文件,如果单个线程从头开始依次构建该文件需要很长的时间,有一种思路就是将文件分为多段,然后使用多线程来操作,每个线程负责其中一段数据的写入;这个有点像我们现实生活当中施工队修路的感觉,比如说修建一条高速公路,单个施工队修筑会很慢,这个时候可以安排多个施工队,每一个施工队负责修建其中一段,最后将他们连接起来。

来看一下实际中空洞文件的两个应用场景:

在使用迅雷下载文件时,还未下载完成,就发现该文件已经占据了全部文件大小的空间,这也是空洞文件;下载时如果没有空洞文件,多线程下载时文件就只能从一个地方写入,这就不能发挥多线程的作用了;如果有了空洞文件,可以从不同的地址同时写入,就达到了多线程的优势;

在创建虚拟机时,你给虚拟机分配了 100G 的磁盘空间,但其实系统安装完成之后,开始也不过只用了 3、4G 的磁盘空间,如果一开始就把 100G 分配出去,资源是很大的浪费。

1.open.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	// 文件路径:
		//相对路径:1.txt
		//绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt
	int fd;	// 文件描述符(操作句柄,文件编号)
	fd = open("1.txt", O_RDWR);
	if(fd == -1)
	{
		perror("open failed");	// 打印错误信息
		return -1;
	}

	printf("open success![%d]\n", fd);

	return 0;
}

2.open_close.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
	// 文件路径:
		//相对路径:1.txt
		//绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt
	int fd;	// 文件描述符(操作句柄,文件编号)

	int cnt=1;
	while(1)
	{
		// 打开
		fd = open("1.txt", O_RDWR);
		if(fd == -1)
		{
			perror("open failed");	// 打印错误信息
			return -1;
		}

		printf("open success![%d][%d]\n", fd, cnt++);

		// 关闭
		// close(fd);
	}

	return 0;
}

3.creat.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
	// 文件路径:
		//相对路径:1.txt
		//绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt
	int fd;	// 文件描述符(操作句柄,文件编号)

	// 打开
	fd = open("a.txt", O_RDWR|O_CREAT|O_EXCL, 0644);
	if(fd == -1)
	{
		perror("open failed");	// 打印错误信息
		return -1;
	}

	printf("open success![%d]\n", fd);

	// 关闭
	close(fd);

	return 0;
}

4.write.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	// 文件路径:
		//相对路径:1.txt
		//绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt
	int fd;	// 文件描述符(操作句柄,文件编号)

	// 1.打开(不存在则创建,存在则直接打开)
	fd = open("1.txt", O_RDWR|O_CREAT, 0644);
	if(fd == -1)
	{
		perror("open failed");	// 打印错误信息
		return -1;
	}
	printf("open success![%d]\n", fd);

	// 2.写入
		// sizeof(str1)	:计算的是指针的大小(64位都是8字节)
	char *str1 = "a";
	int n_write = write(fd, str1, strlen(str1));
	printf("%d write\n", n_write);

	// 关闭
	close(fd);

	return 0;
}

5.read.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	// 文件路径:
		//相对路径:1.txt
		//绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt
	int fd;	// 文件描述符(操作句柄,文件编号)

	// 1.打开
	fd = open("1.txt", O_RDONLY, 0644);
	if(fd == -1)
	{
		perror("open failed");	// 打印错误信息
		return -1;
	}
	printf("open success![%d]\n", fd);

	// 2.读取
	char r_buf[10];
	bzero(r_buf, sizeof(r_buf));
	int n_read = read(fd, r_buf, sizeof(r_buf));
	printf("[%d]: %s\n", n_read, r_buf);

	// 3.关闭
	close(fd);

	return 0;
}

6.lseek偏移

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	// 文件路径:
		//相对路径:1.txt
		//绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt
	int fd;	// 文件描述符(操作句柄,文件编号)

	// 1.打开
	fd = open("1.txt", O_RDWR);
	if(fd == -1)
	{
		perror("open failed");	// 打印错误信息
		return -1;
	}
	printf("open success![%d]\n", fd);

	// 2.写入
	char w_buf[100] = "Lisi";
	int n_write = write(fd, w_buf, strlen(w_buf));
	printf("%d write\n", n_write);
	
	// 3.文件偏移量修改
	// lseek(fd, -4, SEEK_CUR);	// 从当前位置向前偏移4个字节
	lseek(fd, 0, SEEK_SET);		// 从文件开头,不偏移

	// 4.读取
	char r_buf[10];
	bzero(r_buf, sizeof(r_buf));
	int n_read = read(fd, r_buf, sizeof(r_buf));
	printf("read[%d]: %s\n", n_read, r_buf);

	// 5.关闭
	close(fd);

	return 0;
}

7.读写偏移.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	// 1.打开文件
	int fd;
	fd = open("1.txt", O_RDWR);
	if(fd == -1)
	{
		perror("open failed");
		return -1;
	}

	// 2.输入名字并写入指定位置
	char name[10] = {0};
	printf("Pls Input: ");
	scanf("%s", name); while(getchar()!='\n');
		// 偏移到指定位置并写入
	lseek(fd, 6, SEEK_SET);
	write(fd, name, strlen(name));

	// 3.读取文件内容
		// 偏移到开头并读取
	lseek(fd, 0, SEEK_SET);
	char r_buf[100];
	bzero(r_buf, sizeof(r_buf));
	int n_read = read(fd, r_buf, sizeof(r_buf));
	printf("read(%d): %s\n", n_read, r_buf);

	// 4.关闭文件
	close(fd);

	return 0;
}

8.主函数传参.c

代码语言:javascript
复制
#include <stdio.h>

// 主函数
	// arg:argument形参简称	
	// c:count计数
	// v:varible变量
// int main(int argc, const char *argv[])
int main(int argc, const char **argv)
{
	int i;
	for(i=0; i<argc; i++)
		printf("argv[%d]: %s\n", i, argv[i]);

	return 0;
}

9.ioctl控制蜂鸣器.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

int main()
{
	// 1.打开蜂鸣器
	int beep_fd = open("/dev/beep", O_RDWR);
	if(beep_fd == -1)
	{
		perror("open beep failed");
		return -1;
	}

	// 2.控制蜂鸣器
	int i;
	for(i=0; i<3; i++)
	{
		ioctl(beep_fd, 0, 1);	//响
		sleep(1);
		ioctl(beep_fd, 1, 1);	//不响
		sleep(1);
	}

	// 3.关闭蜂鸣器
	close(beep_fd);

	return 0;
}

10.dip和dup2复制文件描述符.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

int main()
{
	int fd = open("1.txt", O_RDWR);
	if(fd == -1)
	{
		perror("open failed");
		return -1;
	}

	// 复制文件描述符,由系统分配新的文件描述符(最小、未用)
	int new_fd1 = dup(fd);
	char ch;
	lseek(fd, 0, SEEK_SET);
	read(fd, &ch, 1);
	printf("fd(%d): %c\n", fd, ch);

	lseek(new_fd1, 0, SEEK_SET);
	read(new_fd1, &ch, 1);
	printf("new_fd1(%d): %c\n", new_fd1, ch);

	// 复制文件描述符,自行指定新的文件描述符
	int new_fd2 = dup2(fd, 100);
	lseek(new_fd2, 0, SEEK_SET);
	read(new_fd2, &ch, 1);
	printf("new_fd2(%d): %c\n", new_fd2, ch);

	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档