4

ファイルの読み取りと書き込みを行うクラスを作成しようとしています。文字列の場合、ANSI と Unicode の 2 つの方法があります。ANSI 関数は問題ありませんが、私の Unicode 関数には問題があります。

「0xFEFF」のものをチェックしたりスキップしたりせずに、Unicodeファイルを直接、つまり直接読み取ることができるのは少し配線されています。どの言語を使用していても機能します (英語、中国語、日本語を試しました)。私が知っておくべきことはありますか?

次に、最大の問題が飛び出しました: Unicode 文字列をファイルに書き込むことです。最初に、「\n」文字を使用せずにアルファベットとして簡単な英語を試しましたが、うまくいきました。次に、「\ n」を押し込むと、問題が発生し始めます。出力は、「abcdefg \nhijklmn \nopqrst \nuvwxyz」(「\ n」は機能しますが、スペースが非常に多い)のように多くのスペースで挿入され、ファイルは再び ANSI になります。他の言語の文字を聞かないでください。まったく読めません。

ここで質問があります: Unicode 文字列をファイルに正しく書き込むにはどうすればよいですか? 「_wopen」関数については言及しないでください。ファイルは既に「fopen」関数で開かれています。

回答とアドバイスをいただければ幸いです。

Windows 7 とビジュアル スタジオを使用しています。

編集:次のコードで英語以外の文字に対して機能しますが、「\ n」ではまだ間違っています。

char* cStart = "\xff\xfe";

if (::ftell(m_pFile) == 0)
    ::fwrite(cStart, sizeof(wchar_t), 1, m_pFile);

しかし、それはどのように機能しますか?ファイルを読んでいる間、私はそれを見なかったということです。

編集:私のコードの一部。

void File::ReadWText(wchar_t* pString, uint32 uLength)
{
    wchar_t cLetter = L'\0';
    uint32 uIndex = 0;

    do {
        cLetter = L'\0';
        ::fread(&cLetter, sizeof(wchar_t), 1, m_pFile);
        pString[uIndex] = cLetter;
    }while (cLetter != L'\0' && !::feof(m_pFile) && uIndex++ < uLength);
    pString[uIndex] = L'\0';
}

void File::WriteWText(wchar_t* pString, uint32 uLength)
{
    char* pStart = "\xff\xfe";

    if (::ftell(m_pFile) == 0)
        ::fwrite(pStart, sizeof(wchar_t), 1, m_pFile);

    m_uSize += sizeof(wchar_t) * ::fwrite(pString, sizeof(wchar_t), uLength, m_pFile);
}

void main()
{
    ::File* pFile = new File();
    wchar_t* pWString = L"abcdefg\nhijklmn\nopqrst\nuvwxyz";

    pFile->Open("TextW.txt", File::Output);
    // fopen("TextW.txt", "w");
    pFile->WriteWText(pWString, ::wcslen(pWString));
    pFile->Close();
}

出力ファイルの内容は次のとおりです。

「L'\n'」の正しい表現かどうかはわかりませんが、Unicode を扱ったことがありません。私を助けてくれてありがとう :)

4

3 に答える 3

3

この質問に C および C++ のタグが付けられていることに気付きました。以下では、C++ の状況について説明しています。の使用を完全に無視しており、 を使用してさまざまなエンコーディングを処理する方法がわかりません。

ファイルを読み書きするときは、ファイルのエンコーディングをシステムに伝える必要があります。これにより、ファイルのバイトをプログラム内部の文字に変換し、書き込み時に文字をバイトに変換できます。多くの場合、この変換は完全に無視されます。これは、バイトから文字への変換が ID であるためです。バイトは文字として解釈でき、その逆も可能です。これは、外部エンコーディングがASCIIの場合に当てはまります(これは、質問では「ANSI」と呼ばれていると思います)。

UTF-8 でエンコードされたファイルが恒等変換を使用してバイトから文字に変換するふりをして、いくつかの拡張機能を使用します。C++ での内部文字表現の当初のビジョンは、文字ごとに 1 つのユニット (たとえば acharや a ) を持つことでしたwchar_t。Unicode は、これとうまく機能する一連の目標 (たとえば、各文字は 1 つの単位で表され、単位のサイズは 16 ビット) を設定していましたが、元の目標をすべて犠牲にすることを感じ、最終的にシステムに行き着きました。ここで、1 つの文字 (実際には「コード ポイント」と呼ばれていると思いますが、私は Unicode の専門家ではありません) は複数の単語で構成される場合があります (たとえば、文字を組み合わせて使用​​する場合)。いずれにせよ、個々のユニットが個性を無視して変異しない限り、char(例 as std::string) および UTF-16 のシーケンスとしてwchar_t(例 as std::wstring)。ただし、UTF-8 (または UTF-8 のサブセットである ASCII) とは異なるものを読み取る場合は、どのエンコーディングが使用されているかを認識できるようにストリームを設定するように注意する必要があります。

特定のエンコーディングについて知るためにファイル ストリームを設定する標準的な方法は、特定のエンコーディングを使用して外部バイトと内部文字の間で変換std::localeする対応するファセットを含む適切なファイルを作成することです。std::codecvt<...>実際に対応std::localeを取得する方法は、個々の実装次第です。デフォルトの変換は、プログラムが のすべての値をカバーする ASCII の拡張子を使用するふりをすることを意図していますchar。UTF-8 を読み書きする場合、これは問題なく動作するはずです。

「Unicode文字列を書く」とはどういう意味かわかりませんが、見た目からするとstd::wstring、エンコーディングを設定せずに書いています。

于 2012-02-09T20:09:28.450 に答える
2

ソースを含む編集された質問への回答:

void File::ReadWText(wchar_t* pString, uint32 uLength)バギーです。uLength配列のサイズ ( wchar_t string[size])の場合

while (.... && uIndex++ < uLength); する必要がありますwhile (.... && (++uIndex)+1 < uLength);

そうpString[uIndex] = L'\0';しないと、オーバーフローする可能性があります。

改行の問題.. L"abcdefg\nhijklmn\nopqrst\nuvwxyz"; windows は\r\n改行として使用します。L"abcdefg\r\nhijklmn\r\nopqrst\r\nuvwxyz";動作するはずです。

このmsdn-thread unicode newline problem とあなたのに基づいて// fopen("TextW.txt", "w");、ファイルを開く必要があると思います"wb"! そう\nしないと、自動的に展開され\r\n、ユニコードエンコーディングが台無しになります..

于 2012-02-09T21:03:32.970 に答える
1

うーん、これは役立つかもしれません..

先頭にBOMを書くことを忘れないでくださいFF FE

コードを投稿していないため..新しい行をASCII'\n'として書いていると思います(質問に書かれているように)

新しい行については、書く必要があります0D 00 0A 00

または を使用する場合'\n'は、キャストする必要があります(short)'\n'

于 2012-02-09T20:14:07.403 に答える