我的编程空间,编程开发者的网络收藏夹
学习永远不晚

linux系统中文件I/O的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

linux系统中文件I/O的示例分析

小编给大家分享一下linux系统中文件I/O的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

linux 文件I/O

一,文件描述符
对内核而言,所以打开的文件都通过文件描述符引用。每个进程都有一些与之关联的文件描述符。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读或写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传送给read和write。

一般有三个以及打开的文件描述符,他们是:

代码如下:


0:标准输入                     STDIN_FILENO
1:标准输出                     STDOUT_FILENO
2标准错误输出               STDERR_FILENO

每行后面的符号常量是依从POSIX而定的。
open函数

代码如下:


#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);

pathname是要打开或创建文件的名字。

flag用来定义打开文件所采取的的动作,必须调用以下模式之一
O_RDONLY, O_WRONLY,  O_RDWR分别代表只读,只写,读写方式打开。

open还可以包括以下可选模式的组合
O_APPEND:把写入数据追加到文件的尾端
O_CREAT:若文件不存在,则创建它。使用此选项时,需要第三个参数mode,用其指定该新文件的访问权限。
O_EXCL:如果同时指定了O_CREAT,而文件存在,则会出错。用此可以测试一个文件是否存在,如果存在,则创建文件,这使测试和创建两者成为一个原子操作。
O_TRUNC: 如果此文件存在,而且为只写或读写成功打开,则将其长度截为0。

open返回的文件描述符一定是最小的未用描述符数值。这一点被某些应用程序用在标准输入,标准输出或标准错误输出上。如,一个程序关闭了自己的标准输出,然后再次调用open,文件描述符1就会被调用,并且标准输出将被有效的重定向到另一个文件或设备。

POSIX规范还标准化了一个creat调用,此函数等效于
open(pathname,O_WONLY |O_CREAT | O_TRUNC, mode);

close函数
#include <unistd.h>
int close(int fd);

close调用终止一个文件描述符fd与对应文件之间的关联。文件描述符被释放后并能重新使用。close调用成功返回0,出错返回-1.

关闭一个文件时会释放该进程加在文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有打开的文件。

lseek函数
每个打开的文件都有一个与其相关联的”当前文件偏移量”。按系统默认情况,当打开一个文件时,除非指定O_APPEND选项,否则该偏移量被设置为0。lseek可以为一个打开的文件设置偏移量。

代码如下:


#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, intwhence);

offset用来指定位置,whence参数定义该偏移值的用法。whence可取以下值:

代码如下:


SEEK_SET:     The offset is set to offset bytes.
SEEK_CUR:    The offset is set to its current locationplus offset bytes.
SEEK_END:    The offset is set to the size of the fileplus offset bytes.

成功调用返回从文件头到文件指针被设置处的字节偏移值,失败返回-1。参数offset定义在<sys/types.h>中。

当偏移量大于文件长度时,出现空洞,空洞不占用存储区。

read函数

代码如下:


#include <unistd.h>
ssize_t read(int fd, void *buf, size_tcount);

将与文件描述符fd关联的文件中读入count个字符放到buf中。返回读入的字节数,它可能小于请求的字节数。如果read调用返回0,就表示未读入任何数据,已到达了文件尾。返回-1,就表示出错。

write函数

代码如下:


#include <unistd.h>
ssize_t write(int fd, const void *buf,size_t count);

把缓冲区buf的前count个字节写入与文件描述符fd相关联的文件中。返回实际写入的字节数,通常与count值相同;否则表示出错。出错的一个常见原因是:磁盘已写满,或者超出了一个给定进程的文件长度限制。

实例:创建一个文件,写入数据,移动当前偏移量,在读数据。

代码如下:


#include<unistd.h>           //<unistd.h>必须最早出现,因为它可能会影响到其他头文件。#include<stdio.h>  
#include<fcntl.h>  
#include<string.h>  
#include<errno.h>  
int main()  
{  
  char* filename = ".//file";  
  char buf[100];  
  char buf1[5];  
  int fd;  
 
  printf("open a file to write\n");  
  if((fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ))==-1)  
   {  
      perror("cannot open file\n");  
      return 1;  
   }  
  printf("open file successfully!\n");  
  printf("input a string:");  
gets(buf);  
//write intofile  
   if(write(fd,buf,strlen(buf)) !=strlen(buf))  
   {  
       perror("cannot write intofile\n");  
       return 1;  
   }  
   close(fd);  
 
   printf("open file to read.\n");  
   if((fd=open(filename,O_RDONLY)) == -1)  
   {  
       perror("cannot open thefile.\n");  
       return 1;  
   }  
   if(lseek(fd,3,SEEK_SET) == -1)  
   {  
       perror("lseek erroe\n");  
       return 1;  
   }  
   //read from the file  
   if(read(fd,buf1,4)==-1)  
   {  
perror("read error.\n");  
       return 1;  
   }  
   printf("read from file is%s\n",buf1);  
   close(fd);  
 
   return 0;  
}

执行与输出结果:

代码如下:


root@jb51:~$gcc -o io io.c
root@jb51:~$./io
open a file towrite
open filesuccessfully!
input a string:akxivbaslzkncxcasbxbwwvaidxbd
open file toread.
read from fileis ivba

linux 文件I/O教程(2)

下面介绍了linux中有关文件I/O的相关内容,内核使用三种数据结构表示打开的文件,他们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。

一,文件共享
内核使用三种数据结构表示打开的文件,他们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。
1)  每个进程在进程表中都有一个记录项,记录项中包含一张打开文件描述表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:
a)      文件描述符标志
b)      指向一个文件表项的指针
2)  内核为所有打开文件维持一张文件表。每个文件表项包含:
a)      文件状态标志(读、写、读写、添些、同步和阻塞等)
b)      当前文件偏移量
c)      指向文件v节点表项的指针
3)  每个打开文件(或设备)都有一个v节点(v-node)结构。v节点包含了文件类型和对比文件进行各种操作的函数的指针。对于大多数文件,v节点还包含了该文件的i节点。i节点包含文件所有者、文件长度、文件所在的设备、指向文件实际数据块在磁盘上所在位置的指针等。

打开文件的内核数据结构

如果两个进程各自打开了同一个文件,则如图2所示。假定第一个进程在文件描述符3打开上该文件,而另一个进程在文件描述符4上打开该文件。每个进程都得得到一个文件表项,但对一个给定的文件只有一个v节点表项。每个进程都有自己的文件表项的一个理由是:使每个进程都有自己对该问价的当前偏移量。

现在对前一节文件I/O(1)的几个操作进一步说明:
1.  完成write之后,文件中当前偏移量即所增加的字节数。如果当前偏移量大于文件长度,则将i节点中当前文件长度设为当前文件偏移量。
2.  用O_APPEND打开一个文件,相应标志会被设置到文件状态标识中。每次写时,当前偏移量会被设置为i节点中的文件长度
3.  lseek定位到文件尾端时,则文件当前偏移量会被设置为当前文件长度。

可能有多个文件描述符指向同一文件表项。调用dup和fork时都能看到这一点。
多个进程读同一文件能正确工作。但多个进程写同一文件时,可能产生预期不到的后果。可以利用原子操纵避免这种情况。

原子操作
一般而言,原子操作指的是由多部组成的操作。如果该院自地执行,要么执行完所以步骤,要么一步也不执行。
1.      添加至一个文件
考虑一个进程,它要讲数据添加到一个文件尾端。早期UNIX不支持open,所以可以如下实现:

代码如下:


if(lseek(fd, 0L, 2)<0)
  err_sys(“lseekerror”);
if(write(fd, buf, 100) != 100)
  err_sys(“writeerror”);

对于单个进程,这段程序能正常工作。但多个进程就不一定。结社进程A和B都对同一文件进行添加操作。每个进程都打开该文件,此时数据结构之间关系如图2中所示。假定A调用lseek,将A的当前偏移量设置为1500。进程B执行lseek也将其当前偏移量设为1500。然后B调用write,将当前偏移量增至1600。然后内核又进行进程切换使进程A恢复运行,当A调用write时,从其当前偏移量1500处将数据写入,将替换B刚写入到该文件中的数据。

问题出在逻辑操作“定位到文件尾端处,然后写“使用了两个分开的函数调用。解决办法是使这两个操作成为一个原子操作。O_APPEND标识,使内核每次对文件进行写之前,都将进程当前偏移量设置到该文件的尾端处。

2.pread和pwrite函数
原子性地定位搜索和执行I/0。

代码如下:


#include <unistd.h>
ssize_t pread(int fd, void *buf, size_tcount, off_t offset);
ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset);
ssize_t pread(int fd, void *buf, size_tcount, off_t offset);
ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset);

dup和dup2函数

代码如下:


#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);

上面两个函数都可用来复制一个现存的文件描述符。

由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。用dup2则可以用newfd参数指定新描述符的数值。如果newfd已经打开,则先将其关闭。如果newfd等于oldfd,则dup2返回newfd而不关闭它。

图3.3显示了这种情况。

假定我们的进程执行了:

newfd = dup(1);

当此函数执行时,假设下一个可用的描述符是3。因为这两个描述符指向同一个文件表项,所以他们共享文件标志以及同一文件偏移量。

sync、fsync和fdatasync

代码如下:


#include <unistd.h>
void sync(void);
int fsync(int fd);
int fdatasync(int fd);

当将数据写入文件时,内核通常将数据复制到一个缓冲区,直到缓冲区写满,再将缓冲区排路输出队列,然后等待其到达队首,才进行实际的I/O操作。这种输出防暑被称为延迟写。延迟写减少了磁盘的读写次数,但却降低了文件内容的跟新速度。当系统发生故障时,延迟写可能造成文件跟新内容的丢失。为了保证磁盘上实际文件系统与缓冲区高速缓存中内容一致性,UNIX系统提供了sync、fsync和fdatasync 三个函数。

fcntl函数

代码如下:


#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... );

可以改变已经打开文件的性质。

复制一个现有的描述符(cmd=F_DUPFD)
获得或设置文件描述符(cmd=F_GETFD|F_SETFD)
获得或设置文件状态标志(cmd=F_GETFL|F_SETFL)
获得或设置异步I/O所有权(cmd=F_GETOWN|F_SETOWN)
获得或设置记录锁(cmd=F_GETLK|F_SETLK、F_SETLKW)

可以用fcntl函数设置文件状态,常用设置套接字描述符为非阻塞O_NONBLOCK

ioctl函数
#include <sys/ioctl.h>
int ioctl(int d, int request, ...);

提供了一个用于控制设备及其描述符行为和配置底层服务的接口。

/dev/fd
打开文件/dev/fd/n等效于复制描述符n。

以上是“linux系统中文件I/O的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

linux系统中文件I/O的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

linux系统中文件I/O的示例分析

小编给大家分享一下linux系统中文件I/O的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!linux 文件I/O一,文件描述符对内核而言,所以打开的文件
2023-06-13

Nodejs中异步I/O的示例分析

小编给大家分享一下Nodejs中异步I/O的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!“异步”这个名词其实在Node之前就已经诞生了。但是在绝大多数高
2023-06-14

Java I/O 之File类的示例分析

这篇文章主要为大家展示了“Java I/O 之File类的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java I/O 之File类的示例分析”这篇文章吧。File类Java使用Fil
2023-06-20

Linux系统DNS文件的示例分析

这篇文章将为大家详细讲解有关Linux系统DNS文件的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。DNS一般指域名系统。DNS是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库
2023-06-28

Linux文件系统权限的示例分析

小编给大家分享一下Linux文件系统权限的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!理解 ls 命令的输出在讨论如何修改权限之前,我们需要知道如何查看权限。通过 ls 命令的长列表参数(-l)为我们提供了有关文
2023-06-16

Linux系统备份文件的示例分析

这篇文章的内容主要围绕Linux系统备份文件的示例分析进行讲述,文章内容清晰易懂,条理清晰,非常适合新手学习,值得大家去阅读。感兴趣的朋友可以跟随小编一起阅读吧。希望大家通过这篇文章有所收获!一、备份服务器配置rsync文件 vi /etc
2023-06-28

linux中根文件系统挂载的示例分析

这篇文章主要介绍linux中根文件系统挂载的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!st1\:*{behavior:url(#ieooui) }一:前言前段时间在编译kernel的时候发现rootfs挂
2023-06-12

Linux下常见文件系统的示例分析

这篇文章主要介绍了Linux下常见文件系统的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。历史文件系统创建者创建时间最开始支持的平台ext2Rémy C
2023-06-16

Linux中文件系统及一些命令的示例分析

这篇文章主要介绍了Linux中文件系统及一些命令的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.磁盘分区和文件系统 1.1 硬盘分区 一块新的硬
2023-06-05

linux中磁盘与文件系统管理的示例分析

这篇文章将为大家详细讲解有关linux中磁盘与文件系统管理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。====三个重要的概念====* super block:记录文件系统的整体信息,包括in
2023-06-13

linux中ELF文件的示例分析

这篇文章给大家分享的是有关linux中ELF文件的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。示例程序我们的示例程序如下:#include int main(int argc,char
2023-06-16

Linux文件系统安装模块化的示例分析

小编给大家分享一下Linux文件系统安装模块化的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!以Fedora8下面安装minix文件系统为例:为了保证与系
2023-06-17

Linux服务器高I/O等待延迟问题查找的示例分析

这篇文章主要介绍Linux服务器高I/O等待延迟问题查找的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!0. 首先是top查看一下系统状况 发现两个参数异常,一是平均负载高,一是cpu %wa一直在50%以上
2023-06-16

分布式文件系统HDFS的示例分析

小编给大家分享一下分布式文件系统HDFS的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧! 从RAID说起大数据技术主要要解决的问题的是大规模数据的计算处理问题,那么首先要解决的就是大规模数据的存储问题。大规模数据存
2023-06-19

编程热搜

目录