将Unicode字符串写入文件

时间:2012-02-09 19:26:25

标签: c++ c unicode-string

我正在努力找一堂课阅读和阅读写文件。对于字符串,有两种方式:ANSI和Unicode。 ANSI函数很好,但我的Unicode函数有问题。

有点连线,我可以读取Unicode文件就好了,我的意思是,没有检查或跳过“0xFEFF”的东西。无论我在哪种语言(我试过英语,中文和日语),它都有效。有什么我应该知道的吗?

然后最大的问题就出现了:将Unicode字符串写入文件。首先我尝试简单的英语作为没有'\ n'字符的字母,它确实很好用。然后我按'\ n'进入并且事情开始出错了:输出插入了许多空格,因为“a b c d e f g \ n h i j k l m n \ n o p q r s t \ n u v w x y z”('\ n'可以工作但空间很大)并且文件再次是ANSI。不要问其他语言的字符,我甚至根本不能阅读它们。

所以这就是问题:如何正确地将Unicode字符串写入文件中以及如何操作?请不要提及“_wopen”功能,文件已经用“fopen”功能打开。

答案&建议会非常感激。

我正在使用Windows 7和visual studio。

编辑:它适用于具有以下代码的非英文字符,但仍然错误地使用'\ n'。

char* cStart = "\xff\xfe";

if (::ftell(m_pFile) == 0)
    ::fwrite(cStart, sizeof(wchar_t), 1, m_pFile);

但是如何运作?我的意思是我在阅读文件时没有看到它。

编辑:我的代码的一部分。

void File::ReadWText(wchar_t* pString, uint32 uLength)
{
    wchar_t cLetter = L'\0';
    uint32 uIndex = 0;

    do {
        cLetter = L'\0';
        ::fread(&cLetter, sizeof(wchar_t), 1, m_pFile);
        pString[uIndex] = cLetter;
    }while (cLetter != L'\0' && !::feof(m_pFile) && uIndex++ < uLength);
    pString[uIndex] = L'\0';
}

void File::WriteWText(wchar_t* pString, uint32 uLength)
{
    char* pStart = "\xff\xfe";

    if (::ftell(m_pFile) == 0)
        ::fwrite(pStart, sizeof(wchar_t), 1, m_pFile);

    m_uSize += sizeof(wchar_t) * ::fwrite(pString, sizeof(wchar_t), uLength, m_pFile);
}

void main()
{
    ::File* pFile = new File();
    wchar_t* pWString = L"abcdefg\nhijklmn\nopqrst\nuvwxyz";

    pFile->Open("TextW.txt", File::Output);
    // fopen("TextW.txt", "w");
    pFile->WriteWText(pWString, ::wcslen(pWString));
    pFile->Close();
}

输出文件的内容是:“abcdefg਍栀碗樀欀氀洀ഀഀഀഀ瘀瘀瘀礀礀礀”,文件用Unicode。

我不知道它是否是“L'\ n'”的正确表达式,我之前从未使用过Unicode。 谢谢你帮助我:)。

3 个答案:

答案 0 :(得分:3)

我刚注意到这个问题被标记为C和C ++:下面是讨论C ++中的情况。它完全忽略了使用,我不知道如何处理不同的编码。

在读取或写入文件时,您需要告诉系统文件的编码是什么,以便在读取时将文件中的字节转换为程序内部的字符,并在写入时将字符转换为字节。在许多情况下,完全忽略此转换,因为从字节到字符的转换是标识:字节可以解释为字符,反之亦然。当外部编码为ASCII时(在我的问题中,这被称为“ANSI”),这是真的。

假装UTF-8编码文件使用标识转换从字节转换为字符工作到某些扩展。 C ++中内部字符表示的原始愿景是每个字符有一个单位,例如一个charwchar_t。尽管Unicode已经制定了一系列可以很好地实现此目标的目标(例如,每个角色由一个单位表示,单位大小为16位),但他们觉得牺牲了所有原始目标,我们最终得到了一个系统其中一个字符(我认为它们实际上称为“代码点”,但我不是Unicode专家)可以由多个单词组成(例如,当使用组合字符时)。在任何情况下,只要个别单位在不注意字符的情况下不会发生变异,通常可以将UTF-8作为char(例如std::string)和UTF-的序列进行处理。 16作为wchar_t的序列(例如std::wstring)。但是,当读取不同于UTF-8(或UTF-8子集的ASCII)的内容时,您需要小心设置流,以便知道使用了哪种编码。

设置文件流以了解特定编码的标准方法是创建一个合适的std::locale,其中包含在外部字节和内部字符之间使用其特定的std::codecvt<...>方面转换编码。如何实际获得相应的std::locale取决于个人实施。默认转换是为了假装程序使用ASCII的扩展名,该扩展名涵盖char的所有值。在读写UTF-8时,这应该可行。

我不确定“编写Unicode字符串”是什么意思,但从它的外观来看,你正在编写std::wstring而没有设置编码。

答案 1 :(得分:2)

使用来源回答编辑过的问题:

void File::ReadWText(wchar_t* pString, uint32 uLength)是错误的。 如果uLength是数组的大小(wchar_t string[size]

while (.... && uIndex++ < uLength); 应为while (.... && (++uIndex)+1 < uLength);

否则pString[uIndex] = L'\0';可能会溢出!

新行问题.. L"abcdefg\nhijklmn\nopqrst\nuvwxyz"; windows使用\r\n作为新行。 L"abcdefg\r\nhijklmn\r\nopqrst\r\nuvwxyz";应该有用。

基于此msdn-thread unicode newline problem 和您的// fopen("TextW.txt", "w");,我相信您必须使用"wb"打开文件! 否则\n将自动扩展为\r\n,这会阻碍您的unicode编码..

答案 2 :(得分:1)

嗯这可能会有所帮助..

不要忘记在FF FE开头写BOM

因为您还没有发布任何代码.. 我相信你把新行写成ASCII '\n'(如你的问题中所写)

对于新行,您需要撰写0D 00 0A 00

或者如果您想使用'\n',则必须将其(short)'\n'