linux应用编程和网络编程——文件IO(1)

1. 应用编程框架介绍

1.什么是应用编程

  1. 整个嵌入式linux核心课程包括5点:裸机,c高级,uboot和系统移植,linux应用编程和网络编程,驱动。
  2. 典型的嵌入式产品就是基于嵌入式linux操作系统来工作的。典型的嵌入式产品的研发过程是:第一步让linux系统在硬件上跑起来(系统移植工作),第二步基于linux系统开发应用程序实现产品功能。
  3. 基于linux做应用编程,其实就是调用linux系统的API来实现应用需要完成的任务。

2.什么是文件IO

  1. IO就是input output,输入/输出。文件IO就是读写文件。

2.文件操作的主要接口API

1.什么是API

  1. API是一些函数,这些函数由linux系统提供支持的,由应用层程序来使用。
  2. 应用层程序通过调用API来调用操作系统中的各种功能。
  3. 学习一个操作系统,就是学习使用这个操作系统的API

3.linux常用文件IO接口

  1. open,close,write,read,lseek

4.文件操作的一般步骤

  1. 在linux系统要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作,最后close关闭文件。

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

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

  4. 常见的一些现象:
    第一个:打开一个大文件时比较慢。
    第二个:我们写了一半文件,如果没有保存直接关机,重启后文件内容丢失。

  5. 为什么要这样设计?
    因为块设备本身有读写限制(回忆sd卡等块设备的读写特征),对它进行操作非常不灵活。而内存可以按字节为单位来操作,而且可以随机访问操作,很灵活。所以内核设计文件操作时就是这样设计了。

5.重要概念:文件描述符

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

6.简单文件读写实例

1. 打开关闭文件

实例源码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	int fd = -1;	//fd is file descriptor
	char buf[100] = {0};
	char writebuf[100] = "I love linux";
	int ret = -1;
	
	// 打开文件
	fd = open("a.txt",O_RDWR);
	if(-1 == fd)
		printf("open file wrong!\n");
	else
		printf("open file success,fd = %d.\n",fd);
	
	// 读写文件
	// 写文件
	ret = write(fd,writebuf,strlen(writebuf));
	if(-1 == ret)
		printf("failure\n");
	else
	{
		printf("write成功,写入了%d个bytes\n",ret);
	}
	
	// 读文件
	ret = read(fd,buf,12);
	if(-1 == ret)
		printf("read failure!\n");
	else
		printf("read success.read %d bytes.\n",ret);
		printf("content is %s\n",buf);
	
	// 关闭文件
	close(fd);
	
	return 0;
}

2. 实时查询man手册

  1. man 1 ××:查询linux shell命令
  2. man 2 ××:查询API
  3. man 3 ××:查询库函数

7.open函数的flag详解

1. 必选项(读写权限:O_RDONLY O_WRONLY O_RDWR)

  1. linux中文件有读写权限,我们在open文件时也可以附带一定的权限说明(O_RDONLY:只读方式;O_WRONLY :只写方式;O_RDWR:可读可写方式)。
  2. 当我们附带了权限说明后,文件就只能按照这种权限来操作了。

2. 以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags参数。

(1)O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆盖原来的内容。
(2)O_CREAT 若此文件不存在则创建它。使用此选项时需要提供第三个参数mode(0666后面三位对应ls -l前面的9个标志位),表示该文件的访问权限。
(3)O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
(4)O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断(Truncate)为0字节。
(5)O_NONBLOCK 对于设备文件,以O_NONBLOCK方式打开可以做非阻塞I/O(Nonblock I/O)。

  1. 阻塞和非阻塞。阻塞和非阻塞是两种不同的设计思路。如果一个函数是阻塞式的,则我们调用这个函数时当前进程有可能被卡住(阻塞,实质是这个函数内部要完成的条件不具备,当前不能完成);如果是非阻塞的,函数调用后一定会立即返回,但是函数不一定完成任务。
  2. 一个文件默认是阻塞式的,如果你希望以非阻塞打开文件,则flag中要加O_NONBLOCK。
  3. 只用于设备文件(硬件器件,如串口等),而不用于普通文件。

3. 以下三个常量同样是选用的,它们用于同步输入输出

(1)O_DSYNC  等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下,不等待文件属性更新。
(2)O_RSYNC  read 等待所有写入同一区域的写操作完成后再进行.
(3)O_SYNC  等待物理 I/O 结束后再 write,包括更新文件属性的 I/O。

  1. O_SYNC等待底层(os中负责实现open,write这些操作的代码,也包含os中读写硬盘等底层硬件的代码)完成写入才返回到应用层。

  2. 无O_SYNC时write只是将内容写入底层缓冲区即返回,然后底层在合适的时候会将缓冲区的内容一次性传给硬盘。这种设计是为了提升硬件操作的性能和寿命;但是有时候我们希望硬件不要等待合适机会,直接将我们的内容写入硬盘,我们可以使用O_SYNC。

4. exit,_exit, _Exit退出进程

  1. 当我们程序在前面步骤操作失败导致后面的操作都没有可能进行下去时,应该在前面的错误监测中结束整个程序,不应该继续让程序运行下去了。
  2. 如何退出程序?
    第一种:在main中用return,一般原则是程序正常终止return0;如果异常终止则return -1;。
    第二种:正式终止进程应该使用exit(库函数),_exit(API), _Exit(API)==之一。

8 文件读写的细节

1.errno和perror

errno
  1. errno是error number,错误号码。linux系统对各种常见错误做了编号,当我们的函数执行错误时,函数会返回一个特定的errno来告诉我们这个函数错 了。
  2. errno是由os来维护的全局变量,任何OS内部函数都可以通过设置error来告诉上层调用者发生了什么错误。
  3. errno本身实质是一个int类型的数字,每个数字编号对应一种错误。
perror
  1. linux系统提供一个函数perror(print error),perror函数内部会读取error并且将这个不好认的数字直接转换成对应的错误信息字符串,然后print打印出来。

2.read和write的count

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

  1. count和返回值的关系。count参数表示我们想要写或者读的字节数,返回值表示实际完成的要写或者读的字节数。

3.文件IO和标准IO

  1. 文件IO就是open,close,read,write等API函数构成的一套用来读写文件的体系,这套体系可以很好的完成文件读写,但是效率并不是最高的。
  2. 应用层C语言库函数提供了一些用来做文件读写的函数列表,叫标准IO。标准IO有一些了的c库函数构成(fopen,fclose,fread,fwrite),这些标准IO函数其实是由文件IO封装而来的。标准IO加了封装之后是为了在应用层添加一个缓冲机制,这样我们通过fwrite写入的内容不是直接进入OS中的缓冲区,而是先进入应用层标准IO库自己维护的缓冲区中,然后标准IO库自己根据OS单次write的最佳count来选择好的时机来完成write到内核中的缓冲区(内核中的缓冲区再根据硬盘的特性来选择好的时机最终写入硬盘)。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值