zoukankan      html  css  js  c++  java
  • C和指针 第十五章 二进制I/O

    二进制I/O

     数据写入到文件效率最高的是用二进制形式写入,二进制输出避免了在数值转换为字符串过程中,所涉及的开销和精度损失,但而精致并非人眼所能阅读,所以这个技巧只有当数据被另一个程序按顺序读取才能使用。

    /*二进制读和写函数
    buffer是指向用于保存数据的内存位置指针
    size 是缓冲区中每个元素的字节数
    count 是读取或写入的元素数量
    stream是读写流*/
    size_t fread(void *buffer, size_t size, size_t count, FILE *steam);
    size_t fwrite(void *buffer, size_t size, size_t count, FILE *steam);
    

    buffer被解释为一个或多个值的数组,count参数指定数组中有多少值,所以读取标量,count值应该为1。函数返回值是实际读取或者写入的元素(非字节)数目。如果遇到文件结尾或者错误,那么这个数字可能比请求的元素数目要小。

    下面的代码先二进制写入浮点数到文件,然后再读出:

    #include <stdio.h>
    #include <string.h>
    
    int main(){
    	float array[2] = {1.1, 2.2};
    	float temp[2];
    
    	FILE *file = fopen("D:\C\writeBin.txt", "wb");
    	if(file == NULL){
    		printf("open error");
    	}
    	//二进制写入两个浮点数
    	if(fwrite(array, sizeof(float), 2, file) != 2){
    		printf("写入失败
    ");
    	}
    	fclose(file);
    
    	//二进制打开
    	file = fopen("D:\C\writeBin.txt", "rb");
    	//二进制读入两个浮点数
    	if(fread(temp, sizeof(float), 2, file) == 2){
    		printf("temp: %.2f %.2f
    ", temp[0], temp[1]);
    	}
    
    	return 0;
    }
    

    运行:

    文件打开是二进制不可见的,所以乱码

    刷新的定位函数:

    fflush迫使一个输出流的缓冲区内的数据进行物理写入,不管它是否已经写满,原型如下:

    int fflush(FILE *stream);
    

    当需要把输出缓冲立即写入时可以使用这个函数

    正常情况下,数据以线性的方式写入,后写入的数据在文件中是在之前写入的数据之后的,C语言支持随机访问I/O,可以任意顺序访问文件的不同位置。通过在读写前确定到文件中需要的位置来实现。下面两个函数:

    //返回流当前位置,也就是下一个读取或者写入开始的位置,距离文件起始位置的偏移量
    long ftell(FILE *stream);
    

    二进制流中,返回值就是距离开始的字节数,文本流中,这个值表示一个位置,但它不一定是距离文件开始的字节数,因为系统会对行尾字符进行翻译转换,但是它的值都可以传递给fseek,作为距离开始位置偏移量。

    //fseek函数允许你在一个流中定位,将改变下一个读入和写入操作的位置。
    int fseek(FILE *stream, long offset, int from);
    

    定位到起始位置之前是错误的,定位到文件尾之后写入将扩展这个文件,读取将导致“到达文件尾”信息。

    #include <stdio.h>
    
    int main()
    {
    	float array[2] = {1.1, 2.2};
    	FILE *file = fopen("D:\C\writeBin.txt", "wb");
    	
    	fwrite(array, sizeof(float), 5, file);
    	//偏移到seek_end之后,将扩展文件
    	fseek(file, 1000, 0);
    	fwrite(array, sizeof(float), 1, file);
    
    	fclose(file);
    	return 0;
    }

    SEEK_SET,流起始位置

    SEEK_CUR,流当前位置

    SEEK_END,流尾部结束位置

    对于二进制流,从SEEK_END进行定位可能不被支持,应该避免

    对于文本流,因为会执行行末字符映射,所以文本文件的字节数可能和程序写入的字节数不同,所以无法通过SEET_CUR和SEEK_END准确定位,所以用这个两个位置时offset应该为0,如果是从SEEK_SET,offset必须是ftell的返回偏移位置。

    如果使用fseek,将导致三个副作用,

    1.行尾指示字符被清除

    2.ungetc把字符返回流中,那么这个被退回的字符将被丢掉,因为在定位操作后,它不再是下一个字符了。

    3.定位允许从写模式切换到读取模式

    #include <stdio.h>
    
    int main()
    {
    	float array[2] = {1.1, 2.2};
    	float temp[1];
    	FILE *file = fopen("D:\C\writeBin.txt", "wb");
    	fwrite(array, sizeof(float), 5, file);
    	fseek(file, 1000, 0);
    	//更改写模式到读模式
    	fread(temp, sizeof(float), 1, file);
    	//打印1.1
    	printf("%lf
    ", temp[1]);
    	fclose(file);
    	return 0;
    }
    

    运行:

    //将读写指针设置为指定流的起始位置,同时清除流错误提示标志。
    void rewind(FILE *stream);
    

    fgetpos和tfsetpos分别是ftell和fseek的替代,但是不是标准定义的。

    改变缓冲方式

    当流打开后,没有进行任何其他操作时,可以通过下面的函数改变留的缓冲方式

    //另设一个数组,用于对流进行缓冲
    void setbuf(FILE *stream, char *buf);
    

    为流自行指定一个缓冲,大小为BUFSIZ,定义在stdio.h中,可以防止I/O函数库为他动态分配缓冲,如果使用NULL调用,则关闭所有缓冲方式

    int setvbuf(FILE *stream, char *buf, int mode, size_t size);
    

    mode参数用于设置缓冲模式,_IONBF指定不缓冲,__IOLBF,行缓冲,每遇到换行符,缓冲刷新,__IOFBF指定一个完全缓冲流。

    流错误函数

    //遇到文件尾,返回真,可以通过fseek和rewind清除
    int feof(FILE *stream)
    //报告流错误状态,如果出现错误返回真
    int ferror(FILE *stream);
    //对流错误标志重置
    void  clearerr(FILE *stream);
    

    临时文件和文件操纵

    //创建一个文件,wb+打开,程序关闭后自动删除,不会与已存在文件同名
    FILE *tmpfile(void);
    //删除文件,成功返回0
    int remove(char const *filename);
    //重命名,成功返回0
    int rename(char const*oldname, char const * newname);
    

    重命名后删除文件:

    #include <stdio.h>
    
    int main()
    {
    	printf("%d
    ", rename("writeBin.txt", "newName"));
    	printf("%d
    ", remove("newName"));
    	return 0;
    }
    

    运行

  • 相关阅读:
    android 蓝牙各种UUID (转)
    Linux下Shell重定向
    linux命令学习笔记——tee命令
    正则表达式之正向预查和反向预查
    shell常用正则表达式
    saltstack知识点
    linux命令学习笔记——ldd命令
    shell中${ } 的一些特异功能
    linux命令学习笔记——nl命令
    linux命令学习笔记——losetup命令:设置循环设备
  • 原文地址:https://www.cnblogs.com/yangxunwu1992/p/5862224.html
Copyright © 2011-2022 走看看