`
ydbc
  • 浏览: 766658 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

文件I/O编程

 
阅读更多


一、系统调用

所谓的系统的调用时操作系统提供给用户程序调用的一组“特殊”接口,用户可以同个接口获得系统提供的服务。例如用户通过系统调用可以实现创建进程、进程的管理、soket网络通信。

linux用户程序是不能直接访问系统内核提供的服务的。这样做是为了保护系统内核的数据不被修改,保证了系统的安全性。用户空间和内核空间是分离的,通常情况下用户程序不允许访问内核数据和内核的函数。

二、用户编程接口(API)

前面写到用户不是直接和系统进行交互的,而是通过软中断机制向内核提出申请,以获取内核服务的接口。在实际编程中用户调用的是API函数。并不是一个API对应一个系统调用,有的时候一个API 函数对应几个系统的调用。

三、系统命令

系统命令相对于API更高了一层,它实际 上是一个可执行的程序。它们三者之间的关系如下图:


四、linux文件及文件描述符

在linux学习中很重要的一点就是所有的操作都是对文件的操作,内核区分文件就是通过文件描述符。文件描述符是一个非负的整数,它是一个索引值,指向内核中每个进程打开文件的记录表。当打开一个现存文件或新建一个文件时,就会返回一个文件描述符;当读写文件时,也需要将文件描述符作为参数传递给函数。

通常一个进程启动时,会打开三个文件:标准输入,标准输出,标准出错处理。这三个文件分别对应文件描述符0,1,2.(也就是宏替换STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO).

五、不带缓存的I/O操作

下面的第一个程序是向一个文件中写入字符,并按照指定的字节读出来。调用了write、open和read函数。

/*write.c*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXSIZE
int main(void)
{
	int i,fd,size,len;
	char *buf="Hello! I'm writing to this file!";//指针指向的将要写入文件的字符
	char buf_r[10];
	len = strlen(buf);//获得字符串的大小
	buf_r[10] = '\0';
	//打开文件
	if((fd = open("/tmp/hello.c", O_CREAT | O_TRUNC | O_RDWR,0666 ))<0){
		perror("open:");
		exit(1);
	}
	else
		printf("open file:hello.c %d\n",fd);
	//写入字符
	if((size = write( fd, buf, len)) < 0){
		perror("write:");
		exit(1);
	}
	else
		printf("Write:%s\n",buf);

	lseek( fd, 0, SEEK_SET ); //定位在起始的位置
	//读10个字节到buf_r中
	if((size = read( fd, buf_r, 10))<0){ 
		perror("read:");
		exit(1);
	}
	else
		{
			printf("read form file:%s\n",buf_r);
			printf("size = %d\n",size);
		}
	if( close(fd) < 0 ){
		perror("close:");
		exit(1);
	}
	else
		printf("Close hello.c\n");
	exit(0);
}

程序执行的结果是:


六、fcntl函数

当多个 用户共同使用和操作一个文件时,为了避免出错和进程竞争资源的问题,linux采用给文件上锁的方式。实现上锁的函数式lock和fcntl。其中flock对文件施加建议锁。而fcntl不仅可以施加建议性锁还可以施加强制性锁。同时fcntl还可以对文件上记录锁。

记录锁又分为读取锁和写入锁,其中读取锁又称为共享锁,它能使多个进程在同一时刻对文件建立读取锁。写入锁又称为排斥锁,在任意时刻只有一个进程可以对文件的某一部分施加写入锁。当然,在文件的同一部分不能同时建立写入锁和读取锁。


下面是测试文件的写入锁,首先创建一个hello文件,然后加上写入锁,写入之后释放写入锁。

#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>

void lock_set(int fd, int type)
{
	struct flock lock;
	//加锁整个文件
	lock.l_whence = SEEK_SET;
	lock.l_len =0;
	while(1){
		lock.l_type = type;
		
		if((fcntl(fd, F_SETLK, &lock)) == 0){
		if( lock.l_type == F_RDLCK )
			printf("read lock set by %d\n",getpid());
		else if( lock.l_type == F_WRLCK )
			printf("write lock set by %d\n",getpid());
		else if( lock.l_type == F_UNLCK )
			printf("release lock by %d\n",getpid());
		return;
		}
		fcntl(fd, F_GETLK,&lock);
		if(lock.l_type != F_UNLCK){
			if( lock.l_type == F_RDLCK ) 
				printf("read lock already set by %d\n",lock.l_pid);
			else if( lock.l_type == F_WRLCK )
				printf("write lock already set by %d\n",lock.l_pid);
			getchar();
		}
	}
}

int main(void)
{
	int fd;
	fd=open("hello",O_RDWR | O_CREAT, 0666);
	if(fd < 0){
		perror("open");
		exit(1);
	}
	lock_set(fd, F_WRLCK);
	getchar();
	lock_set(fd, F_UNLCK);
	getchar();
	close(fd);
	exit(0);
}

为了更好的展示写入锁的效果,可以打开两个终端执行这个程序,看程序的运行的结果。

终端1运行的结果:




终端2运行的结果:


七、总的来说I/O处理的模型有5种。

1、阻塞I/O模型:在这种模型下,若所调用的I/O函数没有完成相关的功能,就会将进程挂起,直到相关数据到才会出错返回。如常见的对管道设备、终端设备和网络设备进行读写时就会经常出现这种问题。

2、非阻塞模型:这种模型下,当情求的I/O不能完成时,则不让进程睡眠,而是返回一个错误。

3、I/O多路转接模型:在这种模型下,如果请求的I/O阻塞,且它不是真正的阻塞,而是让其中的一个函数等待,在这期间,I/O还能继续其他的操作。select函数就是属于这种模型。

4、信号驱动I/O模型:在这种模型下,通过安装一个信号处理程序,系统可以自动捕获特定信号的到来,从而启动I/O。这是由内核通知用户何时何时启动I/O操作。

5、异步I/O模型:在这种模型下,当一个描述符已经准备好,可以启动I/O时,进程会通知内核。现在,并不是所有的内核都支持这种模型。

可以看到select的多路转接模型是处理I/O复用的一个高效的方式。它可以具体设置每一个具体所关心的文件描述符的条件、等待的时间。


本例中是将hello1的内容读出,并将此内容每隔10秒写入hello2中。在这里建立了两个描述符集,其中一个描述符inset1用于读取文件,另一个inset2用于写文件。在初始化文件描述符之后,就循环的测试这两个文件是否可读写,由于这里没有阻塞,所以文件描述符处于准备就绪状态。这时对两个描述符进行fds[0]和fds[1]进行读写操作。

/*select.c*/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int fds[2];
	char buf[7];
	int i,rc,maxfd;
	fd_set inset1,inset2;
	struct timeval tv;
	//以一定的权限打开文件hello1
	if((fds[0] = open ("hello1", O_RDWR|O_CREAT,0666))<0)
		perror("open hello1");
		//以一定的权限打开文件hello2
	if((fds[1] = open ("hello2", O_RDWR|O_CREAT,0666))<0)
		perror("open hello2");
		//将字符写入hello1文件
	if((rc = write(fds[0],"Hello!\n",7)))
		printf("rc=%d\n",rc);
		//将文件指针恢复在起始的位置
	lseek(fds[0],0,SEEK_SET);
	//取出两个文件描述符较大者
	maxfd = fds[0]>fds[1] ? fds[0] : fds[1];
	//初始化读集合inset1,并在读集合中加入描述集
	FD_ZERO(&inset1); 
	FD_SET(fds[0],&inset1);
	//初始化写集合inset2,并在写集合中加入描述集
	FD_ZERO(&inset2);
	FD_SET(fds[1],&inset2);
	
	tv.tv_sec=2;
	tv.tv_usec=0;
	//循环的测试这两个文件是否可读写
	while(FD_ISSET(fds[0],&inset1)||FD_ISSET(fds[1],&inset2)){ 
		if(select(maxfd+1,&inset1,&inset2,NULL,&tv)<0) 
			perror("select");
		else{
			if(FD_ISSET(fds[0],&inset1)){
				rc = read(fds[0],buf,7);
				if(rc>0){
					buf[rc]='\0';
					printf("read: %s\n",buf);
				}else
					perror("read");
			}
			if(FD_ISSET(fds[1],&inset2)){
				rc = write(fds[1],buf,7);
				if(rc>0){
					buf[rc]='\0';
					printf("rc=%d,write: %s\n",rc,buf);
				}else
					perror("write");
			sleep(10);
			}
		}
	}
	exit(0);
}

程序运行的结果:


程序运行的流程:



版权所有,属于华清远见。

分享到:
评论

相关推荐

    linux系统文件I/O编程

    掌握Linux中系统调用的基本概念 掌握Linux中用户编程接口(API)及系统命令的相互关系 掌握文件描述符的概念 掌握Linux下文件相关的不带缓存I/O函数的使用 ...熟悉Linux中标准文件I/O函数的使用

    linux 文件I/O编程

    在Linux系统中,文件I/O(输入/输出)编程是操作系统与应用程序交互的重要部分,它涉及到数据在程序和磁盘之间的传输。以下是对标题和描述中提到的知识点的详细解释: 1. **open()**: `open`函数是用于打开一个文件...

    怎么使用I/O编程???

    【I/O编程基础】 在Java编程中,I/O(Input/Output)处理是与外部世界交互的关键技术,涉及文件读写、网络通信等场景。I/O的核心思想是通过流(Stream)来传输数据,使得程序能从数据源读取数据或将数据写入目标。 *...

    Linux文件I/O编程实验代码copy_file

    在这个实验"Linux文件I/O编程实验代码copy_file"中,我们将深入理解如何使用C语言进行低级别的文件复制。这个实验的主要目标是实现一个名为`copy_file`的函数,它可以将源文件的内容复制到目标文件。 首先,我们...

    Linux的I/O编程的基础实验open.c

    在Linux操作系统中,I/O...在实际项目中,你可能还会遇到更多复杂的情况,比如多线程下的I/O同步、异步I/O、缓冲I/O等,这些都是Linux I/O编程的深入话题。不过,从基础实验"open.c"开始,你已经迈出了坚实的第一步。

    Java I/O编程 java

    在Java I/O编程中,理解不同类型的流及其用途至关重要。字节流和字符流分别处理二进制和文本数据,过滤流提供了额外的功能,管道流实现了线程间的通信,对象流使得对象可以持久化。掌握这些基础,开发者能够有效地...

    Linux下必用的I/O 操作手段I/O文件

    文件I/O操作是API的一个重要部分,包括打开文件(open)、读取文件(read)、写入文件(write)、改变文件位置(lseek)以及关闭文件(close)等功能。这些函数允许程序与文件系统进行交互,完成数据的读写。 文件描述符是...

    文件I/O实验的实验报告

    实验 单片机I/O 口控制实验 一. 实验目的 利用单片机的P1 口作IO 口,使用户学会利用P1 口作为输入和输出口。 二. 实验设备及器件 IBM PC 机 一台

    java阻塞i/o与非阻塞i/o控制

    在Java编程环境中,I/O(输入/输出)操作是程序与外部世界交互的关键部分,包括读取文件、网络通信等。对于高效的系统设计,理解并掌握阻塞I/O和非阻塞I/O是非常重要的。这两种I/O模型在处理数据传输时有着显著的...

    Unix I/O 小结

    Unix I/O系统是操作系统的核心部分,它提供了对文件和设备进行输入输出操作的接口。本文主要总结了Unix下的I/O模型及其相关系统调用。 在Unix中,每个进程都有一个打开文件描述符表,用于存储指向文件inode的指针和...

    Linux C | Linux标准I/O编程

    总结来说,Linux标准I/O编程是通过C语言标准库提供的函数接口,如fopen、fread、fwrite等,来实现对文件的操作,这些函数在内部使用系统调用并管理缓冲区,从而提高了程序的可移植性和效率。理解这些基础知识对于...

    异步I/O处理

    在进行异步I/O编程时,使用工具如调试器、日志记录、性能分析器等可以帮助理解程序的行为和优化性能。对于初学者来说,阅读和分析开源项目源码也是很好的学习途径,例如查看上述链接的博客文章《异步I/O处理》...

    SHENZHEN I/O Manual (深圳 I/O 游戏手册)

    根据提供的文件内容,可以看出SHENZHEN I/O是一款集成了电子电路设计、编程模拟和经营策略元素的电脑游戏。以下是从手册内容中提取的详细知识点: 1. SHENZHEN I/O游戏手册的使用建议: 手册建议玩家为了获得最佳的...

    LabVIEW的文件I/O操作

    常见的文件I/O操作包括以下流程: · (1)创建或打开一个文件。文件打开后,引用句柄即代表该文件的... 文件操作节点位于程序框图函数选板的“编程→文件I/O”中,如图1所示。  图1 文件I/O子选板  文件I/

    unix平台下I/O聚集和分离的一种方案

    在处理多个文件或套接字时,I/O聚集和分离是优化性能和管理资源的重要手段。本篇文章将详细探讨在Unix平台下实现I/O聚集和分离的一种方案,以及其背后的原理和实际应用。 首先,理解I/O模型是至关重要的。Unix系统...

    关于I/O流读写文件

    I/O流读写文件 I/O流是Java编程语言中的一种基本概念,用于处理输入输出数据的功能。在Java中,I/O流是通过流的概念来实现的,流是一种抽象表示,用于表示输入设备或输出设备。根据不同的功能,I/O流可以分为输入流...

    Socket I/O 模型的使用示例

    Socket I/O 模型在计算机网络编程中扮演着至关重要的角色,它允许应用程序通过网络进行数据传输。在本文中,我们将深入探讨异步Socket I/O模型的几种常见实现方式,包括选择(select)、异步选择(asynchronous ...

    windows下六种socket I/O模型示例

    在Windows操作系统中,进行网络编程时,我们常常会遇到多种Socket I/O模型。这些模型决定了如何处理输入/输出操作,从而影响程序的性能和效率。本文将深入探讨六种主要的Socket I/O模型,并通过实例解析它们的工作...

Global site tag (gtag.js) - Google Analytics