如何在Windows下用C++将UTF-8编码的字符串写入文件

6
我有一个字符串,其中可能包含Unicode字符,我想将其写入Windows上的文件。下面是我发布的一小段示例代码,我的问题在于当我在Windows上打开并读取值时,它们都被解释为UTF-16字符。
char* x = "Fool";
FILE* outFile = fopen( "Serialize.pef", "w+,ccs=UTF-8");
fwrite(x,strlen(x),1,outFile);
fclose(outFile);

char buffer[12];
buffer[11]=NULL;
outFile = fopen( "Serialize.pef", "r,ccs=UTF-8");
fread(buffer,1,12,outFile);
fclose(outFile);

如果我在Wordpad等软件中打开文件,字符也会被解释为UTF-16编码。我做错了什么吗?
2个回答

7

是的,当您指定文本文件应以UTF-8编码时,CRT会默认您将向文件写入Unicode文本。不这样做是没有意义的,您就不需要UTF-8。以下是正确的操作:

wchar_t* x = L"Fool";
FILE* outFile = fopen( "Serialize.txt", "w+,ccs=UTF-8");
fwrite(x, wcslen(x) * sizeof(wchar_t), 1, outFile);
fclose(outFile);

或者:

char* x = "Fool";
FILE* outFile = fopen( "Serialize.txt", "w+,ccs=UTF-8");
fwprintf(outFile, L"%hs", x);
fclose(outFile);

1
当然,你将会向文件中写入Unicode文本,但重点是CRT假定你将会写UTF-16 - dan04
1
@dan - 不,它假设您将编写wchar_t。Windows上的utf-16是实现细节。 - Hans Passant

1

如果您使用C++11标准,那么很容易(因为有很多额外的包含文件,如"utf8",可以永久解决这些问题)。

但是,如果您想要使用旧标准的多平台代码,则可以使用此方法使用流进行编写:

  1. 阅读有关流UTF转换器的文章
  2. 从上面的源代码中添加stxutif.h到您的项目中
  3. 以ANSI模式打开文件并在文件开头添加BOM,如下所示:

    std::ofstream fs;
    fs.open(filepath, std::ios::out|std::ios::binary);
    
    unsigned char smarker[3];
    smarker[0] = 0xEF;
    smarker[1] = 0xBB;
    smarker[2] = 0xBF;
    
    fs << smarker;
    fs.close();
    
  4. 然后以UTF格式打开文件并在其中编写内容:

    std::wofstream fs;
    fs.open(filepath, std::ios::out|std::ios::app);
    
    std::locale utf8_locale(std::locale(), new utf8cvt<false>);
    fs.imbue(utf8_locale); 
    
    fs << .. // 写入任何你想要的内容...
    

1
你如何使用C++11实现它? - aCuria
为什么需要BOM?我看到有人说在UTF-8中不需要甚至不建议使用BOM,因为它没有意义。在Windows中是否需要写BOM或者可以完全避免使用? - Germán Diago

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接