我想将文件保存为二进制文件,因为我听说它可能比普通文本文件小.
现在我试图用一些文本保存二进制文件,但问题是该文件只包含文本和NULL最后.我希望文件中只能看到零和一个.
任何解释或建议都非常感谢.
这是我的代码
#include <iostream>
#include <stdio.h>
int main()
{
/*Temporary data buffer*/
char buffer[20];
/*Data to be stored in file*/
char temp[20]="Test";
/*Opening file for writing in binary mode*/
FILE *handleWrite=fopen("test.bin","wb");
/*Writing data to file*/
fwrite(temp, 1, 13, handleWrite);
/*Closing File*/
fclose(handleWrite);
/*Opening file for reading*/
FILE *handleRead=fopen("test.bin","rb");
/*Reading data from file into temporary buffer*/
fread(buffer,1,13,handleRead);
/*Displaying content of file on console*/
printf("%s",buffer);
/*Closing File*/
fclose(handleRead);
std::system("pause");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
unw*_*ind 12
所有文件只包含1和0,在二进制计算机上可以使用.
保存文本时,您将使用给定的编码保存该文本的二进制表示,该编码定义每个字母如何映射到位.
因此对于文本,文本文件或二进制文件几乎无关紧要; 您听说过的空间节省通常会对其他数据类型起作用.
考虑浮点数,例如3.141592653589.如果保存为文本,则每个数字需要一个字符(只计算它们)加上句点.如果以二进制形式保存为float比特的副本,则在典型的32位系统上将需要四个字符(四个字节或32位).调用存储的确切位数,例如:
FILE *my_file = fopen("pi.bin", "wb");
float x = 3.1415;
fwrite(&x, sizeof x, 1, my_file);
Run Code Online (Sandbox Code Playgroud)
是CHAR_BIT * sizeof x,看到<stdlib.h>了CHAR_BIT.
小智 12
您所描述的问题是(很常见的一个链条1,不幸)的错误和误解.让我试着详细说明正在发生的事情,希望你会花时间阅读所有材料:它很冗长,但这些都是程序员应该掌握的非常重要的基础知识.如果你不完全理解所有这一切,请不要绝望:只是试着玩它,一周或两个回来,练习,看看会发生什么:)
字符编码和字符集的概念之间存在着重要的区别.除非你真的明白这种差异,否则你永远不会真正理解这里发生的事情.Joel Spolsky(Stackoverflow的创始人之一,想到它)写了一篇文章,解释了不久前的差异:绝对最低每个软件开发人员绝对,必须知道关于Unicode和字符集(没有借口!).在继续阅读之前,在继续编程之前,请阅读.老实说,读它,理解它:标题毫不夸张.你必须完全知道这些东西.
在那之后,让我们继续:
当一个C程序运行时,一个应该保存"char"类型值的内存位置,就像任何其他内存位置一样,包含一个1和0的序列.变量的"类型"只对编译器有意义,而不是对刚看到1和0并且不知道更多的正在运行的程序.换句话说:你通常会想到某个位于内存中的"字母"(字符集中的元素),实际上有一个位序列(来自字符编码的元素).
每个编译器都可以自由地使用他们希望在内存中表示字符的任何编码.因此,它可以自由地代表我们称之为内线的"换行符",就像它选择的任何数字一样.例如,假设我编写了一个编译器,我同意自己每次我想在内部存储"换行符"时,我将其存储为数字六(6),二进制只有0x6(或二进制为110).
写入文件是通过同时告诉操作系统2四件事来完成的:
fwrite())fwrite)请注意,这与该数据的"类型"无关:您的操作不知道,也不关心.它对字符集一无所知,也不关心:它只是看到从某处开始的一系列零和零,并将其复制到文件中.
以"二进制"模式打开文件实际上是处理新手程序员所期望的文件的正常,直观的方式:您指定的内存位置一对一地复制到文件中.如果编写一个用于保存编译器决定存储为"char"类型的变量的内存位置,则这些值将一对一写入文件.除非你知道编译器如何在内部存储值(它与换行符相关联的值,带有字母'a','b'等),否则这是无意义的.将此与Joel关于文本文件无用而不知道其编码是什么的类似观点相比:同样的事情.
在"文本"模式下打开文件几乎等于二进制模式,只有一个(并且只有一个)区别:任何时候写入的值的值等于编译器对换行符使用INTERNALLY的值(在我们的例子中为6),它会写一些与文件不同的东西:不是那个值,但无论你使用什么操作系统都认为是新行.在Windows上,这是两个字节(在Windows上为13和10,或0x0d 0x0a).另请注意,如果您不了解编译器对其他字符的内部表示的选择,那么这仍然是无意义的.
在这一点上请注意,很明显在文本模式下编写除编译器指定为文件的数据之外的任何内容都是一个坏主意:在我们的例子中,6可能正好恰好是您正在编写的值之一,在哪种情况下输出以我们绝对不想要的方式改变.
(联合国)幸运的是,大多数(所有?)编译器实际上对字符使用相同的内部表示:这种表示是US-ASCII,它是所有默认值的母亲.这就是你可以将一些"字符"写入程序中的文件,用任何随机编译器编译,然后用文本编辑器打开它的原因:它们都使用/理解US-ASCII,它恰好起作用.
好的,现在将此连接到您的示例:为什么在二进制模式和文本模式下编写"test"之间没有区别?因为"测试"中没有换行符,所以这就是原因!
当你"打开文件",然后"看到"字符时,它意味着什么?这意味着您用来检查该文件中的1和0序列的程序(因为硬盘上的所有内容都是1和0)决定将其解释为US-ASCII,这恰好是您的编译器决定编码的内容该字符串在其内存中.
加分点:编写一个程序,将文件中的1和0读入内存并打印每个BIT(有多个位组成一个字节,提取它们需要知道'按位'操作员技巧,谷歌!)为"用户1"或"0".请注意,"1"是CHARACTER 1,即您选择的字符集中的点,因此您的程序必须取一个位(数字1或0)并将其转换为表示字符1或0所需的位序列.终端模拟器使用的编码,你正在查看我的上帝的程序标准.好消息:你可以通过在任何地方假设US-ASCII来采取大量的捷径.该程序将向您展示您想要的内容:编译器用于在内部表示"测试"的1和0的序列.
这东西实在是令人望而生畏的新手,我知道,我花了很长的时间,甚至知道有被设置的字符和编码之间的差异,更何况这一切是如何工作.希望我没有让你失去动力,如果我这样做,只要记住你永远不会失去已有的知识,只能获得它(确定并非总是如此:P).苏格拉底认识到这一点并且他的智慧在2.4k年后无缝地应用于现代技术,这在生活中是正常的.
祝你好运,不要犹豫继续问.致其他读者:如果您发现错误,请随时改进此帖子.
Hraban
1那个告诉你"以二进制文件保存文件可能更小"的人,例如,可能严重误解了这些基本原理.除非他指的是在保存之前压缩数据,否则他只是使用一个令人困惑的词("二进制")来表示"压缩".
2 "告诉操作系统的东西"是通常所说的系统调用.