Linuxに非ASCII文字列を含むWCHAR_T*を使用してファイルを開くにはどうすればよいですか?
質問
環境:GCC/G ++ Linux
ファイルシステムにはASSASCII以外のファイルがあり、開くつもりです。
今、私はwchar_t*を持っていますが、それを開く方法がわかりません。 (私の信頼できるfopenはchar*ファイルのみを開くだけです)
助けてください。どうもありがとう。
解決
2つの答えがあります。
すべてのUnicodeファイル名が表現可能であることを確認する場合は、ファイルシステムがUTF-8ファイル名を使用するという仮定をハードコードできます。これは、「モダンな」Linuxデスクトップアプリアプローチです。弦をから変換してください wchar_t
(UTF-32)ライブラリ関数を使用してUTF-8に(iconv
うまくいきます)またはあなた自身の実装(ただし、Shelwienが行ったように恐ろしく間違っていることはありません)を使用して使用してください fopen
.
より標準指向の方法で物事をやりたい場合は、使用する必要があります wcsrtombs
変換します wchar_t
マルチバイトへの文字列 char
Localeのエンコード(最新のシステムではとにかくUTF-8)の文字列と使用 fopen
. 。これには、以前にロケールを設定する必要があることに注意してください setlocale(LC_CTYPE, "")
また setlocale(LC_ALL, "")
.
そして最後に、正確には答えではなく、推奨事項:
ファイル名を保存します wchar_t
ひもはおそらく恐ろしい間違いです。代わりに、ファイル名を抽象バイト文字列として保存し、それらをにのみ変換する必要があります wchar_t
ユーザーインターフェイスにそれらを表示するためのジャストインタイム(それが必要な場合でも、多くのUIツールキットはプレーンバイト文字列自体を使用し、あなたのために文字として解釈を行います)。これにより、多くの厄介なコーナーケースを排除し、名前のためにいくつかのファイルがアクセスできない状況に遭遇することはありません。
他のヒント
LinuxはUTF-8ではありませんが、とにかくファイル名の唯一の選択肢です
(ファイルには何でも必要です 中身 彼ら。)
ファイル名に関しては、Linuxには心配する文字列エンコードが実際にはありません。ファイル名は、ヌル終了する必要があるバイト文字列です。
これは、LinuxがUTF-8であることを正確に意味するものではありませんが、バイトでゼロを持つことができるため、幅の広い文字と互換性がないことを意味します。
しかし、UTF-8はエンドの存在なしモデルを保存するため、実際のアプローチはファイル名の「UTF-8に変換」であると信じなければなりません。
ファイルのコンテンツは、Linuxカーネルレベルを超える標準の問題であるため、ここではLinux-yができることややりたいことはありません。ファイルの内容は、それらを読み書きするプログラムの懸念のみになります。 Linuxは、バイトストリームを保管して返品するだけで、必要なすべての埋め込みNULを持つことができます。
WCHAR STRINGをUTF8 CHAR STRINGに変換し、FOPENを使用します。
typedef unsigned int uint;
typedef unsigned short word;
typedef unsigned char byte;
int UTF16to8( wchar_t* w, char* s ) {
uint c;
word* p = (word*)w;
byte* q = (byte*)s; byte* q0 = q;
while( 1 ) {
c = *p++;
if( c==0 ) break;
if( c<0x080 ) *q++ = c; else
if( c<0x800 ) *q++ = 0xC0+(c>>6), *q++ = 0x80+(c&63); else
*q++ = 0xE0+(c>>12), *q++ = 0x80+((c>>6)&63), *q++ = 0x80+(c&63);
}
*q = 0;
return q-q0;
}
int UTF8to16( char* s, wchar_t* w ) {
uint cache,wait,c;
byte* p = (byte*)s;
word* q = (word*)w; word* q0 = q;
while(1) {
c = *p++;
if( c==0 ) break;
if( c<0x80 ) cache=c,wait=0; else
if( (c>=0xC0) && (c<=0xE0) ) cache=c&31,wait=1; else
if( (c>=0xE0) ) cache=c&15,wait=2; else
if( wait ) (cache<<=6)+=c&63,wait--;
if( wait==0 ) *q++=cache;
}
*q = 0;
return q-q0;
}
このドキュメントをご覧ください
http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm
Linuxは、すべてのファイル名をUTF-8として扱うPOSIX Standardに従うと思います。
「ファイルシステムではASSASCII以外のファイル」と言うとき、ファイル自体ではなく、ASCII以外の文字を含むファイルの名前です。ファイルに何が含まれているかは本当に問題ではありません。
これを通常のFOPENで行うことはできますが、ファイルシステムの使用をエンコードすることを一致させる必要があります。
これは、Linuxのバージョンと使用しているファイルシステムと設定方法によって異なりますが、運が良ければ、ファイルシステムがUTF-8を使用している可能性があります。したがって、WCHAR_T(おそらくUTF-16エンコードされた文字列ですか?)を使用して、UTF-8でエンコードされたchar文字列に変換し、それをfopenに渡します。
// locals
string file_to_read; // any file
wstring file; // read ascii or non-ascii file here
FILE *stream;
int read = 0;
wchar_t buffer= '0';
if( fopen_s( &stream, file_to_read.c_str(), "r+b" ) == 0 ) // in binary mode
{
while( !feof( stream ))
{
// if ascii file second arg must be sizeof(char). if non ascii file sizeof( wchar_t)
read = fread( & buffer, sizeof( char ), 1, stream );
file.append(1, buffer);
}
}
file.pop_back(); // since this code reads the last character twice.Throw the last one
fclose(stream);
// and the file is in wstring format.You can use it in any C++ wstring operation
// this code is fast enough i think, at least in my practice
// for windows because of fopen_s