考虑以下两个函数,第一个函数使用 Windows API 函数
ReadFile()
和 CreateFileW()
,而第二个函数使用 fopen()
和 fgetws()
,从名为 data.txt
的文件中读取非英语文本.
第一个函数输出垃圾文本,而第二个函数输出文件中的文本,没有任何问题。
请注意,
fopen()
具有定义要使用的字符编码的ccs=UTF-8
,而read_file_2()
没有类似的东西。
DWORD read_file_2()
{
wchar_t wstr[512];
BOOL success = FALSE;
DWORD dwRead, total =0;
HANDLE handle = CreateFileW(L"data.txt",
GENERIC_READ,
0,
NULL,
3,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (handle == INVALID_HANDLE_VALUE)
return -1;
do
{
success = ReadFile(handle, wstr, 20, &dwRead, NULL);
total += dwRead;
} while(!success || dwRead == 0);
wstr[total] = L'\0';
wprintf(L"%ls\n",wstr);
return 0;
}
void read_file_1()
{
wchar_t converted[20];
FILE * ptr;view=msvc-170
ptr = fopen("data.txt", "rt+,ccs=UTF-8");
fgetws(converted, 20, ptr);
wprintf(L"%ls\n", converted);
fclose(ptr);
}
int main()
{
_setmode(fileno(stdin), _O_U8TEXT);
_setmode(fileno(stdout), _O_U8TEXT);
read_file_1();
read_file_2();
}
如何使用
ReadFile()
从文本文件中读取 wchar_t
字符串并将其输出到终端而不将其变成垃圾文本?
Шифрование.txt ال
퀠킨톸톄킀킾킲킰킽킸♥
data.txt
实际内容:
Шифрование.txt العربية.txt
您可以使用MultiByteToWideChar。
#define MALLOC( t, n ) ( ( t* )malloc( sizeof( t ) * n ) )
int total_wchars = MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
bytes, // lpMultiByteStr The bytes read using `ReadFile`/`read`.
total_bytes, // cbMultiByte No need for NUL.
NULL, // lpWideCharStr
0 // cchWideChar 0 = Get size incl NUL.
);
if ( total_wchars == 0 ) {
// Error. Use GetLastError() and such.
...
}
LPWSTR wchars = MALLOC( WCHAR, total_wchars );
MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
bytes, // lpMultiByteStr
total_bytes, // cbMultiByte
wchars, // lpWideCharStr
total_wchars // cchWideChar
);
注意,如果编译器有
wchar_t
,
WCHAR
是 wchar_t
LPWSTR
是 wchar_t *
LPCWSTR
是 const wchar_t *
问题在于
ReadFile()
不读取字符串,甚至字符。它读取字节。
由于它不读取字符串,因此它也不会像字符串那样“空终止”数据。 您需要确保它读取足够的字节,并且如果它是字符串,则以空终止缓冲区。
通过使用循环,您有一个良好的开始,但是您的循环会覆盖循环最后一次迭代中读取的内容,从而使您丢失数据。
您需要在循环中传递一个指向缓冲区末尾的指针。
正如我在评论中已经提到的,请确保循环正常工作(例如,如果出现错误,则不会进入无限循环)。