4

我正在尝试编写一个读写文件的类。对于字符串,有两种方法:ANSI 和 Unicode。ANSI 函数没问题,但我的 Unicode 函数有问题。

有点连线,我可以直接读取 Unicode 文件,而无需检查或跳过“0xFEFF”内容。无论我使用哪种语言(我尝试过英语、中文和日语),它都可以正常工作。有什么我应该知道的吗?

然后最大的问题就跳出来了:将Unicode字符串写入文件。首先我尝试了简单的英语作为没有'\n'字符的字母,它确实很好用。然后我将 '\n' 推入并开始出现问题:输出插入了许多空格,如“abcdefg \nhijklmn \nopqrst \nuvwxyz”('\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਍栀碗樀欀氀洀渀ഀopqrst਍甀淤眀砀礀稀”,文件为Unicode。

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

4

3 回答 3

3

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

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

假装 UTF-8 编码文件使用身份转换将字节转换为字符在某些方面起作用。C++ 中内部字符表示的最初设想是每个字符有一个单元,例如 achar或 a wchar_t。尽管 Unicode 已经制定了一套可以很好地解决这个问题的目标(例如,每个字符由一个单元表示,单元大小为 16 位),但他们觉得牺牲了所有最初的目标,我们最终得到了一个系统其中一个字符(嗯,我认为它们实际上被称为“代码点”,但我不是 Unicode 专家)可以由多个单词组成(例如,使用组合字符时)。无论如何,只要个别单位没有在不注意性格的情况下发生变异,char(例如 as )和 UTF-16 作为(例如 as )std::string的序列。但是,当读取不同于 UTF-8(或 UTF-8 子集的 ASCII)的内容时,您需要小心设置流,使其知道使用哪种编码。wchar_tstd::wstring

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

我不确定您所说的“编写 Unicode 字符串”是什么意思,但从外观上看,您正在编写一个std::wstring没有设置编码的代码。

于 2012-02-09T20:09:28.450 回答
2

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

void File::ReadWText(wchar_t* pString, uint32 uLength)是越野车。IfuLength是数组的大小 ( 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 换行问题 和你的// fopen("TextW.txt", "w");,我相信你必须打开你的文件"wb"!否则\n会自动扩展为\r\n会搞砸你的 unicode-encoding..

于 2012-02-09T21:03:32.970 回答
1

嗯,这可能会有所帮助..

别忘了在开头写BOMFF FE

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

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

或者如果你想使用'\n',你必须施放它(short)'\n'

于 2012-02-09T20:14:07.403 回答