我有一个uint8_t
类型的变量,我想序列化并写入一个文件(这应该是非常便携的,至少对于Windows来说,这正是我的目标)。
尝试将其写入二进制形式的文件中,我遇到了这个工作片段:
uint8_t m_num = 3;
unsigned int s = (unsigned int)(m_num & 0xFF);
file.write((wchar_t*)&s, 1); // file = std::wofstream
首先,让我确保我理解这个代码片段的作用 - 它需要我的var(基本上是一个无符号字符,长度为1个字节),将其转换为unsigned int
(长度为4个字节,以及不太可移植),并使用& 0xFF
“提取”只有最不重要的字节。
现在,有两件事我不明白:
unsigned int
,为什么我不能简单地执行类似的事情
file.write((wchar_t*)&m_num, 1);
或reinterpret_cast<wchar_t *>(&m_num)
? (Ref)uint64_t
(长度为8个字节)? unsigned int
在这里可能还是不够。答案 0 :(得分:1)
uint8_t
为1个字节,与char
wchar_t
在Windows中为2个字节,在Linux中为4个字节。它还取决于字节顺序。如果担心可移植性,则应避免使用wchar_t
。
您可以使用std::ofstream
。 Windows有std::ofstream
的附加版本,它接受UTF16文件名。这样,您的代码与Windows UTF16文件名兼容,您仍然可以使用std::fstream
。例如
int i = 123;
std::ofstream file(L"filename_in_unicode.bin", std::ios::binary);
file.write((char*)&i, sizeof(i)); //sizeof(int) is 4
file.close();
...
std::ifstream fin(L"filename_in_unicode.bin", std::ios::binary);
fin.read((char*)&i, 4); // output: i = 123
这相对简单,因为它只存储整数。这将适用于不同的Windows系统,因为Windows始终是little-endian,int
大小始终为4.
但是有些系统是大端的,你必须单独处理它。
如果使用标准I / O,例如fout << 123456
,则整数将存储为文本“123456”。标准I / O是兼容的,但它需要更多的磁盘空间,并且可能会慢一些。
它的兼容性与性能。如果您有大量数据(几兆字节或更多),并且您将来可以处理兼容性问题,那么继续编写字节。否则,使用标准I / O会更容易。性能差异通常无法衡量。
答案 1 :(得分:0)
将unit8_t
值写入wofstream
是不可能的,因为wofstream
只能写宽字符而根本不处理二进制值。
如果您要做的是写一个代表0到255之间代码点的宽字符,那么您的代码是正确的。
如果要将二进制数据写入文件,则最近的等效数据为ofstream
,这将允许您写入字节。
回答你的问题:
wofstream::write
写入宽字符,而不是字节。如果重新解释m_num
的地址作为宽字符的地址,您将编写一个16位或32位(取决于平台)宽字符,其中第一个字节(即最不重要)或者最重要的,取决于平台)是m_num
的值,剩余的字节是在m_num
之后发生在内存中的任何事件。根据宽字符的字符编码,这甚至可能不是有效字符。即使有效,这在很大程度上是无稽之谈。 (如果wofstream::write
需要宽字符对齐而不是字节对齐的输入,或者m_num
后面紧跟不可读的内存,则还有其他可能的问题。
如果你使用wofstream
那么这就是一团糟,而我却没有解决它。如果切换到面向字节的ofstream
,那么您有两个选择。 1。如果您只是在同一系统上阅读该文件,file.write(&myint64value,sizeof(myint64value))
将起作用。写入64位值的字节的顺序将是未定义的,但是当您回读时将使用相同的顺序,因此这并不重要。 不要尝试做一些与wofstream
类似的事情,因为它很危险! 2. 分别提取myint64value
的8个字节中的每一个(向右移8位的倍数,然后取下6位),然后写入。这是完全可移植的,因为您可以控制写入字节的顺序。