文件IO操作相关系统编程

这里主要说两套IO操作接口,分别是:

POSIX标准

read|write接口,函数定义在#include<unistd.h>

ISO C标准

fread|fwrite接口,函数定义在#include<stdio.h>

有书上说POSIX标准与ISO C标准的区别在于文件读写是否带缓冲区,我则不是很认同,因此POSIX标准下的IO操作也是带缓冲区的,至于这两个标准下的IO性能谁更加好则不一定,因为这和缓冲区的大小,以及用户逻辑有很大关系。

POSIX标准
ssize_t read (int __fd, void *__buf, size_t __nbytes)

ssize_t write (int __fd, constvoid *__buf, size_t __n)

读规则:

如预读字节数>文件总字节数,则全部读入文件字节数,返回值为文件字节数

如预读字节数<文件总字节数,则读满__buf(以__nbytes为准)后返回,下回读取会将继续读

如读到文件末尾,则返回值为0

比如:文件长度是100,buf长度是70,那么第一个读取70,读2此会读取剩下的30 ,第三次由于文件游标已经处于文件末尾,则返回0

写操作

#include <unistd.h>
#include <fcntl.h>
#include<stdio.h>
#define BUFFER_SIZE 200
int main() {
    int fd = -1;
    if (access("/tmp/iofile", F_OK)) {
        fd = creat("/tmp/iofile", 0777);
    } else {
        fd = open("/tmp/iofile", O_WRONLY | O_APPEND);
    }
    if (fd == -1) {
        perror("文件打开错误!");
        return -1;
    }
    char buf[BUFFER_SIZE];
    int val = 0, sum = 0;
    do {
        val = read(0, buf, BUFFER_SIZE);
        if (val > 0) {
            write(fd, buf, BUFFER_SIZE);
        } else {
            break;
        }
        sum += val;
    } while (1);
    printf("写入数据总长度是:%d\n", sum);
    return 1;
}

读操作

#include <unistd.h>
#include <fcntl.h>
#include<stdio.h>
#define BUFFER_SIZE 400
int main() {
    int fd = open("/tmp/iofile", O_RDONLY);
    if (fd == -1) {
        perror("文件打开错误!");
        return -1;
    }
    char buf[BUFFER_SIZE];
    int val = 0, sum = 0;
    do {
        val = read(fd, buf, BUFFER_SIZE);
        printf("读入数据长度是:%d\n", val);
        if (val > 0) {
            write(1, buf, BUFFER_SIZE);
            printf("\n");
        } else {
            sleep(1);
        }
        sum += val;
    } while (1);
    return 1;
}

执行顺序

1.执行写操作:

tkf@tkf:~/workspace/FileIOWrite/Debug$./FileIOWrite </etc/mtab

写入数据总长度是:990

2.在另外命令行(进程)执行读操作

tkf@tkf:~/workspace/FiloIORead/Debug$./FiloIORead

读入数据长度是:400

读入数据长度是:400

读入数据长度是:200

读入数据长度是:0

……..

è由于此时文件游标已经处于文件末端因此,长度是0

读入数据长度是:0

3.再次执行写操作

tkf@tkf:~/workspace/FileIOWrite/Debug$./FileIOWrite </etc/mtab

写入数据总长度是:990

此时读端进程输出

读入数据长度是:400

读入数据长度是:400

读入数据长度是:200

读入数据长度是:0

è因为再次有数据写入,所以可以读到数据,当数据再次读取完毕,则返回0

当然对于第三步骤,我们也可以通过更改读进程游标的位置(lseek)使其能读到数据

IO效率

根据书上效率对比试验,当缓冲区大小(buf)等于文件系统块大小时,性能是最佳的。

文件系统块大小struct stat –>st_blksize 查看

对于IO操作主要步骤可以理解为:

1.内核与系统缓冲区的数据拷贝

2.系统缓冲区与用户缓冲区的拷贝

举例,用户BUF是10字节,系统缓冲区时4096字节,那么到我们写端将用户BUF数据拷贝被系统缓冲区中,由于系统缓冲区没有填满,因此不会执行IO操作,直到写满或者执行同步操作。对于读来说,文件系统会将数据先都预读到系统缓冲区,每次我们请求读都是从系统缓冲区拷贝到用户缓冲器。因此在数据存在缓冲区并没有写到磁盘时如果系统出现故障可能数据会丢失。

ISO C标准(标准IO)

标准IO是围绕流的,他与POSIX标准相比可以使用户不用关注分配缓冲区的大小,他会选择适当缓冲区以优化执行IO

冲洗(fflush)
对于标准IO来说,冲洗就是讲缓冲区的数据写入磁盘

缓冲
对于标准IO库提供了三种类型的缓冲

全缓冲:在填满标准IO缓冲区后才进行实际的IO操作

行缓冲:当输入和输出遇到换行符时才执行实际的IO操作

不带缓冲:每次一个都进行实际的IO操作

void setbuf(FILE *__restrict __stream, char *__restrict __buf) ;

int setvbuf (FILE *__restrict __stream, char *__restrict __buf,

int __modes, size_t __n) ;

参数:

__n:缓冲区长度

__buf:缓冲区指针

__stream文件流

__modes:缓冲模式

_IOFBF0:全缓冲

_IOLBF 1:行缓冲

_IONBF 2:无缓冲

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/18996.html