假设我有一个字符数组,char a[8]包含10101010。如果我将这些数据存储在.txt文件中,则该文件的大小为8字节。现在我在问,我如何将这些数据转换为二进制格式,并将其保存在一个文件中作为8位(而不是8字节),以便文件大小只有1字节。
此外,一旦我将这8个字节转换为一个字节,我应该用哪种文件格式保存输出。txt或.dat或.bin?
我正在研究文本文件的霍夫曼编码。我已经将文本格式转换为二进制格式,即0和1,但当我将输出数据存储在文件中时,每个数字(1或0)都使用一个字节而不是一位。我想要一个解决方案,这样每个数字只需要一点点。
char buf[100];
void build_code(node n, char *s, int len)
{
static char *out = buf;
if (n->c) {
s[len] = 0;
strcpy(out, s);
code[n->c] = out;
out += len + 1;
return;
}
s[len] = '0'; build_code(n->left, s, len + 1);
s[len] = '1'; build_code(n->right, s, len + 1);
}
这就是我如何在霍夫曼树的帮助下建立我的代码树。和
void encode(const char *s, char *out)
{
while (*s)
{
strcpy(out, code[*s]);
out += strlen(code[*s++]);
}
}
这就是我如何编码以获得最终输出。
不完全确定如何得到表示值的二进制表示的字符串,但是,您可以使用std::strtoul等标准函数从字符串(以任意基数)中获取整数值。
该函数提供一个无符号长值,因为您知道您的值在0-255范围内,所以可以将其存储在无符号字符中:
无符号字符v=(无符号字符)(std::strtoul(binary_string_value.c_str(),0,2)&0xff);
将其写入磁盘,您可以使用流写入
我应该用哪种文件格式保存输出。txt或.dat或.bin?
请记住,扩展名(.txt、.dat或.bin)并没有真正强制要求格式(即内容的结构)。扩展名是常用的惯例,用于表示您正在使用一些众所周知的格式(在某些操作系统/环境中,它驱动哪个程序最能处理该文件的配置)。由于这是您的文件,因此由您定义实际格式。。。并用你最喜欢的任何扩展名(甚至没有扩展名)命名文件(或者换句话说,任何最能代表你的内容的扩展名),只要它对你和那些将使用你的文件的人有意义。
编辑:其他详细信息
假设我们有一个一定长度的缓冲区,用于存储字符串"0"one_answers"1"
int codeSize; // size of the code buffer
char *code; // code array/pointer
std::ofstream file; // File stream where we're writing to.
unsigned char *byteArray=new unsigned char[codeSize/8+(codeSize%8+=0)?1:0]
int bytes=0;
for(int i=8;i<codeSize;i+=8) {
std::string binstring(code[i-8],8); // create a temp string from the slice of the code
byteArray[bytes++]=(unsigned char)(std::strtoul(binstring.c_str(),0,2) & 0xff);
}
if(i>codeSize) {
// At this point, if there's a number of bits not multiple of 8,
// there are some bits that have not
// been writter. Not sure how you would like to handle it.
// One option is to assume that bits with 0 up to
// the next multiple of 8... but it all depends on what you're representing.
}
file.write(byteArray,bytes);
将表示位表示的输入8个字符转换为一个字节的函数。
char BitsToByte( const char in[8] )
{
char ret = 0;
for( int i=0, pow=128;
i<8;
++i, pow/=2;
)
if( in[i] == '1' ) ret += pow;
return ret;
}
我们对传递给函数的数组(由于明显的原因,大小为8)进行迭代,并根据其内容增加返回值(数组中的第一个元素表示最旧的位)。CCD_ 1被设置为128,因为CCD_。
您可以很容易地将它们转换为一个字节,如下所示:
byte x = (s[3] - '0') + ((s[2] - '0') << 1) + ((s[1] - '0') << 2) + ((s[0] - '0') << 3);
在我的例子中,我只移动了一个半字节,即4位。您可以展开此示例来移动整个字节。这个解决方案将比循环更快。
单向:
/** Converts 8 bytes to 8 bits **/
unsigned char BinStrToNum(const char a[8])
{
return( ('1' == a[0]) ? 128 : 0
+ ('1' == a[1]) ? 64 : 0
+ ('1' == a[2]) ? 32 : 0
+ ('1' == a[3]) ? 16 : 0
+ ('1' == a[4]) ? 8 : 0
+ ('1' == a[5]) ? 4 : 0
+ ('1' == a[6]) ? 2 : 0
+ ('1' == a[7]) ? 1 : 0);
);
};
将其保存为您提到的任何格式;或者自己发明!
int main()
{
rCode=0;
char *a = "10101010";
unsigned char byte;
FILE *fp=NULL;
fp=fopen("data.xyz", "wb");
if(NULL==fp)
{
rCode=errno;
fprintf(stderr, "fopen() failed. errno:%dn", errno);
goto CLEANUP;
}
byte=BinStrToNum(a);
fwrite(&byte, 1, 1, fp);
CLEANUP:
if(fp)
fclose(fp);
return(rCode);
}