Linux操作系统-标准IO库(3)

Linux操作系统—标准IO库(3)(2015-8-5)

分类:Linux操作系统

二进制IO和定位流

  二进制I/O也称直接I/O,一个一个对象的I/O,面向记录的I/O或面向结构的I/O。每次I/O操作读取或写一定数量的对象,而每个对象具有指定的长度。常用于二进制文件中读或向二进制文件中写一个结构。

读取二进制流

  使用fread函数可以进行二进制数据的读取。

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

  函数fread的各参数和返回值的含义如下:
1. ptr:输入缓存
2. size:数据块的大小
3. nitems:数据块的个数
4. stream:流文件指针
5. 返回值:返回实际读取到的数据块的个数。如果次数字小于nitems,则表示出错或到达文件尾端,应调用ferror或feof以判断究竟是哪一种情况

  这个函数参数有点多,还是找一个使用的例子来看看

nRead = fread(buf, sizeof(unsigned char), BUFFSIZE, fpIn);

  这一小段代码的作用是:调用fread函数从源文件中读取BUFFSIZE各字节。fpIn是源文件的流指针,BUFFSIZE是数据块的个数,sizeof(unsigned char)是数据块的大小,也即是一个字符的大小,buf是输入的缓存,也即是fread读取的数据存放的地方。fread返回的是实际读取的字符数,该数值被记录在了变量nRead中。
  实际读取的数据块的个数nRead如果小于预定的BUFFSIZE,则表示出错或者到达文件尾端,应调用ferror或feof以判断究竟是哪中情况。

写二进制流

  使用fwrite函数可以进行二进制数据块的输出。

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);

  函数fwrite的各参数和返回值的含义如下:
1. ptr:待输出的数据的
2. size:数据块的大小
3. nitems:数据块的个数
4. stream:流文件的指针
5. 返回值:返回实际输出的数据块的个数,如果小于nitems,则表示出错。

  总结这两个函数(不严谨,但可以这样区分两者):
- fread:从stream流中读取数据存入ptr中
- fwrite:从ptr总读取数据存入stream中

二进制I/O的常见用法

  • 读或写一个二进制数组。例如:
float data[10]
...
if (fwrite(&data[2], sizeof(float), 4, fp) !=  4)
    printf("fwrite error.\n");

  这段代码调用fwrite向文件流写入data数组从第3个元素起的连续4个元素,每个数据块的大小为一个元素(一个浮点数)的大小,如果写入的元素个数不为4,则说明发生了错误。

  • 读或写一个结构。此时,指定size为结构体的大小,nitems指定为1。例如:
struct {
    short count;
    long total;
    char name[NAMESIZE];
}item;
...
if (fwrite(&item, sizeof(item), 1, fp) != 1)
    printf("fwrite error");

  这段代码盗用fwrite向文件流写入结构体变量item,数据块为1,返回值如果不为1,则说明发生了错误。

  • 以上二者的结合。如:向一个结构体数组内写数据。

二进制I/O实践篇

目标:实现简单的问价复制功能

#include <stdio.h>
#include <stdlib.h>
#define     BUFFSIZE    80  

int main(int argc, char *argv[])
{
    FILE *fpIn, *fpOut;
    int nRead, nWrite;
    unsigned char buf[BUFFSIZE];

    if (argc != 3){         /* 如果从命令行传递过来的参数的个数不是3个 */                                          
        printf("Usage : %s <source_file> <destination_file>\n", argv[0]);
        return -1;
    }
                            /* 如果要被复制的文件无法打开被读取 */
    if ((fpIn = fopen(argv[1], "r")) == NULL){
        printf("Cannot open file [%s] for reading.\n", argv[1]);
        return -1;
    }
                            /* 如果复制过来的新文件无法打开被写入 */
    if ((fpOut = fopen(argv[2], "w")) == NULL){
        printf("Cannot open file [%s] for writing.\n", argv[2]);
        return -1;
    }
                            /* 当要被复制的文件没有到达文件尾时 */
    while (!feof(fpIn)){
        nRead = fread(buf, sizeof(unsigned char), BUFFSIZE, fpIn);
        if (nRead < BUFFSIZE){
            if (ferror(fpIn)){              /* 如果读取出错了 */
                printf("Copy failed.\n");
                break;
            }
        }

        if (nRead > 0){                     /* 进行复制操作 */
            nWrite = fwrite(buf, sizeof(unsigned char), nRead, fpOut);
            if (nWrite != nRead){           /* 如果复制出错了 */
                printf("Copy failed.\n");
                break;
            }
        }
    }

    fclose(fpOut);                          /* 将文件关闭 */
    fclose(fpIn);

    return 0;
}

  编译并运行

biantiao@lazybone1994-ThinkPad-E430:~/桌面$ gcc -o ioCopy ioCopy.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./ioCopy
Usage : ./ioCopy <source_file> <destination_file>
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./ioCopy a.txt b.txt
Cannot open file [a.txt] for reading.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ touch a.txt
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./ioCopy a.txt b.txt
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ls
a.txt  b.txt  ioCopy  ioCopy.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$

  你可以发现参数argv[0]不是ioCopy而是./ioCopy,如果你不想在运行时加入./,就把ioCopy程序文件放入bin目录下好了。

定位流

  可以调用fseek来定位流文件的读写指针。

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

  函数fseek的各参数和返回值的含义如下:
1. stream:流文件的指针
2. offset:位移量
3. whence:指定位移量相对于何处开始。whence可以取如下三个常量

  • SEEK_SET:文件开始位置
  • SEEK_CUR:文件指针当前位置
  • SEEK_END:未见结束位置

4 返回值:成功返回0,失败返回-1,错误记录在errno

  一次成功的调用ftell()会清除流结束标志,并会撤销已调用的ungetc()对流的影响。调用rewind()函数可以将一个流的读写指针设置到文件的起始位置。其原型如下:

#include <stdio.h>
void rewind(FILE *stream);

  该函数的唯一参数是已打开流的流文件指针。调用rewind(fp)基本等同于调用fseek(stream, 0L, SEEK_SET)。稍微不同的是,rewind函数将在读写指针设置到文件的起始位置时同时会将出错指示errno清0
  调用ftell()函数可以获得一个流的读写指针的当前位置。该函数的原型如下:

#include <stdio.h>
long ftell(FILE *stream);

  该函数返回读写指针当前相对于文件起始位置的位移量;若出错,则返回-1,错误记录在errno中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值