第6章文件IO编程Word文档下载推荐.docx

上传人:b****5 文档编号:21141806 上传时间:2023-01-27 格式:DOCX 页数:97 大小:588.77KB
下载 相关 举报
第6章文件IO编程Word文档下载推荐.docx_第1页
第1页 / 共97页
第6章文件IO编程Word文档下载推荐.docx_第2页
第2页 / 共97页
第6章文件IO编程Word文档下载推荐.docx_第3页
第3页 / 共97页
第6章文件IO编程Word文档下载推荐.docx_第4页
第4页 / 共97页
第6章文件IO编程Word文档下载推荐.docx_第5页
第5页 / 共97页
点击查看更多>>
下载资源
资源描述

第6章文件IO编程Word文档下载推荐.docx

《第6章文件IO编程Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《第6章文件IO编程Word文档下载推荐.docx(97页珍藏版)》请在冰豆网上搜索。

第6章文件IO编程Word文档下载推荐.docx

但并不是所有的函数都一一对应一个系统调用,有时,一个API函数会需要几个系统调用来共同完成函数的功能,甚至还有一些API函数不需要调用相应的系统调用(因此它所完成的不是内核提供的服务)。

在Linux中,用户编程接口(API)遵循了在UNIX中最流行的应用编程界面标准——POSIX标准。

POSIX标准是由IEEE和ISO/IEC共同开发的标准系统。

该标准基于当时现有的UNIX实践和经验,描述了操作系统的系统调用编程接口(实际上就是API),用于保证应用程序可以在源代码一级上在多种操作系统上移植运行。

这些系统调用编程接口主要是通过C库(libc)实现的。

6.1.3系统命令

以上讲解了系统调用、用户编程接口(API)的概念,分析了它们之间的相互关系,那么,读者在第2章中学到的那么多的Shell系统命令与它们之间又是怎样的关系呢?

系统命令相对API更高了一层,它实际上是一个可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能。

它们之间

的关系如图6.1所示。

6.2Linux中文件及文件描述符概述

图6.1系统调用、A

系统命令之间的关

在Linux中对目录和设备的操作都等同于文件的操作,因此,大大简化了系统对

不同设备的处理,提高了效率。

Linux中的文件主要分为4种:

普通文件、目录文件、

链接文件和设备文件。

那么,内核如何区分和引用特定的文件呢?

这里用到了一个重要的概念——文件描述符。

对于Linux而言,所有对设备和文件的操作都是使用文件描述符来进行的。

文件描述符是一个非负的整数,它是一个索引值,并指向在内核中每个进程打开文件的记录表。

当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;

当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数。

通常,一个进程启动时,都会打开3个文件:

标准输入、标准输出和标准出错处理。

这3个文件分别对应文件描述符为0、1和2(也就是宏替换STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO,鼓励读者使用这些宏替换)。

基于文件描述符的I/O操作虽然不能移植到类Linux以外的系统上去(如Windows),但它往往是实现某些I/O操作的惟一途径,如Linux中低级文件操作函数、多路I/O、TCP/IP套接字编程接口等。

同时,它们也很好地兼容POSIX标准,因此,可以很方便地移植到任何POSIX平台上。

基于文件描述符的I/O操作是Linux中最常用的操作之一,希望读者能够很好地掌握。

6.3底层文件I/O操作

本节主要介绍文件I/O操作的系统调用,主要用到5个函数:

open()、read()、write()、lseek()和close()。

这些函数的特点是不带缓存,直接对文件(包括设备)进行读写操作。

这些函数虽然不是ANSIC的组成部分,但是是POSIX的组成部分。

6.3.1基本文件操作

(1)函数说明。

open()函数用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。

close()函数用于关闭一个被打开的文件。

当一个进程终止时,所有被它打开的文

件都由内核自动关闭,很多程序都使用这一功能而不显示地关闭一个文件。

read()函数用于将从指定的文件描述符中读出的数据放到缓存区中,并返回实际读入的字节数。

若返回0,则表示没有数据可读,即已达到文件尾。

读操作从文件的当前指针位置开始。

当从终端设备文件中读出数据时,通常一次最多读一行。

write()函数用于向打开的文件写数据,写操作从文件的当前指针位置开始。

对磁盘文件进行写操作,若磁盘已满或超出该文件的长度,则write()函数返回失败。

lseek()函数用于在指定的文件描述符中将文件指针定位到相应的位置。

它只能用在可定位(可随机访问)文件操作中。

管道、套接字和大部分字符设备文件是不可定位的,所以在这些文件的操作中无法使用lseek()调用。

(2)函数格式。

open()函数的语法格式如表6.1所示。

表6.1open()函数语法要点

所需头文件

#include<

sys/types.h>

/*提供类型pid_t的定义*/

sys/stat.h>

fcntl.h>

函数原型

intopen(constchar*pathname,intflags,intperms)

函数传入值

pathname

被打开的文件名(可包括路径名)

flag:

文件打开的方式

O_RDONLY:

以只读方式打开文件

O_WRONLY:

以只写方式打开文件

O_RDWR:

以读写方式打开文件

O_CREAT:

如果该文件不存在,就创建一个新的文件,并用第

三个参数为其设置权限

O_EXCL:

如果使用O_CREAT时文件存在,则可返回错误消息。

这一参数可测试文件是否存在。

此时open是原子操作,防止多个进程同时创建同一个文件

O_NOCTTY:

使用本参数时,若文件为终端,那么该终端不会

成为调用open()的那个进程的控制终端

O_TRUNC:

若文件已经存在,那么会删除文件中的全部原有数据,并且设置文件大小为0。

O_APPEND:

以添加方式打开文件,在打开文件的同时,文件

指针指向文件的末尾,即将写入的数据添加到文件的末尾

perms

被打开文件的存取权限

可以用一组宏定义:

S_I(R/W/X)(USR/GRP/OTH)

其中R/W/X分别表示读/写/执行权限

USR/GRP/OTH分别表示文件所有者/文件所属组/其他用户

例如,S_IRUSR|S_IWUSR表示设置文件所有者的可读可写属性。

八进制表示法中600也表示同样的权限

函数返回值

成功:

返回文件描述符失败:

1

在open()函数中,flag参数可通过“|”组合构成,但前3个标志常量(O_RDONLY、

O_WRONLY以及O_RDWR)不能相互组合。

perms是文件的存取权限,既可以用宏

定义表示法,也可以用八进制表示法。

close()函数的语法格式表6.2所示。

表6.2close()函数语法要点

所需头文件#include<

unistd.h>

函数原型intclose(intfd)函数输入值fd:

文件描述符

函数返回值0:

成功

1:

出错

read()函数的语法格式如表6.3所示。

表6.3read()函数语法要点

所需头文件#include<

函数原型ssize_tread(intfd,void*buf,size_tcount)

fd:

buf:

指定存储器读出数据的缓冲区count:

指定读出的字节数成功:

读到的字节数

0:

已到达文件尾

在读普通文件时,若读到要求的字节数之前已到达文件的尾部,则返回的字节数

会小于希望读出的字节数。

write()函数的语法格式如表6.4所示。

表6.4write()函数语法要点

ssize_twrite(intfd,void*buf,size_tcount)

指定存储器写入数据的缓冲区

count:

指定读出的字节数

已写的字节数

在写普通文件时,写操作从文件的当前指针位置开始。

lseek()函数的语法格式如表6.5所示。

表6.5lseek()函数语法要点

off_tlseek(intfd,off_toffset,intwhence)

offset:

偏移量,每一读写操作所需要移动的距离,单位是字节,可正可负

(向前移,向后移)

whence:

当前位置的基点

SEEK_SET:

当前位置为文件的开头,新位置为偏移量的大小

SEEK_CUR:

当前位置为文件指针的位置,新位置为当前位置加上偏移量

SEEK_END:

当前位置为文件的结尾,新位置为文件的大小

加上偏移量的大小

文件的当前位移

(3)函数使用实例。

下面实例中的open()函数带有3个flag参数:

O_CREAT、O_TRUNC和O_WRONLY,这样就可以对不同的情况指定相应的处理方法。

另外,这里对该文件的权限设置为0600。

其源码如下所示:

下面列出文件基本操作的实例,基本功能是从一个文件(源文件)中读取最后

10KB数据并到另一个文件(目标文件)。

在实例中源文件是以只读方式打开,目标文件是以只写方式打开(可以是读写方式)。

若目标文件不存在,可以创建并设置权限的初始值为644,即文件所有者可读可写,文件所属组和其他用户只能读。

读者需要留意的地方是改变每次读写的缓存大小(实例中为1KB)会怎样影响运行效率。

/*copy_file.c*/

stdlib.h>

stdio.h>

#defineBUFFER_SIZE1024/*每次读写缓存大小,影响运行效率*/

#defineSRC_FILE_NAME"

src_file"

/*源文件名*/

#defineDEST_FILE_NAME"

dest_file"

/*目标文件名文件名*/

#defineOFFSE10240/*复制的数据大小*/

intmain()

{

intsrc_file,dest_file;

unsignedcharbuff[BUFFER_SIZE];

intreal_read_len;

/*以只读方式打开源文件*/

src_file=open(SRC_FILE_NAME,O_RDONLY);

/*以只写方式打开目标文件,若此文件不存在则创建该文件,访问权限值为644*/

dest_file=open(DEST_FILE_NAME,O_WRONLY|O_CREAT,

S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

if(src_file<

0||dest_file<

0)

printf("

Openfileerror\n"

);

exit

(1);

}

/*将源文件的读写指针移到最后10KB的起始位置*/

lseek(src_file,-OFFSET,SEEK_END);

/*读取源文件的最后10KB数据并写到目标文件中,每次读写1KB*/

while((real_read_len=read(src_file,buff,sizeof(buff)))>

write(dest_file,buff,real_read_len);

close(dest_file);

close(src_file);

return0;

$./copy_file

$ls-lhdest_file

-rw-r--r--1davidroot10K14:

06dest_file

open()函数返回的文件描述符一定是最小的未用文件描述符。

由于一个进程在

启动时自动打开了0、1、2三个文件描述符,因此,该文件运行结果中返回的注意文件描述符为3。

读者可以尝试在调用open()函数之前,加一句close(0),则此后在调用open()函数时返回的文件描述符为0(若关闭文件描述符1,则在程

序执行时会由于没有标准输出文件而无法输出)。

6.3.2文件锁

(1)fcntl()函数说明。

前面的这5个基本函数实现了文件的打开、读写等基本操作,本小节将讨论的是,在文件已经共享的情况下如何操作,也就是当多个用户共同使用、操作一个文件的情况,这时,Linux通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态。

文件锁包括建议性锁和强制性锁。

建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。

在一般情况下,内核和系统都不使用建议性锁。

强制性锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作。

采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。

在Linux中,实现文件上锁的函数有lockf()和fcntl(),其中lockf()用于对文件施加建议性锁,而fcntl()不仅可以施加建议性锁,还可以施加强制锁。

同时,fcntl()还能对文件的某一记录上锁,也就是记录锁。

记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。

而写入锁又称为排斥锁,在任何时刻只能有一个进程在文件的某个部分上建立写入锁。

当然,在文件的同一部分不能同

时建立读取锁和写入锁。

fcntl()是一个非常通用的函数,它可以对已打开的文件描述符进行各种操作,

注意不仅包括管理文件锁,还包括获得和设置文件描述符和文件描述符标志、文件描述符的复制等很多功能。

在本节中,主要介绍建立记录锁的方法。

(2)fcntl()函数格式。

用于建立记录锁的fcntl()函数格式如表6.6所示。

表6.6fcntl()函数语法要点

函数原型intfcnt1(intfd,intcmd,structflock*lock)

函数传入值fd:

cmd

F_DUPFD:

复制文件描述符

F_GETFD:

获得fd的close-on-exec标志,若标志未设置,则文件经过exec()

函数之后仍保持打开状态

F_SETFD:

设置close-on-exec标志,该标志由参数arg的FD_CLOEXEC

位决定

F_GETFL:

得到open设置的标志

F_SETFL:

改变open设置的标志

F_GETLK:

根据lock参数值,决定是否上文件锁

F_SETLK:

设置lock参数值的文件锁

F_SETLKW:

这是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。

在无法获取锁时,会进入睡眠状态;

如果可以获取锁或者捕捉到信号则会

返回

lock:

结构为flock,设置记录锁的具体状态

这里,lock的结构如下所示:

structflock

shortl_type;

off_tl_start;

shortl_whence;

off_tl_len;

pid_tl_pid;

lock结构中每个变量的取值含义如表6.7所示。

表6.7lock结构变量取值

l_type

F_RDLCK:

读取锁(共享锁)

F_WRLCK:

写入锁(排斥锁)

F_UNLCK:

解锁

l_stat

相对位移量(字节)

l_whence:

相对位移量的起点(同lseek的whence)

当前位置为文件指针的位置,新位置为当前位置加上偏移量

当前位置为文件的结尾,新位置为文件的大小加上偏移量的大

l_len

加锁区域的长度

小技巧为加锁整个文件,通常的方法是将l_start设置为0,l_whence设置为

SEEK_SET,l_len设置为0。

(3)fcntl()使用实例

下面首先给出了使用fcntl()函数的文件记录锁功能的代码实现。

在该代码中,首先给flock结构体的对应位赋予相应的值。

接着使用两次fcntl()函数,分别用于判断文件是否可以上锁和给相关文件上锁,这里用到的cmd值分别为F_GETLK和F_SETLK

(或F_SETLKW)。

用F_GETLK命令判断是否可以进行flock结构所描述的锁操作:

若可以进行,则flock结构的l_type会被设置为F_UNLCK,其他域不变;

若不可行,则l_pid被设置为拥有文件锁的进程号,其他域不变。

用F_SETLK和F_SETLKW命令设置flock结构所描述的锁操作,后者是前者的

阻塞版。

文件记录锁功能的源代码如下所示:

/*lock_set.c*/

intlock_set(intfd,inttype)

structflockold_lock,lock;

lock.l_whence=SEEK_SET;

lock.l_start=0;

lock.l_len=0;

lock.l_type=type;

lock.l_pid=-1;

/*判断文件是否可以上锁*/

fcntl(fd,F_GETLK,&

lock);

if(lock.l_type!

=F_UNLCK)

/*判断文件不能上锁的原因*/

if(lock.l_type==F_RDLCK)/*该文件已有读取锁*/

Readlockalreadysetby%d\n"

lock.l_pid);

elseif(lock.l_type==F_WRLCK)/*该文件已有写入锁*/

Writelockalreadysetby%d\n"

/*l_type可能已被F_GETLK修改过*/

/*根据不同的type值进行阻塞式上锁或解锁*/

if((fcntl(fd,F_SETLKW,&

lock))<

Lockfailed:

type=%d\n"

lock.l_type);

return

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 思想汇报心得体会

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1