1

私はこのタスクを持っています:
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 ew To" (strlen = 10) として書き込まれます。どうする?

4

5 に答える 5

2

テキスト ファイル ビューアーまたはエディターは、utf-16 でエンコードされたテキスト ファイルを記述したことを認識できるほど賢くありません。ほとんどのテキスト エディターはヘルプを必要とします。BOMをファイルに書き込みます。

    cout << "CreateFile() succeeded!\n";
    wchar_t bom = L'\xfeff';
    WriteFile(c, &bom, sizeof(bom), &bytesWritten, NULL);
于 2013-10-26T09:59:26.063 に答える
1

WideCharToMultiByte()UNICODE 文字列を ANSI (または UTF8) に変換するようなものを使用する必要があります。

于 2013-10-26T09:39:44.137 に答える
1

「スペース」が表示される理由は、ファイルを一覧表示するために使用しているプログラムが 1 文字あたり 1 バイトとして扱うためです。Windows で Unicode を使用すると、2 つ取得され、2 番目のバイトは '\0' になります。

ファイル内のデータをエンコードする方法を選択する必要があります。

UTF-16LEこれは Windows のネイティブ エンコーディングであるため、最も簡単な方法は を使用することです。次に、ファイルの先頭にバイト オーダー マーカーを追加するだけです。このエンコーディングには、 0 バイトが観察されるため、エンコーディングUTF-8と簡単に区別できるという利点があります。extended ASCIIその欠点は、圧縮が必要であり、BOM圧縮されていない場合により多くのディスク領域を占有することです。

UTF-8コンパクトになるメリットがあります。また、pureASCIIと完全に互換性があり、プログラミング コミュニティに好まれています。

extended ASCIIどのコンテキストでも使用する必要がない場合は、データを でエンコードする必要がありますUTF-8。その場合は、 を使用しますUTF-16LE

UTF-8検証に合格したテキストがエンコードされていると主張する人は、テキストUTF-8全体が利用できる場合は正しいですが、そうでない場合は間違っています。

スウェーデンの名前のアルファベット順のリストを考えてみましょう。リストの最初の部分だけをチェックし、それがLatin-1( ISO/IEC 8859-1) であれば、それもUTF-8テストに合格します。

そして最後に「Örjansson」が来て、文字化けに分解されます。実際、「Ö」は無効なUTF-8ビット シーケンスになります。一方、 を使用すると、実際に使用されるすべての文字が 1 バイトに収まるので、そうではないことも、UTF-16LEそうでないことも十分に確信できます。UTF-8Latin-1

于 2013-10-26T10:08:22.197 に答える
0

Windows では、「ネイティブ」の unciode 形式は W スタイル関数 ( CreateFileW ) で使用される UTF-16 であることを知っておく必要があります。そのことを念頭に置いて、ファイルを作成すると有効なUTF-16テキストが得られるはずですが、エディターはそれを認識しない場合があります。プログラムが機能することを確認するには、エンコーディングを手動で指定できるテキストエディターを使用します(必要なものはわかっています) ) 認識しない場合は、この Notepad++ が適切な選択です。

他の人が既に述べたように、BOM を書くことはテキスト エディターにとって非常に役立ち、ファイルが正しく読み取られるようになります。

互換性をさらに高めるために、WideCharToMultiByte を使用して UTF-16 を UTF-8 に変換できます。

また、なぜ FindFirstFileW ではなく CreateFileW を直接使用したのですか? プロジェクトで UNICODE を定義しているのですか? そうする場合、コンパイラは CreateFile を CreateFileW に解決します。

ここもまた

WriteFile(c, findFileData.cFileName, (DWORD)wcslen(findFileData.cFileName), &bytesWritten, NULL);

wcslen は、非 ANSI テキストのデータ サイズとは異なる文字数を示します。次のようになります。

wcslen(findFileData.cFileName)*sizeof(wchar_t)
于 2013-10-26T15:29:49.620 に答える
0

UTF-16 ファイルを扱う場合は、バイト オーダー マークを記述し、文字ではなくバイト単位の長さでデータを記述することが重要です。 wcslen文字列の長さを文字数で返しますが、ワイド文字列を使用する場合、文字は 2 バイトです。こちらが修正版です。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;
}
于 2013-10-26T19:43:34.963 に答える