I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分.。
与IO性能直接相关的几个缓存分别是文件系统缓存(File SySTem Cache)、磁盘控制器缓存(Disk CONtroller Cache)和磁盘缓存(Disk Cache,也称为Disk Buffer)。
不管是控制器缓存还是磁盘缓存,他们所起的作用主要是分为三部分:缓存数据、预读(Read-ahead)和回写(Write-back)。
什么是文件的概念:就是一组相关数据的有序集合,而文件名就是这组数据集合的名称。
一般常规文件有ASCII码文件还有就是二进制文件还有包括目录和字符设备,块设备,有名管道,套接口,和符号链接;
在说明文件IO和标准IO的区别之前
先了解到的是在UNIX操作系统下的出错处理:
首先了解的是全局出错码errno,它的头文件是<errno.h>,它返回的是字符串格式输出,那么打印格式就是printf("%s\n",error);
还有一种打印方法,即perror("this is "),这是一种简化形式,他会自己自动补上是成功读取还是失败。它的输出格式是双引号里的字符(字符自己打的)后面会默认加上:冒号还有输出的出错信息和成功信息。
【1】文件IO
文件IO是直接对应内核的系统调用。
当一个文件IO(读写)要对磁盘的数据访问读写输入输出的时候,内核系统会保护硬件,从而会在内核空间创建文件描述符,内核向进程返回一个文件描述符,他表示硬件设备文件在内存空间的映像。
文件IO不带缓冲,指的是每个read和write都是调用内核中相应的系统调用,不带缓存的文件IO不是ANSI的一部分,但是是POSIX的一部分,都经过标准的API。
对于常用的文件IO函数有;open read write close lseek以及creat函数(是open函数的一层封装):
对于open函数有几种形式,一般形式如下:
#include
#include
#include
#include
int main ()
{
int fd;
fd = open ("/home/tmp/text.c",
O_RDONLY|O_WRONLY|O_RDWR|
O_CREAT|O_APPEND,0777):
if (fd == -1){
perror("can not open");
return -1
}else{
return 0
}
}
//这里RD,WR,RDWR三种形式只有有一种形式出现就可以,他们是互斥关系
//对于CREAT表示打开的文件不存在可以以创建的形式打开,但是后面要加权限位0777
//,等其他权限,而APPEND是决定以什么方式创建文件的还有一种形式就是以清零
//的形式O_TRUNC
example 2
#include
#include
#include
#include
#include
#define lockfile "/etc/tmp" int main () { int fd; if (fd = open (lockfile,O_RDWR|O_CREAT|O_TRUNC,0644) == -1) { fprintf(stderr,"%d\n",errno); return -1; } }
return的成功返回时0,错误返回时-1。
当一个进程结束时,该进程打开的所有文件有内核来关闭,或者用close来关闭,
关闭一个文件的同时,也释放该进程加在该文件的所有记录锁。
设备文件一般都可以用OPEN函数打开,但不可以创建/dev下面的设备文件,但可以用mknod创建设备的节点
就在open()函数结束时加close(fd);
使用read()函数可以对已经打开的函数进行读取,read函数的一般形式是:
#include
#include
#define N 100
int main ()
{
char buf[N];
size_t nbytes;
ssize_t bytes_read;
int fd;
nbytes = sizeof(buf);
fd = open ("/tec/tmp",O_RDWR|O_CREAT,0644);
if (fd == -1) return -1;
bytes_read = (fd,buf,nbytes);
return 0;
}
/*
*这里的buf是应用程序所开的缓存空间大小,表示这个程序进程执行的时候一次可以读出
*多少数据,而nbytes则是内核文件描述符在内存空间给定进程空间大小,
*所以count的值要比buf大,
*当程序成功读出字节数就是read的返回值,在读操作的当前位移处开始,内核里记录
*了偏移量,buf是由调用者在内存空间创建缓存区的大小,并在使用后由使用者释放
*
*
*/
这里读操作和写操作基本差不多,只是write函数也可以对read函数的写。
文件IO的lseek函数可以记录显示定位一个已经打开的文件
每当一个文件打开,都有一个与其相关的“当前文件偏移量”来记录下次文件从什么地方开始执行,在成功读写后,内核会自动维护偏移量并记录在内核中,标记下次程序从什么地方开始lseek只对常规文件静态文件有效,而对于那些流式文件则会失效,因为流式文件在内核中没有固定的pc标记读取的位置
这里可以间接求取文件大小;length =lseek (fd,0,seek_end);这里的0零时位置偏移量off_t offset。
文件偏移量可以大于文件当前长度,即是大于文件字节数但是不占用文件的空间,这样对文件的写操作会形成空洞。
修改于【2014-11-23-10:15】
【1】对于一个应用程序当要访问磁盘上的文件时,内核会帮应用程序打开文件,通过文件描述符来引用,在内存中创建磁盘上相应的文件内容,内核会向进程返回一个文件描述符,当读文件描述符的时候通过返回的文件描述符来标识文件,之后再将标识文件作为参数返回给read和write,这里的读写操作都是在内存中完成的,并没有改变磁盘上的文件,只有当进程结束后,uinx系统会通过shell关联幻术0,1,2,才可以正真意义上对磁盘文件永久的改写。
【2】对于lseek(当前文件偏移量):文件偏移量是由内核空间来维护的,当一个读写操作进程的时候,内核会自动记录当前位置,以便于下次读写继续从此处开始进行,但是人为也可以对lseek进行修改,当文件偏移量大于文件的字节数的时候,在写操作的时候,会形成空洞,这一点是可以允许的,对于文件中没有写过的字节都可以用0来存储,这只是在内存抽象的文件描述符引用的文件上修改的,当一个进程结束时,空洞并不占用磁盘上的存储区,对于新写的数据需要分配空间,但对于原文件尾部和新写的中间不需要分配磁盘空间。