環境: Gcc/G++ Linux
ファイル システムに非 ASCII ファイルがあり、それを開こうとしています。
これで wchar_t* ができましたが、それを開く方法がわかりません。(私の信頼できる fopen は char* ファイルしか開きません)
助けてください。どうもありがとう。
考えられる答えは 2 つあります。
すべての Unicode ファイル名が表現可能であることを確認したい場合は、ファイルシステムが UTF-8 ファイル名を使用するという仮定をハードコーディングできます。これは、「最新の」Linux デスクトップ アプリ アプローチです。wchar_t
ライブラリ関数を使用して (UTF-32) から UTF-8 に文字列を変換するだけで(iconv
うまく機能します)、独自の実装 (ただし、Shelwien のようにひどく間違っていないように仕様を調べてください) を使用しますfopen
。
より標準指向の方法で処理したい場合は、 を使用してロケールのエンコーディングで文字列をマルチバイト文字列wcsrtombs
に変換し(最新のシステムではいずれにせよ UTF-8 であることが望ましい) 、 を使用する必要があります。これには、以前にまたはでロケールを設定する必要があることに注意してください。wchar_t
char
fopen
setlocale(LC_CTYPE, "")
setlocale(LC_ALL, "")
そして最後に、正確な答えではなく推奨事項:
ファイル名をwchar_t
文字列として保存することは、おそらく恐ろしい間違いです。代わりに、ファイル名を抽象的なバイト文字列として保存し、それらをwchar_t
ジャストインタイムに変換してユーザー インターフェイスに表示する必要があります (それが必要な場合でも、多くの UI ツールキットはプレーンなバイト文字列自体を使用し、文字として解釈します)。あなた)。このようにして、考えられる多くの厄介なコーナーケースを排除し、名前が原因で一部のファイルにアクセスできないという状況に遭遇することはありません.
(ファイルには、必要なものを何でも含めることができます。)
ファイル名に関しては、Linuxには実際には心配する必要のある文字列エンコーディングがありません。ファイル名は、nullで終了する必要があるバイト文字列です。
これは、LinuxがUTF-8であることを正確に意味するわけではありませんが、エンドバイトではないバイトにゼロが含まれる可能性があるため、ワイド文字と互換性がないことを意味します。
ただし、UTF-8は最後を除いてnullがないモデルを保持しているため、実際のアプローチはファイル名の「UTF-8への変換」であると信じる必要があります。
ファイルの内容はLinuxカーネルレベルより上の標準の問題であるため、ここではLinux-yで実行できることや実行したいことは何もありません。ファイルの内容は、ファイルを読み書きするプログラムのみに関係します。Linuxはバイトストリームを保存して返すだけで、必要なすべてのnulを埋め込むことができます。
wchar 文字列を utf8 char 文字列に変換してから、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 標準に従っていると思います。
「ファイルシステム内の非ASCIIファイル」と言うとき、ファイル自体ではなく、非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