unix高级环境编程之文件io(上)
apue学习总结之文件IO操作
1-文件描述符:
首先我们 要知道文件描述符的概念,文件描述符是操作系统为了描述文件而产生的一个概念,对与操作系统而言,一切都是文件,所以操作系统需要管理这些文件的时候,打 开一个文件就给它分配一个文件的标识,也就是文件描述符。站在文件描述符的角度就是在用此文件描述符来引用文件。
文件描述符是一个非负的整形,当打开一个文件或者创建一个文件时,内核向进程返回一个文件描述符,当读写文件的时候将其作为参数传递给读写操作的函数。
2-文件操作的几个关键的函数:
在ubuntu12.10操作系统下man手册当中的函数定义如下:
如下为open和creat函数的定义(主要完成的功能为:打开文件和创建一个新的文件):
1 open creat open and possibly create a file or device 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 7 int open(const char *pathname, int flags); 8 int open(const char *pathname, int flags, mode_t mode); 9 int creat(const char *pathname, mode_t mode);
参数pathnam为在当前操作系统当中的文件的路径,可以是相对路径也可以是绝对路径。
flags参数为:以什么样的方式进行创建或者打开。用的对多的O_CREAT O_RDONLY O_RDWR
mode参数为创建文件的权限为多少一般是mode权限减去umask的值,umask值是当前操作系统的一个权限管理的标识值,一般创建的文件的权限都是当前创建的文件的权限减去这个umask的值。并且权限值一般用8进制表示.
read - read from a file descriptor #include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
此 函数是读取创建的文件描述符所制定的文件的内容,所以里面传的参数就是前创建的fd , 第二个参数是从文件中读取的内容存放到内存的一块区域上也就是自定义的buf,第三个参数是读取的字节数。其实读取文件的过程就是从存储设备上的文件内容 读取到内存上,进行自己的利用。返回值就是读到的字节数。如果出错将会返回errno。
1 write - write to a file descriptor 2 3 4 #include <unistd.h> 5 6 ssize_t write(int fd, const void *buf, size_t count);
此函数是从一块buf当中的内容写入到文件当中,返回写入正确的字节数,否则返回-1
第三个参数是写入的字节数。
#include <sys/types.h> #include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
lseek()函数是用来改变当前的文件偏移量,文件偏移量为所打开的文件偏移文件的开始的位置。下面用具体的例子来说明
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 6 /* 测试标准输入能否改变偏移量*/ 7 8 int main() 9 { 10 if( lseek( STDIN_FILENO , 0 , SEEK_CUR ) == -1 ) 11 printf("cannot seek!\n"); 12 else 13 printf("seek ok!\n"); 14 return 0; 15 }
此例子是为了测试默认打开的标准输入能否改变其偏移量。
当一个文件的偏移位置到了文件的实际内容的末尾,如果再进行往后偏移的话将会产生一个文件的空洞。这些空洞将会以/0填充。下面我们来做一个这样的实验:
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 #include <stdlib.h> 7 8 #define err(x) {\ 9 perror(x); \ 10 exit(1); \ 11 } 12 13 /* 当文件偏移量大于当前文件的长度,将会产生一个文件空洞*/ 14 /* 下面我们创建一个具有空洞的文件 */ 15 16 char buf1[] = "abcdefghij"; 17 char buf2[] = "ABCDEFGHIJ"; 18 19 int main() 20 { 21 int fd = open("./file.hole" , O_RDWR | O_CREAT , 0666); 22 if( fd == -1 ) 23 { 24 err("creat"); 25 } 26 if( write( fd , buf1 , 10 ) != 10 ) 27 { 28 err("write"); 29 } 30 /* now offset is 10 */ 31 if( lseek( fd , 40 , SEEK_SET ) == -1 ) 32 { 33 err("lseek"); 34 } 35 /* now offset is 40 */ 36 if( write( fd , buf2 , 10 ) != 10 ) 37 { 38 err("write"); 39 } 40 return 0; 41 }
下面的一个例子为实现linux操作系统下的cat命令,可以将一个可读文件里的内容显示出来。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 #include <string.h> 10 char buf[BUFSIZ]; 11 12 int main(int argc , char *argv[] ) 13 { 14 int fd = open( strncat("./" , argv[1] , sizeof(argv[1]) ) , O_RDONLY ); 15 if( fd == -1 ) 16 { 17 perror("open "); 18 exit(1); 19 } 20 memset( buf , 0 , BUFSIZ ); 21 while( read( fd , buf , BUFSIZ ) >0 ) 22 { 23 printf("%s\n" , buf ); 24 } 25 return 0; 26 }
在linux操作系统中,一切都是文件,包括设备,默认输入设备为键盘,默认的输出设备为屏幕,既然是文件就对应着有它的文件描述符,0为标准输入,1为标准输出,2为标准的错误输出,然后系没打开一个文件则系统将自动为它分配一个从3开始的文件描述符,也就是说当前三个默认都被占据着之后最小的文件描述符为3.如下例子为:从标准输入复制到标准的输出,即从0当中读内容写到1当中打印出来。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 8 /*此例子是从输入端复制到输出端 */ 9 10 int main() 11 { 12 int n ; 13 char buf[BUFSIZ]; 14 while( (n = read( STDIN_FILENO , buf , BUFSIZ )) > 0 ) 15 { 16 if( write( STDOUT_FILENO , buf , n ) != n ) 17 { 18 perror("write"); 19 exit(1); 20 } 21 } 22 23 if( n == -1 ) 24 { 25 perror("read"); 26 exit(1); 27 } 28 return ; 29 }
本人第一次写博客希望大家指出其中的不足共同学习!