Unix环境高级编程<一>:文件I-O之读写、偏移操作
来源:互联网 发布:移动网络玩游戏卡吗 编辑:程序博客网 时间:2024/05/16 12:46
本节所说明的函数经常称之为不带缓冲区的I/O(unbuffered I/O),ANSI C提供的标准I/O库称为高级I/O,通常也称为带缓冲的I/O
文件描述符:对内核而言,所有打开文件都由文件描述符引用(ulimit -a 查看系统资源,如一个进程能打开的文件描述符个数或ulimit -n),文件描述符是一个非负整数。其中有三个默认打开的文件描述符0(STDIN_FILENO)、1(STDOUT_FILENO)、2(STDERR_FILENO)
一个系统可以支持的文件的个数用cat /proc/sys/fs/file-max查看,这其实和内存有关的
1. 打开、关闭函数
int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);/*仅当创建新文件时,才使用第三个参数。*/
下面看open函数的参数:
O_RDONLY:只读打开O_WRONLY:只写打开O_RDWR:读、写打开O_APPEND:写追加到文件末尾O_CREAT:创建文件时需要,选择此项需要说明第三个参数modeO_EXCL:如果同时指定了O_CREAT,而文件已存在,则出错。O_TRUNC:如果此文件存在,且只读或只写打开,则将其长度截断为0O_NONBLOCK:如果pathname指的是一个FIFO,一个块特殊文件或一个字符特殊文件,选择此项为此文件的本次打开操作和后续的I/O操作设置为非阻塞O_SYNC:使每次write都等到物理I/0操作完成,及将数据从缓冲区同步到磁盘
由open函数返回的文件描述符一定是最小的未用描述符数字。
看一个栗子
#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>/*常用,似的宏总能以你想的方式工作*/#define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0)int main(void){ umask(0);//避免受到shell的umask影响 int fd; fd = open("test.txt", O_WRONLY | O_CREAT | O_EXCL, 0666); if (fd == -1) ERR_EXIT("open error"); printf("open succ\n"); return 0;}
关于UNIX,函数出错常常返回一个负值,并会置errno,文件
#include <string.h>char *strerror(int errnum);//此函数映射为一个出错信息字符串,并返回#include <stdio.h>void perror(const char* msg);//输出由msg指向的字符串
对于errno应知道两条:
(1)如果没有出错,则其值不会被一个例程清除;
(2)任何一个函数都不会将errno置为0
int close(int fd);//关闭
当一个进程终止时,内核自动关闭它所打开的文件,因此也有很多程序不close。
2. 文件读写
ssize_t read(int fd, void *buf, size_t count);/*成功返回读到的字节数,字节数一般小于count,若已到文件尾返回为0,出错返回-1*/ssize_t write(int fd, const void *buf, size_t count);/*其返回值通常与参数值count的值相同,否则表示出错。write出错的一个常见原因:磁盘已写满,或超越一个给定进程的文件长度限制*/
看一个栗子,将标准输入复制到标准输出
#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0)#define BUFFSIZE 8192int main(void){ int n; char buf[BUFFSIZE]; while ( (n=read(STDIN_FILENO,buf,BUFFSIZE)) > 0) { if (write(STDOUT_FILENO,buf,n) != n) ERR_EXIT("write error"); if (n < 0) ERR_EXIT("read error"); } exit(0);}
为什么BUFSIZE是8192呢?你可以测试不同的缓存长度,比较程序的循环次数,运行时间等。
注意:读取成功表明读取到缓存区了,但写操作成功不代表已经写到文件中了,仅仅是表示数据已经拷贝到内核缓存区了,不代表已经同步到文件中了
数据到文件的过程如:数据->内核缓存区->磁盘
延迟写:当数据往文件上写时,数据一般先复制到内核缓存区,若内核缓存区未满,则不将其排入到输出队列,而是等待 其写满或当内核需要重新用该缓存以便存放其他磁盘数据时,再将缓存排入到输出队列。延迟写减少了磁盘的读写次数,但是却降低了文件的更新速度,很可能欲写到文件的数据会丢失,因此可以用fsync函数来同步磁盘的内容。比较一下fsync和O_SYNC:当调用fsync时,它更新文件的内容,而对于O_SYNC,每次对文件调用write函数时,则会更新文件的内容。
3. lseek函数
/*成功返回新的文件位移,出错返回-1*/off_t lseek(int fd, off_t offset, int whence);/*offset:位移量whence如下SEEK_SET:文件位移量被设置为据文件开始处offset个字节SEEK_CUR:被设置为其当前值加offset,offset可正可负SEEK_END:被设置为文件长度加上offset,offset可正可负*/off_t currpos;currpos = lseek(fd,0,SEEK_CUR) /*测试文件是否可以设置位移量,如果文件描述符引用的是一个管道或FIFO,则lseek返回-1,并将errno设置为EPIPE*/
每个打开的文件都有一个与其相关联的“当前位移量”,它是一个非负整数,用于度量从文件开始处计算的字节数,通常,读写操作都从当前文件位移量开始,并使位移量增加所读或所写的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选项,否则该位移量被设置为0,注意lseek函数只修改文件的当前位移量,没有进行任何I/O操作,文件位移量可以大于文件的当前长度
下面看一个栗子,空洞文件
#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>/*do ... while(0)宏定义常用,作用:使用此结构构造的宏定义不会受到大括号,分号等的影响,使得宏总是会按你的期望运行*/#define err_exit(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0)#define FILE_MODE 0666char buf1[] = "abcdefghij";char buf2[] = "ABCDEFGHIJ";int main(void){ int fd; if ( (fd=creat("file.hole",FILE_MODE)) < 0) err_exit("creat error"); if (write(fd,buf1,10) != 10) err_exit("buf1 write error"); /*offset now=10*/ if (lseek(fd,1024*1024,SEEK_SET) == -1) err_exit("lseek error"); /*offset now=40*/ if (write(fd,buf2,10) != 10) err_exit("write error"); /*offset now=50*/ exit(0);}
通过以下三种方式查看
#大小约为1.1Mll -h file.hole#大小约为8kdu -h file.hole#od可查看到文件中的空格od -c file.hole
一个文件的大小不等于其在磁盘上占有的空间,如空洞文件,还有,可以写几个字节到文件中,可以发现其占用磁盘的就是4k.
- Unix环境高级编程<一>:文件I-O之读写、偏移操作
- UNIX环境高级编程--文件I/O(一)
- UNIX环境高级编程----文件I/O
- 《unix高级环境编程》文件I/O
- 《unix高级环境编程》文件I/O
- Unix环境高级编程---文件I/O
- UNIX环境高级编程学习笔记之文件I/O(一)
- UNIX环境高级编程学习之路(一)----文件I/O
- UNIX环境高级编程学习之第三章文件IO-文件读偏移操作
- UNIX环境高级编程笔记之高级I/O
- 《UNIX环境高级编程》笔记--无缓存I/O操作和标准I/O文件操作区别
- 《UNIX环境高级编程》笔记0--无缓存I/O操作和标准I/O文件操作区别
- 高级编程之文件I/O(一)
- Unix环境高级编程第三章文件I/O摘记
- UNIX环境高级编程——文件I/O
- UNIX环境高级编程—文件I/O
- Unix环境高级编程——文件I/O
- 《UNIX环境高级编程》读书笔记 —— 文件 I/O
- Latex 之table
- 字符编码之Base64/32/16编码
- Linux 下创建Oracle表空间
- LeetCode 第十九题 Remove Nth Node From End of List
- Memcache常见问题集
- Unix环境高级编程<一>:文件I-O之读写、偏移操作
- mysql设置初始密码和更改密码(ZIP文件解压安装)
- 声明与定义
- 【H.264/AVC视频编解码技术详解】 九、序列参数集Sequence Paramater Set(SPS)解析
- 外地户籍和车辆将不能在京从事“网约车”
- Java双向认证客户端报错解决
- 【IOC】Spring IOC核心源码学习
- 进程间通信的主要手段
- Chapter 3 Java Threads