一.linux应用&网络编程之文件IO

有道云笔记地址:http://note.youdao.com/noteshare?id=7db133b182f498d61c2b5883fa460463&sub=0E2B5152A6EC4848AA1D193370ABC025

1.典型的嵌入式产品开发的顺序 

1、让Linux系统在硬件上跑起来(系统移植工作) 

2、基于Linux系统来开发应用程序实现产品功能(应用编程属于这一步骤)

基于Linux做应用编程其实就是调用API来实现应用需要完成的一些任务。 

注意:此课程是降低难度版 

主要目的:使用linux内核提供的API和c库函数来实现一定的功能

层次:APP+OS 操作系统本身有一部分是驱动,下面是硬件 

读写文件的案例中,文件是从硬盘中放着,当打开文件即将其读取到内存,这些硬件需要驱动。操作系统中有文件系统fs, 

保证我们用目录+文件名的方式来访问他,给我们提供了一些访问接口,从而用这些“门”去操控硬件和文件。

 

目录

一、文件IO概念

二、文件操作的主要接口API

2.1、什么是操作系统API

2.2、linux常用文件IO接口

三、文件操作的一般步骤

3.1在linux下对文件操作的一般步骤

3.2常用文件IO函数详解(使用man命令查询函数具体功能)

(1)、open函数(E:\Linux\3.AppNet\1.fileio\3.2)

(2)、close函数----关闭文件描述符fd指向的动态文件,并存储文件和刷新缓存。

(3)、read函数---Read成功返回读取的字节数,失败返回-1

write函数---Write成功返回写入的字节数,失败返回-1

3.3、打印错误信息

3.4文件IO效率和标准IO

3.5linux系统如何管理文件

3.6 lseek函数(E:\Linux\3.AppNet\1.fileio\3.4)

(1)、 将读写位置移到文件开头时

(2)、将读写位置移到文件尾时

(3)、想要取得目前文件位置时

(4)、用lseek测定文件大小的程序

(5)、用lseek构建空洞文件

四、多次打开同一文件与O_APPEND

4.1重复打开同一文件读取

(1)一个进程中两次打开同一个文件,然后分别读取,看结果会怎么样

4.2重复打开同一文件写入

(1) 一个进程中2个打开同一个文件,得到fd1和fd2.然后看是分别写还是接续写?

(2)加O_APPEND解决覆盖问题

(3)O_APPEND的实现原理和其原子操作性说明

五、文件共享的实现方式 2019/03/03 22:48

1.何谓文件共享

2.、文件共享的3种实现方式

3.剑指文件描述符

六、文件描述符的复制 E:\Linux\3.AppNet\1.fileio\3.6

1.dup函数(文件描述符重定位函数)

1.1、函数原型和头文件      

1.2、函数功能说明

1.3、函数参数

1.4、返回值

2.dup函数实例

3.dup2函数实例 E:\Linux\3.AppNet\1.fileio\3.6\file1.c

4.dup2共享文件交叉写入测试

5.命令行中重定位命令 >

七、fcntl函数 E:\Linux\3.AppNet\1.fileio\3.7

1、函数原型和头文件

2、函数参数

2.1、第一个参数int fd:文件描述符

2.2、第二个参数 int cmd:控制命令选项,用来控制修改什么样的性质,对于cmd的设置选择如下:

2.3、函数返回值

3、函数功能

4、举例:F_DUPFD

八、标准IO库(会使用man查看手册使用即可)

1.、一个简单的标准IO读写文件实例


一、文件IO概念

(1)IO就是input/output,输入/输出。文件IO的意思就是读写文件。

(2) linux文件IO操作有两套大类的操作方式:不带缓存的文件IO操作,带缓存的文件IO操作。不带缓存的属于直接调用系统调用(system call)的方式,高效完成文件输入输出。它以文件标识符(整型)作为文件唯一性的判断依据。这种操作不是ASCI标准的,与系统有关,移植有一定的问题。而带缓存的是在不带缓存的基础之上封装了一层,维护了一个输入输出缓冲区,使之能跨OS,成为ASCI标准,称为标准IO库。不带缓存的方式频繁进行用户态 和内核态的切换,高效但是需要程序员自己维护;带缓冲的方式因为有了缓冲区,不是非常高效,但是易于维护。由此,不带缓冲区的通常用于文件设备的操作,而带缓冲区的通常用于普通文件的操作。

 

 

二、文件操作的主要接口API

2.1、什么是操作系统API

(1)API是一些函数,这些函数是由linux系统提供支持的,由应用层程序来使用。

(2)应用层程序通过调用API来调用操作系统中的各种功能,来干活。

(3)学习一个操作系统,其实就是学习使用这个操作系统的API。

(1)今天我们要使用linux系统来读写文件,手段就是学习linux系统API中和文件IO有关的几个。

2.2、linux常用文件IO接口

(1)open、close、write、read、lseek

 

三、文件操作的一般步骤

3.1在linux下对文件操作的一般步骤

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

实时查man手册

(1)当我们写应用程序时,很多API原型都不可能记得,所以要实时查询,用man手册

(2)man 1 xx查linux shell命令,man 2 xxx查API, man 3 xxx查库函数

例如我们使用到的open、close、write、read函数,在linux下查阅使用方法即可。

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <string.h>



int main(int argc,char *argv[])

{

int fd=-1; //fd file descriptor,文件描述符

char buf[100]={0};

char writebuf[20]="are you ok";

int ret=-1;

//第一步:打开文件

fd=open("a.txt",O_RDWR);

if(-1 == fd)

{

printf("文件打开错误\n");

}

else

{

printf("文件打开成功,fd=%d.\n",fd);

}



//第二步:读写文件

//写文件

ret=write(fd,writebuf,strlen(writebuf));

if(-1==ret)

{

printf(" 写入失败\n");

}

else

{

printf(" 实际写入了%d字节.\n",ret);

printf(" 文件内容是: [%s] .\n",writebuf);

}

//读文件

ret=read(fd,buf,20);

if(-1==ret)

{

printf(" 读取失败\n");

}

else

{

printf(" 实际读取了%d字节.\n",ret);

printf(" 文件内容是: [%s] .\n",buf);

}

//第三步:关闭文件

close(fd);

return 0;

}

 

3.2常用文件IO函数详解(使用man命令查询函数具体功能)

(1)、open函数(E:\Linux\3.AppNet\1.fileio\3.2)

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

 

Open函数返回打开、创建文件的文件描述符,如果失败返回-1。

Flags:

O_RDONLY   //只读打开

O_WRONLY   //只写打开

O_RDWR    //读、写打开

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

O_CREAT   //若此文件不存在,则创建它。使用时,需要第三个参数mode

O_EXCL   //如果同时指定了O_CREAT,而文件已经存在,则会出错。用此可以测试一个文件是否存在,如果不存在,则创建此文件。

O_TRUNC  //如果此文件存在,而且为只写或读写成功打开,则将其长度截短为0。

O_NONBLOCK  //如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选项为文件的本次操作和后续的I/O操作设置非阻塞模式。只用于设备文件,不能用于普通文件。

O_SYNC    //使每次write都等到物理I/O操作完成,包括由write操作引起的文件属性更新所需的I/O。

Mode:

使用四个数字指定创建文件的权限,与linux的权限设置相同,如0755

譬如一般创建一个可读可写不可执行的文件就用0666

 

(2)、close函数----关闭文件描述符fd指向的动态文件,并存储文件和刷新缓存。

#include <unistd.h>

int close(int fd);

 

(3)、read函数---Read成功返回读取的字节数,失败返回-1

write函数---Write成功返回写入的字节数,失败返回-1

#include <unistd.h>

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

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

count和返回值的关系。count参数表示我们想要写或者读的字节数,返回值表示实际完成的要写或者读的字节数。实现的有可能等于想要读写的,也有可能小于(说明没完成任务)

 

 

3.3、打印错误信息

errno就是error number。

如果程序代码中包含 #include <errno.h>,函数调用失败的时候,系统会自动用用错误代码填充errno这个全局变量,取读errno全局变量可以获得失败原因。

函数调用失败是否会设置errno全局变量由函数决定,并不是所有函数调用失败都会设置errno变量。

 

#include <stdio.h>

void perror(const char *s);

perror ( )用来将上一个函数发生错误的原因输出到标准错误(stderr),参数s 所指的字符串会先打印出,后面再加上错误原因字符串。

3.4文件IO效率和标准IO

(1)文件IO就指的是我们当前在讲的open、close、write、read等API函数构成的一套用来读写文件的体系,这套体系可以很好的完成文件读写,但是效率并不是最高的。

(2)应用层C语言库函数提供了一些用来做文件读写的函数列表,叫标准IO。标准IO由一系列的C库函数构成(fopen、fclose、fwrite、fread),这些标准IO函数其实是由文件IO封装而来的(fopen内部其实调用的还是open,fwrite内部还是通过write来完成文件写入的)。标准IO加了封装之后主要是为了在应用层添加一个缓冲机制,这样我们通过fwrite写入的内容不是直接进入内核中的buf,而是先进入应用层标准IO库自己维护的buf中,然后标准IO库自己根据操作系统单次write的最佳count来选择好的时机来完成write到内核中的buf(内核中的buf再根据硬盘的特性来选择好的实际去最终写入硬盘中)。

 

3.5linux系统如何管理文件

硬盘中的静态文件和inode(i节点)

(1)文件平时都放在硬盘中,硬盘中以一种固定的形式存放,我们称为静态文件

(2)一块硬盘中分为两大区域:一个是硬盘内容管理表,另一个是真正存储的内容区域。操作系统访问硬盘时先去读取硬盘内容管理表,从中找到我们访问的那个扇区级别的信息,然后用这个信息去查询真正的存储内容的区域,然后得到我们要的文件

(3)管理表中以文件为单位,记录了各个文件的各种信息,每一个文件有一个文件列表(我们叫inode,i节点,其实质是一个结构体,这个结构体有很多元素,每个元素记录了这个文件的一些信息,其中包括文件名,文件在硬盘上对应的扇区号,块号那些东西......

(4)硬盘管理的时候以文件为单位,每个文件一个inode,每个inode有一个数字编号,对应一个结构体,结构体记录了各种信息

内存中被打开的文件和vnode(v节点)

(5)格式化硬盘(U盘)时发现:快速格式化和底层格式化。快速格式化非常快,格式32G只需一秒,普通格式速度慢。两者差异?

快速格式化只是删除了U盘硬盘内容管理表(inode),真正存储的内容没有动,这种格式化可能被找回。

(6)一个程序的运行就是一个进程,我们在程序中打开的文件就属于某个进程。每个进程都有一个数据结构来记录这个进程的所有信息(进程信息),表中有一个指针会指向一个文件管理表,文件管理表中记录了当前进程及其相关信息。

文件管理表中用来索引各个打开的文件的index就是文件描述符f,我们最终找到的就是一个已经被打开的文件的管理结构体vnode

(7)一个vnode中记录了一个被打开的文件的各种信息,而且我们只要知道这个文件的fd,就可以很容易找到这个文件的vnode进而对这个文件进行各操作。

文件和流的概念

(1)文件操作中,文件类似一个包裹,里面装了一堆字符,但是文件被读出/写入时都只能一个字符一个字符的进行,而不能一个文件中N多个字符被挨个一次读出/写入时,这些字符就构成了字符流

(2)流是动态的,不是静态的

(3)编程中提到的流的概念,一般是IO相关的。所以经常叫IO流。文件操作就构成了IO流。

简而言之就是:表表相连 :硬盘内容管理表

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值