写入 C:Program Files 中包含的文件夹的文件名

Write into a file names of folders containing in C:Program Files

本文关键字:包含 文件夹 文件名 Files Program 写入      更新时间:2023-10-16

我有这个任务:
1. 在当前目录中创建文件 subMape.dat
2.将存储在C:\Program Files folder
中的所有文件夹名称写入其中3.在屏幕上显示数据,这是用子Mape编写的.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时 - 它写入字符串,其中字符用空格分割。例如:文件夹名称"新建文件夹"(strlen = 10)将作为"N e w T o"(strlen = 10)写入文件。怎么办?

您的文本文件查看器或编辑器不够智能,无法确定您编写了 utf-16 编码的文本文件。 大多数文本编辑器需要帮助,将 BOM 写入文件:

    cout << "CreateFile() succeeded!n";
    wchar_t bom = L'xfeff';
    WriteFile(c, &bom, sizeof(bom), &bytesWritten, NULL);

您需要使用 WideCharToMultiByte() 之类的东西将 UNICODE 字符串转换为 ANSI(或 UTF8)。

您看到"空格"的原因是您用于列出文件的程序将其视为每个字符一个字节。在窗口中使用 Unicode 时,你会得到两个,第二个字节是"\0"。

您需要选择对文件中的数据进行编码的方式。

最简单的方法是使用 UTF-16LE ,因为这是 Windows 上的本机编码。然后,您只需要在文件的开头附加一个字节顺序标记。这种编码比UTF-8具有优势,因为由于观察到的零字节,它很容易从extended ASCII编码中推断出来。它的缺点是您需要BOM并且占用更多未压缩的磁盘空间。

UTF-8的优点是更紧凑。它也与纯ASCII完全兼容,并受到编程社区的青睐。

如果您不需要在任何上下文中使用extended ASCII,则应在 UTF-8 中对数据进行编码。如果这样做,请使用 UTF-16LE

那些认为通过UTF-8验证的文本是用UTF-8编码的人,如果整个文本都可用,这是正确的,但如果不是,则错误:

考虑按字母顺序排列的瑞典名字列表。如果我只检查列表的第一部分并且它是Latin-1ISO/IEC 8859-1),它也将通过UTF-8测试。

最后是"Örjansson",它分解成mojibake,事实上,"Ö"将是一个无效的UTF-8位序列。另一方面,由于使用UTF-16LE时使用的所有字母实际上都适合一个字节,我可以完全确信它不是UTF-8,也不是Latin-1

你应该知道,在Windows中,"本机"uncidode格式是UTF-16,由W样式函数(CreateFileW)使用。考虑到这一点,编写文件应该会给你一个有效的 UTF-16 文本,但编辑器可能没有认识到这一点,为了确保你的程序正常工作,请使用文本编辑器,您可以在其中手动指定编码(你知道它需要什么)以防它无法识别它,因为这个记事本++是一个不错的选择。

正如其他人已经提到的,编写 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)

在处理 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"rn", 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;
}