我有这个任务:
1.在当前目录中创建文件subMape.dat
2.将存储在C:\ Program Files文件夹中的所有文件夹名称写入其中
3.在屏幕数据上显示,用subMape.dat
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
WIN32_FIND_DATA findFileData;
DWORD bytesWritten = 0;
HANDLE f;
HANDLE c = CreateFileW(L"subMape.txt", GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
//TCHAR lpBuffer[32];
DWORD nNumberOfBytesToRead = 32;
//DWORD lpNumberOfBytesRead;
DWORD lengthSum = 0;
if (c) {
cout << "CreateFile() succeeded!\n";
if(f = FindFirstFile(L"C:\\Program Files\\*", &findFileData)){
if(f != INVALID_HANDLE_VALUE) {
while (FindNextFile(f, &findFileData)){
lengthSum += bytesWritten;
WriteFile(c, findFileData.cFileName, (DWORD)wcslen(findFileData.cFileName), &bytesWritten, NULL);
}
}
FindClose(f);
}
else {
cout << "FindFirstFile() failed :(\n";
}
}
else {
cout << "CreateFile() failed :(\n";
}
cout << lengthSum << endl;
//SetFilePointer(c, lengthSum, NULL, FILE_BEGIN);
//ReadFile(c, lpBuffer, lengthSum, &lpNumberOfBytesRead, NULL);
//wprintf(lpBuffer);
CloseHandle(c);
return 0;
}
我正在使用UNICODE,当它写入findFileData.cFileName时 - 它会写入字符串,其中字符用空格分割。例如:文件夹名称“New Folder”(strlen = 10)将作为“N e w T o”(strlen = 10)写入文件。怎么办?
答案 0 :(得分:2)
您的文本文件查看器或编辑器不够智能,无法确定您编写的是utf-16编码的文本文件。大多数文本编辑都需要帮助,将the BOM写入文件:
cout << "CreateFile() succeeded!\n";
wchar_t bom = L'\xfeff';
WriteFile(c, &bom, sizeof(bom), &bytesWritten, NULL);
答案 1 :(得分:1)
您需要使用WideCharToMultiByte()
之类的东西将UNICODE字符串转换为ANSI(或UTF8)。
答案 2 :(得分:1)
您看到“空格”的原因是您用来列出文件的程序将其视为每个字符一个字节。在Windows中使用Unicode时,您将获得两个,第二个字节是'\ 0'。
您需要选择如何对文件中的数据进行编码。
最简单的方法是使用UTF-16LE
,因为这是Windows上的本机编码。然后,您只需要将一个字节顺序标记添加到文件的开头。此编码优于UTF-8
,因为由于观察到的零字节,很容易从extended ASCII
编码中去除序列。它的缺点是你需要BOM
并且它会占用更多未压缩的磁盘空间。
UTF-8
具有更紧凑的优势。它还与纯ASCII
完全兼容,并受到编程社区的青睐。
如果您不需要在任何上下文中使用extended ASCII
,则应在UTF-8
中对数据进行编码。如果您这样做,请使用UTF-16LE
。
那些认为通过UTF-8
验证的文本在UTF-8
编码的文本是正确的,如果整个文本可用,但如果不是,则是错误的:
考虑按字母顺序排列的瑞典名单。如果我只检查列表的第一部分,它是Latin-1
(ISO/IEC 8859-1
),它也会通过UTF-8
测试。
然后最终“Örjansson”分解为mojibake实际上'Ö'将是无效的UTF-8
位序列。另一方面,由于使用UTF-16LE
时所使用的所有字母实际上都适合一个字节,因此我完全可以确信它不是UTF-8
,也不是Latin-1
。
答案 3 :(得分:0)
你应该知道在windows中,“native”uncidode格式是UTF-16,由W风格的函数(CreateFileW)使用。考虑到这一点,编写文件应该为您提供有效的UTF-16文本,但编辑可能无法识别,以确保您的程序使用文本编辑器,您可以手动指定编码(您知道它需要是什么) )如果它不能识别它,对于这个Notepad ++是一个不错的选择。
正如其他人已经提到的那样,编写BOM对文本编辑器非常有用,并确保您的文件能够正确读取。
您可以使用WideCharToMultiByte将UTF-16转换为UTF-8,以获得更高的兼容性。
为什么你直接使用CreateFileW而不是FindFirstFileW你是否在项目中定义了UNICODE?如果您这样做,编译器会将CreateFile解析为CreateFileW。
此外,这里
WriteFile(c, findFileData.cFileName, (DWORD)wcslen(findFileData.cFileName), &bytesWritten, NULL);
wcslen给出的字符数与非ANSI文本的数据大小不同,它应该类似
wcslen(findFileData.cFileName)*sizeof(wchar_t)
答案 4 :(得分:0)
处理UTF-16文件时,编写一个字节顺序标记并写入长度为字节而非字符的数据非常重要。 wcslen
以字符形式返回字符串长度,但使用宽字符串时字符为两个字节。这是一个固定的版本。它显式调用Win32 API的宽版本,因此无论是否定义了UNICODE / _UNICODE都可以使用。
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
WIN32_FIND_DATAW findFileData; // Use the wide version explicitly
DWORD bytesWritten = 0;
HANDLE f;
HANDLE c = CreateFileW(L"subMape.txt", GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD lengthSum = 0;
if(c != INVALID_HANDLE_VALUE) {
cout << "CreateFile() succeeded!\n";
// Write A byte-order mark...make sure length is bytes not characters.
WriteFile(c, L"\uFEFF", sizeof(wchar_t), &bytesWritten, NULL);
lengthSum += bytesWritten;
f = FindFirstFileW(L"C:\\Program Files\\*", &findFileData);
if(f != INVALID_HANDLE_VALUE) {
while(FindNextFileW(f, &findFileData)) {
// Write filename...length in bytes
WriteFile(c, findFileData.cFileName, (DWORD)wcslen(findFileData.cFileName) * sizeof(wchar_t), &bytesWritten, NULL);
// Add the length *after* writing...
lengthSum += bytesWritten;
// Add a carriage return/line feed to make Notepad happy.
WriteFile(c, L"\r\n", sizeof(wchar_t) * 2, &bytesWritten, NULL);
lengthSum += bytesWritten;
}
FindClose(f); // This should be inside findFirstFile succeeded block.
}
else {
cout << "FindFirstFile() failed :(\n";
}
// these should be inside CreateFile succeeded block.
CloseHandle(c);
cout << lengthSum << endl;
}
else {
cout << "CreateFile() failed :(\n";
}
return 0;
}