5

我的软件的一个要求是包含导出数据的文件的编码应为 UTF8。但是当我将数据写入文件时,编码始终是 ANSI。(我使用 Notepad++ 来检查这个。)

我目前正在做的是尝试通过读取文件手动转换文件,将其转换为 UTF8 并将文本写入新文件。

line是一个std::string
inputFile是一个std::ifstream
pOutputFile是一个FILE*

// ...

if( inputFile.is_open() )
{
    while( inputFile.good() )
    {
        getline(inputFile,line);

        //1
        DWORD dwCount = MultiByteToWideChar( CP_ACP, 0, line.c_str(), -1, NULL, 0 );
        wchar_t *pwcharText;
        pwcharText = new wchar_t[ dwCount];

        //2
        MultiByteToWideChar( CP_ACP, 0, line.c_str(), -1, pwcharText, dwCount );

        //3
        dwCount = WideCharToMultiByte( CP_UTF8, 0, pwcharText, -1, NULL, 0, NULL, NULL );
        char *pText;
        pText = new char[ dwCount ];

        //4
        WideCharToMultiByte( CP_UTF8, 0, pwcharText, -1, pText, dwCount, NULL, NULL );

        fprintf(pOutputFile,pText);
        fprintf(pOutputFile,"\n");

        delete[] pwcharText;
        delete[] pText;
    }
}

// ...

不幸的是,编码仍然是 ANSI。我搜索了一段时间的解决方案,但我总是通过 MultiByteToWideChar 和 WideCharToMultiByte 遇到解决方案。但是,这似乎不起作用。我在这里想念什么?

我也在这里寻找解决方案,但大多数 UTF8 问题都涉及 C# 和 php 的东西。

4

4 回答 4

3

在 VC++2010 的 Windows 上,使用本地化方面 std::codecvt_utf8_utf16 (即在 C++11 中)是可能的(据我所知,尚未在 GCC 中实现)。来自cppreference.com的示例代码包含读/写 UTF-8 文件所需的所有基本信息。

std::wstring wFromFile = _T("teststring");
std::wofstream fileOut("textOut.txt");
fileOut.imbue(std::locale(fileOut.getloc(), new std::codecvt_utf8_utf16<wchar_t>));
fileOut<<wFromFile;

它将 ANSI 编码文件设置为 UTF-8(在记事本中检查)。希望这是你需要的。

于 2012-07-25T09:50:57.873 回答
2

在 Windows 上,文件没有编码。每个应用程序都将根据自己的规则进行编码。您可以做的最好的事情是在文件的前面放置一个字节顺序标记并希望它被识别。

于 2012-07-26T01:16:06.093 回答
0

AFAIKfprintf()进行字符转换,因此不能保证将 UTF-8 编码数据传递给它实际上会将 UTF-8 写入文件。由于您已经自己转换了数据,fwrite()因此请改用原样编写 UTF-8 数据,例如:

DWORD dwCount = MultiByteToWideChar( CP_ACP, 0, line.c_str(), line.length(), NULL, 0 );  
if (dwCount == 0) continue;

std::vector<WCHAR> utf16Text(dwCount);  
MultiByteToWideChar( CP_ACP, 0, line.c_str(), line.length(), &utf16Text[0], dwCount );  

dwCount = WideCharToMultiByte( CP_UTF8, 0, &utf16Text[0], utf16Text.size(), NULL, 0, NULL, NULL );  
if (dwCount == 0) continue;

std::vector<CHAR> utf8Text(dwCount);  
WideCharToMultiByte( CP_UTF8, 0, &utf16Text[0], utf16Text.size(), &utf8Text[0], dwCount, NULL, NULL );  

fwrite(&utf8Text[0], sizeof(CHAR), dwCount, pOutputFile);  
fprintf(pOutputFile, "\n");  
于 2012-07-26T01:12:33.083 回答
0

该类型char没有任何编码的线索,它所能做的就是存储8位。因此,任何文本文件都只是一个字节序列,用户必须猜测底层编码。以 BOM 开头的文件表示 UTF 8,但不再建议使用 BOM。相反的类型wchar_t在 Windows 中总是被解释为 UTF 16。

假设你有一个 UTF 8 编码的文件,只有一行:“孔子说:微笑。孔子说:微笑!”。以下代码片段再次附加此文本,然后读取第一行并将其显示在 aMessageBoxWMessageBoxA中。请注意,它MessageBoxW显示了正确的文本,同时MessageBoxA显示了一些垃圾,因为它假定我的本地代码页 1252 用于char*字符串。

请注意,我使用了方便的CA2W类而不是MultiByteToWideChar. 请注意,该CP_Whatever参数是可选的,如果省略,则使用本地代码页。

#include <iostream>
#include <fstream>
#include <filesystem>
#include <atlbase.h>

int main(int argc, char** argv)
{
  std::fstream  afile;
  std::string line1A = u8"Confucius says: Smile. 孔子说:微笑! ";
  std::wstring line1W;

  afile.open("Test.txt", std::ios::out | std::ios::app);
  if (!afile.is_open())
        return 0;

  afile << "\n" << line1A;
  afile.close();

  afile.open("Test.txt", std::ios::in);
  std::getline(afile, line1A);
  line1W = CA2W(line1A.c_str(), CP_UTF8);
  MessageBoxW(nullptr, line1W.c_str(), L"Smile", 0);
  MessageBoxA(nullptr, line1A.c_str(), "Smile", 0);
  afile.close();

  return 0;
}
于 2020-06-16T10:29:45.830 回答