将数据保存到二进制文件中

| 我想将文件另存为二进制文件,因为我听说它可能比普通的文本文件小。 现在,我试图保存带有一些文本的二进制文件,但问题是该文件仅包含文本和结尾处的“ 0”。我希望在文件中仅看到零和一个。 任何解释或建议都将受到高度赞赏。 这是我的代码
#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;
}
    
已邀请:
在所有要使用的二进制计算机上,所有文件都只包含1和0。 保存文本时,将以给定编码保存该文本的二进制表示形式,该编码定义每个字母如何映射到位。 因此,对于文本而言,文本文件或二进制文件几乎无关紧要;通常,您听说过的节省空间对于其他数据类型也会发挥作用。 考虑一个浮点​​数,例如3.141592653589。如果另存为文本,则每位将占用一个字符(只需对它们进行计数),再加上句点即可。如果以二进制形式保存为“ 2”位的副本,则在典型的32位系统上将需要四个字符(四个字节,即32位)。调用存储的确切位数,例如:
FILE *my_file = fopen(\"pi.bin\", \"wb\");
float x = 3.1415;
fwrite(&x, sizeof x, 1, my_file);
CHAR_BIT * sizeof x
,请参见
<stdlib.h>
表示
CHAR_BIT
。     
您描述的问题是一连串的错误和误解(不幸的是,很常见)。让我尝试详细说明正在发生的事情,希望您能花些时间通读所有材料:虽然篇幅冗长,但是这些是程序员必须掌握的非常重要的基础知识。如果您还不完全了解所有内容,请不要感到绝望:试着玩弄它,一两个礼拜再回来,练习一下,看看会发生什么:) 字符编码和字符集的概念之间存在至关重要的区别。除非您真正了解这种差异,否则您将永远无法真正了解正在发生的事情。 Joel Spolsky(Stackoverflow的创始人之一,想到了这一点)不久前写了一篇文章,解释了这一区别:每个软件开发人员绝对绝对要完全了解Unicode和字符集(没有借口!)。在继续阅读本文档之前,甚至在继续编程之前,请先阅读该文档。老实说,请阅读并理解:标题并不夸张。您必须完全了解这些东西。 之后,让我们继续: 当C程序运行时,像其他任何存储位置一样,应该保存类型为“ char”的值的存储位置包含一个1和0的序列。变量的“类型”仅对编译器有意义,而对正在运行的程序仅意味着一和零,并且不知道更多。换句话说:在通常想到驻留在内存中某个位置的\“ letter \”(来自字符集的元素)的地方,实际上是一个位序列(来自字符编码的元素)。 每个编译器都可以随意使用它们希望代表内存中字符的任何编码。结果,它是自由选择的,它在内部代表我们选择的“换行符”。例如,假设我编写了一个编译器,我可以同意自己的看法,每次我要在内部存储\“ newline \”时,都将其存储为数字六(6),二进制文件仅为0x6(二进制文件仅为110)。 。 写入文件是通过同时告诉操作系统2四件事来完成的: 您要写入文件的事实(
fwrite()
) 数据从何处开始写入(
fwrite
的第一个参数) 您要写入多少数据(第二个和第三个参数相乘) 您要写入什么文件(最后一个参数) 请注意,这与该数据的“类型”无关:您的操作毫无头绪,也无关紧要。它对字符集一无所知,也不在乎:它只是看到从某处开始的一系列的1和0,然后将其复制到文件中。 实际上,以\“ binary \”模式打开文件是处理新手程序员所期望的文件的常规,直观方式:将您指定的内存位置一对一复制到文件中。如果您编写了一个存储位置,该位置用于保存编译器决定存储为\“ char \”类型的变量,则这些值将被一对一写入文件中。除非您知道编译器如何在内部存储值(它与换行符关联的值,带有字母'a',\'b \'等),否则这是毫无意义的。将此与乔尔(Joel)关于文本文件无用而又不知道其编码是什么的类似观点比较:同一件事。 在\“ text \”模式下打开文件几乎等于二进制模式,只差一个(只有一个):每次写入的值等于编译器对换行符使用INTERNALLY的值时(在本例中为6) ),它会写入与文件不同的内容:不是该值,而是您所使用的操作系统都认为是换行符。在Windows上,这是两个字节(在Windows上为13和10,或0x0d 0x0a)。再次注意,如果您不知道编译器选择其他字符的内部表示形式,则仍然不需要进行此操作。 请注意,在这一点上很明显,除了将编译器指定为字符的数据以文本模式写入文件之外,其他任何事情都是一个坏主意:在我们的例子中,您正在写入的值中可能恰好有一个6。在这种情况下,我们绝对不会故意改变输出。 幸运的是,大多数(所有?)编译器实际上都使用相同的内部字符表示形式:这种表示形式是US-ASCII,它是所有默认值的母体。这就是您可以在程序中的文件中写入一些“字符”,使用任何随机编译器进行编译,然后使用文本编辑器将其打开的原因:它们都使用/理解US-ASCII,并且它确实起作用。 好,现在将其连接到您的示例:为什么在二进制模式和文本模式下编写\“ test \”之间没有区别?因为\“ test \”中没有换行符,所以! 当您“打开文件”,然后“看到”字符时,这意味着什么?这意味着您用来检查该文件中1和0的顺序的程序(因为硬盘上的所有内容都是1和0)决定将其解释为US-ASCII,而这恰恰是编译器决定对其进行编码的该字符串作为它的内存。 奖励点:编写一个程序,将文件中的1和0读入内存并打印每个BIT(有多个位组成一个字节,要提取它们,您需要了解\'bitwise \'运算符,google !)作为用户的\“ 1 \”或\“ 0 \”。请注意,\“ 1 \”是字符1,即您选择的字符集中的点,因此您的程序必须取一个位(数字1或0)并将其转换为表示字符1或0所需的位序列在终端仿真器使用的编码中,您正在天哪,正在查看程序中的标准。好消息:假设到处都是US-ASCII,您可以采取许多捷径。该程序将向您显示所需内容:编译器用来在内部表示\“ test \”的1和0的序列。 对于新手来说,这些东西确实令人生畏,而且我知道花了很长时间才知道字符集和编码之间存在差异,更不用说所有这些如何工作了。希望我没有让您受挫,如果真的那样,请记住您永远不会失去已经拥有的知识,而只会获取它(可以并不总是正确的:P)。在生活中,陈述提出的问题多于回答的问题是正常的,苏格拉底知道这一点,而他的智慧无缝地适用于2.4k年后的现代技术。 祝你好运,不要犹豫,继续询问。致其他读者:如果发现错误,欢迎改善本文。 Hraban 1例如,告诉您“将文件保存为二进制文件的人可能较小”的人,可能会严重误解了这些基本原理。除非他指的是在保存数据之前先对数据进行压缩,否则在这种情况下,他只会对\“ compressed \”使用一个混淆的单词(\“ binary \”)。 2“告诉操作系统某些内容”是通常所说的系统调用。     
好吧,本机和二进制之间的区别是行尾的处理方式。 如果以二进制形式编写字符串,它将保留该字符串。 如果要使其更小,则必须以某种方式进行压缩(例如查找libz)。 较小的是:当要保存二进制数据(如字节数组)时,将其保存为二进制而不是将其放入字符串(以十六进制表示或base64)较小。我希望这有帮助。     
我认为您在这里有点困惑。 当您将ASCII字符串\“ Test \”写入文件时(即使是二进制模式),它仍然是ASCII字符串。编写二进制有意义的情况适用于char类型以外的其他类型(例如,整数数组)。     
尝试更换
FILE *handleWrite=fopen(\"test.bin\",\"wb\");
fwrite(temp, 1, 13, handleWrite);
FILE *handleWrite=fopen(\"test.bin\",\"w\");
fprintf(handleWrite, \"%s\", temp);
    
函数printf(\“%s \”,buffer);将缓冲区打印为零位字符串。 尝试使用: char temp [20] = \“ Test \\ n \\ rTest \”;     

要回复问题请先登录注册