Как открыть файл с помощью wchar_t*, содержащей строку не ASCII в Linux?
Вопрос
Среда: GCC/G ++ Linux
У меня есть файл не ASCII в файловой системе, и я собираюсь открыть его.
Теперь у меня есть wchar_t*, но я не знаю, как его открыть. (Мой доверенный Фопен только открывает файл char*)
Пожалуйста помоги. Большое спасибо.
Решение
Есть два возможных ответа:
Если вы хотите убедиться, что все имена файлов Unicode представлены, вы можете жестко кодировать предположение, что файловая система использует имена файлов UTF-8. Это «современный» подход Linux Desktop-App. Просто преобразовать свои строки из wchar_t
(UTF-32) в UTF-8 с библиотечными функциями (iconv
будет работать хорошо) или вашей собственной реализации (но поищите спецификации, чтобы вы не поняли это ужасно неправильно, как это сделал Шелвиен), а затем используйте fopen
.
Если вы хотите сделать что-то более ориентированное на стандарты, вам следует использовать wcsrtombs
Чтобы преобразовать wchar_t
строка в мультибит char
строка в кодировке локали (что, надеюсь, в любом случае UTF-8 в любой современной системе) и используйте fopen
. Анкет Обратите внимание, что это требует, чтобы вы ранее установили локаль с setlocale(LC_CTYPE, "")
или же setlocale(LC_ALL, "")
.
И, наконец, не совсем ответ, а рекомендация:
Хранение имен файлов как wchar_t
Строки, вероятно, ужасная ошибка. Вместо этого вы должны хранить имена файлов как абстрактные байтовые строки и только преобразовать их в wchar_t
Просто в свое время для отображения их в пользовательском интерфейсе (если это даже необходимо для этого; многие наборы инструментов пользовательского интерфейса используют сами простые байтовые строки и делают интерпретацию как символы для вас). Таким образом, вы устраняете много возможных неприятных угловых случаев, и вы никогда не сталкиваетесь с ситуацией, когда некоторые файлы недоступны из -за их имен.
Другие советы
Linux не UTF-8, но это ваш единственный выбор для имен файлов в любом случае
(Файлы могут иметь все, что вы хотите внутри их.)
Что касается имен файлов, у Linux на самом деле нет кодирования строки, о которой нужно беспокоиться. Имена файлов-это байтовые строки, которые должны быть установлены на ноль.
Это не точно означает, что Linux является UTF-8, но это означает, что он не совместим с широкими символами, поскольку у них может быть ноль в байте, который не является конечным байтом.
Но UTF-8 сохраняет модель без nulls-except-at-end, поэтому я должен верить, что практический подход «преобразуется в UTF-8» для имен файлов.
Содержание файлов является вопросом для стандартов выше уровня ядра Linux, поэтому здесь нет ничего, что вы можете или хотите сделать. Содержание файлов будет исключительно заботой программ, которые читают и пишут их. Linux просто хранит и возвращает байтовый поток, и он может иметь все встроенные Nuls, которые вы хотите.
Преобразовать строку WCHAR в 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 следует за Posix Standard, который рассматривает все имена файлов как UTF-8.
Я воспринимаю это, это имя файла, который содержит символы не ASCII, а не сам файл, когда вы говорите «не ASCII-файл в файловой системе». Неважно, что содержит файл.
Вы можете сделать это с обычным Fopen, но вам придется соответствовать кодированию, которую использует файловая система.
Это зависит от того, какая версия Linux и какую файловую систему вы используете и как вы ее настроили, но, вероятно, если вам повезет, файловая система использует UTF-8. Так что возьмите свой wchar_t (который, вероятно, является кодированной строкой UTF-16?), Преобразуйте ее в строку Char, кодируемую в UTF-8, и передайте ее в 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