【问题标题】:Unable to read UNICODE text file in C无法读取 C 中的 UNICODE 文本文件
【发布时间】:2017-02-22 16:45:07
【问题描述】:

(我查看了以前的帖子并尝试了他们的建议,但无济于事。)

我正在尝试读取仅包含日文字符的文件。这是该文件的样子:

わたし わ  エドワド オ'ハゲンです。

当我尝试读取它时,控制台中没有任何输出显示,而在调试时,读取缓冲区只是垃圾。这是我用来读取文件的函数:

wchar_t* ReadTextFileW(wchar_t* filePath, size_t numBytesToRead, size_t maxBufferSize, const wchar_t* mode, int seekOffset, int seekOrigin)
{
    size_t numItems = 0;
    size_t bufferSize = 0;
    wchar_t* buffer = NULL;
    FILE* file = NULL;

    //Ensure the filePath does NOT lead to a device.
    if (IsPathADevice(filePath) == false)
    {
        //0 indicates to read as much as possible (the max specified).
        if (numBytesToRead == 0)
        {
            numBytesToRead = maxBufferSize;
        }

        if (filePath != NULL && mode != NULL)
        {
            //Ensure there are no errors in opening the file.
            if (_wfopen_s(&file, filePath, mode) == 0)
            {
                //Set the cursor location (back to the beginning of the file by default).
                if (fseek(file, seekOffset, seekOrigin) != 0)
                {
                    //Error: Could not change file cursor position.
                    fclose(file);
                    return NULL;
                }

                //Calculate the size of the buffer in bytes.
                bufferSize = numBytesToRead * sizeof(wchar_t);

                //Create the buffer to store file data in.
                buffer = (wchar_t*)_aligned_malloc(bufferSize, BYTE_ALIGNMENT);

                //Ensure the buffer was allocated.
                if (buffer == NULL)
                {
                    //Error: Buffer could not be allocated.
                    fclose(file);
                    return NULL;
                }

                //Clear any garbage data in the buffer.
                memset(buffer, 0, bufferSize);

                //Read the data from the file.
                numItems = fread_s(buffer, bufferSize, sizeof(wchar_t), numBytesToRead, file);

                //Check for read errors.
                if (numItems <= 0)
                {
                    //Error: File could not be read.
                    fclose(file);
                    _aligned_free(buffer);
                    return NULL;
                }

                //Ensure the file is closed without errors.
                if (fclose(file) != 0)
                {
                    //Error: File did not close properly.
                    _aligned_free(buffer);
                    return NULL;
                }

            }
        }
    }

    return buffer;
}

要调用此函数,我正在执行以下操作。也许我没有正确使用 setlocale() 但从我读到的内容看来我是。只是重申一下,我遇到的问题是垃圾似乎被读入并且控制台中没有显示任何内容:

    setlocale(LC_ALL, "jp");
    wchar_t* retVal = ReadTextFileW(L"C:\\jap.txt");
    printf("%S\n", retVal);
    _aligned_free(retVal);

我还在 .cpp 的顶部定义了以下内容

#define UNICODE
#define _UNICODE

已解决:

如 ryyker 所述,要解决此问题,您需要知道用于创建原始文件的编码。在记事本和记事本++ 中有一个用于编码的下拉菜单。默认情况下(也是最常用的)是 UTF-8。

知道编码后,您可以将_wfopen_s() 的读取模式更改为以下。

wchar_t* retVal = ReadWide::ReadTextFileW(L"C:\\jap.txt", 0, 1024, L"r, ccs=UTF-8");
MessageBoxW(NULL, retVal, NULL, 0);
_aligned_free(retVal);

您必须使用消息框来打印外来字符。

【问题讨论】:

  • 您确定文件的encoding 吗?该链接讨论了多字节等。人。
  • @ryyker 我不明白你的问题。
  • 我只是建议您尝试解码包含多字节字符的文件,但尚未确定它们由什么编码组成。看看我在上一条评论中留下的链接。
  • 你能拿出你的“已解决”部分作为正确答案吗?
  • 我看到您找到了解决方案!我刚刚在@Mr.C64 的回答下查看了 cmets 的广泛成绩单。看来 Mr.C64 确实是回答您问题的人。尽管我非常感谢您的 accepted answer 点击,但我认为它应该应用于其他地方。 :)

标签: c windows file file-io unicode


【解决方案1】:

这是一个 excerpt discussing content on encoding for Japanese language,使用 Notepad++ 创建(在 cmets 中表示被 OP 使用)

双字节编码,也称为双字节字符 设置(DBCS)

其中一些是预先存在的 Unicode,旨在对字符进行编码 包含大量角色的场景,主要出现在远东地区 具有表意文字或音节文字的语言:

The 2 Bytes Universal Character Set : UCS-2 Big Endian and UCS-2 Little Endian
The Japanese Code Page : Shift-JIS ( Windows-932 )
The Chinese Code Pages : Simplified Chinese GB2312 ( Windows-936 ),
Traditionnal Chinese Big5 ( Windows-950 )
The Korean Code Pages : Windows 949, EUC-KR

看来 Shift-JIS 可能是您尝试读取的编码。 来自here

Shift JIS(Shift 日本工业标准,亦称 SJIS,MIME 名称 Shift_JIS) 是日语的字符编码, 最初由一家名为 ASCII Corporation 的日本公司开发 与微软...

通常,您需要确定用于在文件中创建多字节字符的编码,然后才能通过 C 或任何其他语言的函数正确读取这些字符。 This link may help.

【讨论】:

  • 谢谢,这对理解编码很有帮助。在记事本++ 的顶部,您可以设置一个编码选项。我正在使用 UTF-8。
  • 好吧,我在帖子中所做的假设是不正确的,但更重要的是,您现在知道您的编码是什么,并且应该能够对您的代码进行调整以适应。
  • 我尝试将 _wfopen 的读取模式更改为 "r, ccs=UTF-8" 并且缓冲区正确,但我的 printf 没有将任何内容打印到控制台
  • 我现在没有时间进行故障排除,但我可能稍后会。我的方法是简单地从您的代码库开始(在后期)并使用函数参数中的离散选项集。 (我什至可以上传 Notepad++ 进行测试:))如果我发现任何有用的东西,我会编辑我的答案。
【解决方案2】:

您读取文件内容并将其复制到分配的内存缓冲区中。

但重点是:文件中使用什么encoding来存储日文文本?

例如,如果文本以 UTF-8 编码,您应该从 UTF-8 转换为 UTF-16(例如使用 MultiByteToWideChar Win32 API),因为您似乎在内存中有一个 wchar_t 缓冲区。

如果您使用的是最新版本的 Visual Studio,您还可以将 specify some encoding information in the mode string 传递给 _wfopen_s(使用 ccs 标志)。

编辑由于您使用 printf 打印读取缓冲区的内容,因此请确保缓冲区是 NUL 终止的。

【讨论】:

  • wchar_t 没有标准编码。但是,现代系统使用 UTF-32。 OP 没有写他使用 Windows。
  • @Olaf 你说得对,wchar_t 没有被标准明确定义,但在 Windows 上它用于 UTF-16,而 OP 的代码似乎是特定于 Windows 的。
  • 我如何知道我的日文文本文件的编码是什么?我只是将日文文本写入其中并将其保存为 .txt。如果文件是 UTF-8,那我会将语言环境设置为 UTF-8 吗?我不明白答案。
  • @Katianie 也许控制台无法显示日文字符?尝试使用 MessageBox 而不是 printf,例如MessageBox(NULL, text, L"Test", MB_OK);.
  • @Mr.C64 - 我刚刚注意到同样的事情。我对您的答案(这是一个很好的答案,我在发布我的答案之前点击了)仍然有效。
猜你喜欢
  • 1970-01-01
  • 2020-07-24
  • 1970-01-01
  • 2013-04-01
  • 2018-06-22
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多