web-dev-qa-db-ja.com

NTFSのファイル名はどのエンコーディングとして保存されますか?

WinXPシステムで英語以外の名前のファイル名を処理するためのプログラミングを始めたばかりです。私はユニコードでいくつかの推奨読書をしました、そして私は基本的なアイデアを得ると思いますが、いくつかの部分はまだ私にはあまり明確ではありません。

具体的には、NTFSに保存されているファイル名前(コンテンツではなく、実際のファイル名)がどのエンコーディング(UTF-8、UTF-16LE/BE)ですか? char *を取るfopen()を使用してファイルを開くことは可能ですか、またはwchar_t *を使用し、おそらくUTF-16文字列を取るwfopen()を使用する以外に選択肢はありませんか?

UTF-8でエンコードされた文字列をfopen()に手動で入力しようとしました。

unsigned char filename[] = {0xEA, 0xB0, 0x80, 0x2E, 0x74, 0x78, 0x74, 0x0}; // 가.txt

FILE* f = fopen((char*)filename, "wb+");

しかし、これは「ê°€.txt」として出てきました。

Windowsアプリケーションを(wchar_t *)ではなく(char *)で渡していることを漠然と覚えているため、Windowsでファイル名を開くのにUTF8エンコードされた文字列で十分だという印象を受けました問題はありません。

誰もこれに光を当てることができますか?

39
vroooom

NTFSはファイル名をUTF-16で保存しますが、fopenはANSI(UTF-8ではありません)を使用しています。

UTF16エンコードされたファイル名を使用するには、Unicodeバージョンのファイルオープンコールを使用する必要があります。これを行うには、プロジェクトでUNICODE_UNICODEを定義します。次に、CreateFile呼び出しまたはwfopen呼び出しを使用します。

36
villintehaspam

fopen()-Windows上のMSVCでは、(デフォルトで)utf-8エンコードされたchar *を取りません。

残念なことに、utf-8は、ものごとのすばらしい計画のなかでかなり最近発明されました。 Windows APIは、UnicodeバージョンとAnsiバージョンに分かれています。 every文字列を取得または処理するWindows APIは、実際にはWまたはAの接尾辞で使用可能です-「ワイド」文字/ Unicodeの場合はW、Ansiの場合はAマクロマジックはこれをすべて開発者から隠しているので、違いを知らずに、ビルド構成に応じてchar *またはwchar_t *でCreateFileを呼び出すだけです。

「Ansi」エンコーディングは、実際には特定のエンコーディングではありません。ただし、「char」文字列に使用されるエンコーディングは、PCのロケール設定に固有であることを意味します。

現在、fopenのようなc-runtime関数は、開発者の知識がなくてもデフォルトで動作する必要があるため、Windowsシステムでは、Windowsローカルエンコーディングで文字列を受け取ることを期待しています。 msdnは、Microsoft c-runtime api setlocalが現在のスレッドのロケールを変更できることを示しますが、utf-8のように、1文字あたり2バイトを超えるロケールを必要とする場合は特に失敗します。

そのため、Windowsにはショートカットはありません。 必要 wfopenを使用するか、ネイティブAPI CreateFileW(またはUnicodeビルド設定を使用してプロジェクトを作成し、Createfileを呼び出すだけ)をwchar_t *文字列で使用します。

14
Chris Becke

他の人が答えたように、UTF-8でエンコードされた文字列を処理する最良の方法は、それらをUTF-16に変換し、_wfopenCreateFileWなどのネイティブUnicode APIを使用することです。

ただし、Unicodeをサポートしていないか、ポータブルCで記述されているため、fopen()を無条件に使用するライブラリを呼び出す場合、この方法は役に立ちません。その場合でも、レガシーを使用することは可能です。 UTF-8でエンコードされた文字列をfopenで使用可能なASCII形式に変換するための「短いパス」ですが、いくつかの作業が必要です:

  1. MultiByteToWideChar を使用して、UTF-8表現をUTF-16に変換します。

  2. GetShortPathNameW を使用して、ASCIIのみの「ショートパス」を取得します。 GetShortPathNameWは、すべてのASCIIコンテンツを含むワイド文字列として返します。これは、各wchar_tcharをキャストするロスレスコピーによって、それを狭い文字列に簡単に変換する必要があります。

  3. fopen()または最終的にfopen()を使用するコードに短いパスを渡します。そのコードによって出力されるエラーメッセージがある場合は、見苦しい「短いパス」(たとえば、KINTO~1ではなくkinto-un-筋斗雲)を参照することに注意してください。

これは厳密に推奨される長期戦略ではありませんが、Windowsの短いパスはボリュームごとにオフにできるレガシー機能であるため、fopen()を使用するコードにファイル名を渡す唯一の方法である可能性がありますおよびその他のファイル関連のAPI呼び出し(stataccessCreateFileのANSIバージョンなど)。

5
user4815162342