频道栏目
首页 > 资讯 > 其他 > 正文

Unix环境高级编程(一):文件I-O之读写、偏移操作

16-10-10        来源:[db:作者]  
收藏   我要投稿

本节所说明的函数经常称之为不带缓冲区的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:创建文件时需要,选择此项需要说明第三个参数mode
O_EXCL:如果同时指定了O_CREAT,而文件已存在,则出错。
O_TRUNC:如果此文件存在,且只读或只写打开,则将其长度截断为0
O_NONBLOCK:如果pathname指的是一个FIFO,一个块特殊文件或一个字符特殊文件,选择此项为此文件的本次打开操作和后续的I/O操作设置为非阻塞
O_SYNC:使每次write都等到物理I/0操作完成,及将数据从缓冲区同步到磁盘

由open函数返回的文件描述符一定是最小的未用描述符数字。
看一个栗子

#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

/*常用,似的宏总能以你想的方式工作*/
#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 
char *strerror(int errnum);//此函数映射为一个出错信息字符串,并返回

#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

#define BUFFSIZE 8192
int 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/*
do ... while(0)宏定义常用,作用:使用此结构构造的宏定义不会受到大括号,分号等的影响,使得宏总是会按你的期望运行
*/
#define err_exit(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

#define FILE_MODE 0666
char 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.1M
ll -h file.hole
#大小约为8k
du -h file.hole
#od可查看到文件中的空格
od -c file.hole

一个文件的大小不等于其在磁盘上占有的空间,如空洞文件,还有,可以写几个字节到文件中,可以发现其占用磁盘的就是4k.

相关TAG标签
上一篇:JAVA设计模式--享元模式
下一篇:你敢在速配网站上发秃头丑照吗?
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站