Come aprire un file con wchar_t * contenente stringa non Ascii in Linux?
Domanda
Ambiente: Gcc / G ++ Linux
Ho un file non-ASCII nei file system e ho intenzione di aprirla.
Ora ho un wchar_t *, ma non so come aprirlo. (Il mio fidato FOPEN solo apre char * file)
Si prega di aiuto. Grazie mille.
Soluzione
Ci sono due possibili risposte:
Se si vuole fare in modo tutti i nomi di file Unicode sono rappresentabili, è possibile hard-code l'ipotesi che le usi filesystem UTF-8 nomi di file. Questo è l'approccio di Linux desktop app "moderna". Basta convertire le corde da wchar_t
(UTF-32) a UTF-8 con funzioni di libreria (iconv
avrebbe funzionato bene) o la propria implementazione (ma occhiata le specifiche in modo da non farlo terribilmente storto come Shelwien ha fatto), quindi utilizzare fopen
.
Se si vuole fare le cose più standard-oriented modo, si dovrebbe usare wcsrtombs
per convertire la stringa wchar_t
ad una stringa multibyte char
nella codifica del locale (che si spera è UTF-8 in ogni caso su qualsiasi sistema moderno) e l'uso fopen
. Si noti che questo richiede che precedentemente impostato il locale con setlocale(LC_CTYPE, "")
o setlocale(LC_ALL, "")
.
E, infine, non è esattamente una risposta, ma una raccomandazione:
Memorizzazione nomi di file come stringhe wchar_t
è probabilmente un terribile errore. Si dovrebbe invece archiviare i nomi di file come stringhe di byte astratti, e solo convertire coloro ai wchar_t
just-in-time per la loro visualizzazione nell'interfaccia utente (se è ancora necessario a tal; molti toolkit UI utilizzano stringhe di byte di pianura se stessi e fare l'interpretazione come caratteri per te). In questo modo si eliminano molti possibili casi angolo brutte, e non avete mai incontrare una situazione in cui alcuni file sono inaccessibili a causa dei loro nomi.
Altri suggerimenti
Linux non è UTF-8, ma è l'unica scelta per i nomi dei file in ogni caso
(I file possono avere tutto quello che vuoi all'interno di loro.)
Per quanto riguarda i nomi dei file, linux non hanno davvero una stringa di codifica di cui preoccuparsi. I nomi dei file sono stringhe di byte che devono essere terminata da null.
Questo non significa esattamente che Linux è UTF-8, ma significa che non è compatibile con caratteri estesi in quanto potrebbero avere uno zero in un byte che non è il byte finale.
Ma UTF-8 di preservare il modello no-null-tranne-at-the-end, quindi devo credere che l'approccio pratico è "convertito in UTF-8" per i nomi dei file.
Il contenuto dei file è una questione per gli standard sul livello del kernel di Linux, ecco non c'è nulla di Linux-y che si può o vuole fare. Il contenuto dei file sarà esclusivamente la preoccupazione dei programmi che leggono e scrivono. Linux solo negozi e ritorna il flusso di byte, e può avere tutte le nuls incorporati che si desidera.
stringa Converti wchar a stringa utf8 char, quindi utilizzare 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;
}
Dai un'occhiata a questo documento,
http://www.firstobject.com/wchar_t- string-on-linux-osx-windows.htm
Credo che Linux segue standard POSIX, che tratta tutti i nomi di file come UTF-8.
Lo prendo è il nome del file che contiene caratteri non ASCII, non il file stesso, quando si dice "il file non-ASCII nei file system". Essa in realtà non importa quale sia il file contiene.
Si può fare questo con fopen normale, ma si dovrà corrispondere alla codifica gli usi filesystem.
Dipende da quale versione di Linux e del filesystem che si sta utilizzando e come hai impostato in su, ma probabilmente, se siete fortunati, gli usi filesystem UTF-8. Quindi prendere il vostro wchar_t (che è probabilmente una stringa codificata UTF-16?), Convertirlo in una stringa char codifica UTF-8, e passare che a 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