c++ - 在二进制文件中读取和写入字符串c++

标签 c++ visual-studio-2010 unicode-string wstring

我正在尝试开发一个小型 Windows 应用程序以提高我在 MFC 框架之外的 C++ 技能并帮助我学习外语。
我想制作一个小型的、个人的和易于移植和使用的字典,虽然我在开发 GUI 方面没有问题,但我在保存和恢复数据方面遇到了真正的痛苦。

我的想法是写下一个结构如下的二进制文件关注:

int (representing the number of words)
int (representing the string length + \0)
sequence of characters zero-terminated.
现在,我正在学习俄语,我的主要语言是意大利语,所以我不能使用普通的旧 std::string 来记下单词,此外,谢谢微软,我正在使用 VS2010 和 bads随之而来的。我正在向您展示我写下 int 和 wstring 的例程:
//Writing int
void CDizionario::ScriviInt( int nInt, wofstream& file ) const
{
    file.write( reinterpret_cast < const wchar_t * > ( &nInt ), sizeof( nInt ) );
    file.flush();
}
// Writing string
void CDizionario::ScriviWString( int nLStringa, const wstring* pStrStringa, wofstream& file ) const
{
    wchar_t cTerminatore;
    string strStringa;
    file.write( pStrStringa->c_str(), nLStringa );
    file.flush();
    cTerminatore = L'\0';
    file.write( &cTerminatore, sizeof( wchar_t ) );
    file.flush();
}
// Reading int
void CDizionario::LeggiInt( int *pInt, wifstream& file )
{
    file.read( reinterpret_cast < wchar_t * >( pInt ), sizeof( int ) );
}
// Reading wstring
void CDizionario::LeggiWString( int nLStringa, wstring& strStringa, wifstream& file )
{
    wchar_t *pBuf;
    streamsize byteDaLeggere;
    byteDaLeggere = nLStringa;
    pBuf = new wchar_t[(unsigned int)( byteDaLeggere * sizeof( wchar_t ) )];
    file.read( pBuf, byteDaLeggere * sizeof( wchar_t ) );
    strStringa.append( pBuf );
    delete [] pBuf;
}
// Constructor
CDizionario::CDizionario( void )
{
    m_pLoc = new locale( locale::classic(), new codecvt_utf8_utf16 );
}
// Somewhere in my code before calling LeggiInt/ScriviInt/LeggiWString/ScriviWString:
// ...
file.imbue( *m_pLoc );

嗯,我的第一个测试是:ciao - привет,结果:

01 00 ee bc 90 22 05 00 ee bc 90 22 63 69 61 6f
00 ec b3 8c 07 00 ee bc 90 22 d0 bf d1 80 d0 b8
d0 b2 d0 b5 d1 82 00 ec b3 8c
数字读取正确,当我写下字符串时出现问题:我希望 ciao (63 69 61 6f 00 ec b3 8c) 以 10 个字节(wchar_t 大小)而不是 5 个字节写入,就像俄语翻译(d0 bf d1 80 d0 b8 d0 b2 d0 b5 d1 82 00 ec b3 8c)一样。
显然我遗漏了一些东西,但我不知道它是什么。你们能帮帮我吗?另外,如果您知道解决问题的更好方法,我很乐意接受。

编辑:解决方案

按照@JamesKanze 提出的两种方法中的第一种,我决定牺牲一些可移植性并让系统完成我的作业:

void CDizionario::LeggiInt( int *pInt, ifstream& file )
{
    file.read( reinterpret_cast( pInt ), sizeof( int ) );
}<p></p>

<p>void CDizionario::LeggiWString( int nLStringa, wstring& strStringa, ifstream& file )
{
    char *pBuf;
    streamsize byteDaLeggere;
    wstring_convert> converter;
    byteDaLeggere = nLStringa;
    pBuf = new char[byteDaLeggere];
    file.read( pBuf, byteDaLeggere );
    strStringa = converter.from_bytes( pBuf );
    delete [] pBuf;
}</p>

<p>void CDizionario::ScriviInt( int nInt, ofstream& file ) const
{
    file.write( reinterpret_cast( &nInt ), sizeof( nInt ) );
    file.flush();
}
void CDizionario::ScriviWString( const wstring* pStrStringa, ofstream& file ) const
{
    char cTerminatore;
    string strStringa;
    wstring_convert> converter;
    strStringa = converter.to_bytes( pStrStringa->c_str() );
    ScriviInt( strStringa.length() + 1, file );
    file.write( strStringa.c_str(), strStringa.length() );
    file.flush();
    cTerminatore = '\0';
    file.write( &cTerminatore, sizeof( char ) );
    file.flush();
}</p>

最佳答案

您没有充分指定二进制文件的格式。 你如何表示 int (多少字节,大端或 little-endian),也不是编码和格式 人物。经典的网络表示是 大端四字节(无符号)整数和 UTF-8。自从 这是你为自己做的事情,你可以(和 可能应该)简化,使用 little-endian 作为整数,并且 UTF-16LE;这些格式对应于下的内部格式 window 。 (请注意,这样的代码将不可移植,甚至 到同一架构上的 Apple 或 Linux,并且有 数据在新系统上变得不可读的可能性很小。) 这基本上就是您似乎正在尝试的,但是......

您正在尝试编写原始二进制文件。唯一的标准方法 这将是使用 std::ofstream (和 std::ifstream 到 读取),文件以二进制模式打开 "C"语言环境。对于其他任何事情,将会(或可能)有一些 std::filebuf 中的某种代码翻译和映射. 鉴于此(以及这种写入数据的方式不是 可移植到任何其他系统),您可能只想使用 系统级功能:CreateFile打开,WriteFileReadFile写和读,CloseHandle关闭。 (看 http://msdn.microsoft.com/en-us/library/windows/desktop/aa364232%28v=vs.85%29.aspx ).

另一方面,如果你想要便携,我会推荐 使用数据的标准网络格式。格式化成 一个缓冲区( std::vector<char> ),然后写下来;在另一个 结束,读入缓冲区,并解析它。读写 整数(实际上是无符号整数)的例程可能是 类似于:

void
writeUnsignedInt( std::vector<char>& buffer, unsigned int i )
{
    buffer.push_back( (i >> 24) & oxFF );
    buffer.push_back( (i >> 16) & oxFF );
    buffer.push_back( (i >>  8) & oxFF );
    buffer.push_back( (i      ) & oxFF );
}

unsigned int
readUnsignedInt( 
    std::vector<char>::const_iterator& current,
    std::vector<char>::const_iterator end )
{
    unsigned int retval = 0;
    int shift = 32;
    while ( shift != 0 && current != end ) {
        shift -= 8;
        retval |= static_cast<unsigned char>( *current ) << shift;
        ++ current;
    }
    if ( shift != 0 ) {
        throw std::runtime_error( "Unexpected end of file" );
    }
    return retval;
}

对于字符,您必须将 std::wstring 转换为 UTF-8 中的 std::string,使用许多转换例程之一 在网络上可用。 (问题在于编码 std::wstring , 甚至不是 wchar_t 的大小, 不是 标准化。在我熟悉的系统中,Windows 和 AIX 使用 UTF-16,其他大多数使用 UTF-32;在这两种情况下都带有字节 顺序取决于平台。这使得可移植代码有点 更难。)

在全局范围内,我发现直接在 UTF-8,使用 char .这不适用于 Windows 界面,但是。

最后,您不需要结尾的 '\0'如果你输出 长度。

关于c++ - 在二进制文件中读取和写入字符串c++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23824776/

相关文章:

c++ - UTF-8解码库

visual-studio-2010 - 构建自动部署到 Azure 的工具?

c# - VS 2010 Visual C# - 在同一解决方案中引用其他项目

C# 部署 : install additional file in the installation directory

swift - 将字符串中的 unicode 符号\uXXXX 转换为 Swift 中的字符

python - 需要帮助找出此 UnicodeDecodeError 的解决方案

c# - 想做一个 php get_include_files() 增强

c++ - 32 位和 64 位 Windows 上 GSL 库的差异导致 R 包错误?

C++ 双下标重载 : cannot convert from 'type' to 'type &'

EOF : behavior change; work-around? 上的 C++ istream tellg()/fail()