Как открыть файл с wchar_t *, содержащий не-Ascii строку в Linux? - PullRequest
5 голосов
/ 13 января 2011

Среда: Gcc / G ++ Linux

У меня есть файл не в формате ascii в файловой системе, и я собираюсь открыть его.

Теперь у меня есть wchar_t *, но я не знаю, как его открыть. (мой доверенный fopen открывает только файл char *)

Пожалуйста, помогите. Большое спасибо.

Ответы [ 6 ]

14 голосов
/ 13 января 2011

Есть два возможных ответа:

Если вы хотите убедиться, что все имена файлов Unicode представимы, вы можете жестко закодировать предположение, что файловая система использует имена файлов UTF-8. Это «современный» Linux-подход к настольным приложениям. Просто преобразуйте ваши строки из 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 точно для своевременного отображения их в пользовательском интерфейсе (если это даже необходимо; многие инструментарии пользовательского интерфейса сами используют простые байтовые строки и выполняют интерпретацию как персонажи для вас). Таким образом вы устраняете множество возможных неприятных угловых случаев и никогда не сталкиваетесь с ситуацией, когда некоторые файлы недоступны из-за их имен.

4 голосов
/ 13 января 2011

Linux - это не UTF-8, но в любом случае это ваш единственный выбор имен файлов

(файлы могут иметь все, что вы хотите внутри их.)


Что касается имен файлов, у linux на самом деле нет строковой кодировки, о которой стоит беспокоиться.Имена файлов - это байтовые строки, которые должны заканчиваться нулем.

Это не означает, что Linux является UTF-8, но это означает, что он не совместим с широкими символами, поскольку они могут иметь ноль вБайт - это не конечный байт.

Но UTF-8 сохраняет модель без нулей, кроме как в конце, поэтому я должен верить, что практический подход - это «преобразовать в UTF-8» дляимена файлов.

Содержание файлов зависит от стандартов выше уровня ядра Linux, поэтому здесь нет ничего, что вы могли бы или хотите сделать для Linux.Содержание файлов будет исключительно заботой программ, которые их читают и пишут.Linux просто хранит и возвращает поток байтов, и в нем могут быть все необходимые встроенные нули.

1 голос
/ 13 января 2011

Преобразуйте строку wchar в строку символов utf8, затем используйте 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;
}
0 голосов
/ 26 августа 2014
// 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
0 голосов
/ 13 января 2011

Я так понимаю, это имя файла, который содержит символы не ascii, а не сам файл, когда вы говорите "файл не ascii в файловой системе".На самом деле не имеет значения, что файл содержит.

Вы можете сделать это с обычным fopen, но вы должны будете соответствовать кодировке, используемой файловой системой.

Это зависит от того, какая версияLinux и какую файловую систему вы используете и как вы ее настроили, но, скорее всего, если вам повезет, файловая система использует UTF-8.Поэтому возьмите ваш wchar_t (который, вероятно, является строкой в ​​кодировке UTF-16?), Преобразуйте его в строку символов, закодированную в UTF-8, и передайте ее в fopen.

0 голосов
/ 13 января 2011

Ознакомьтесь с этим документом

http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm

Я думаю, что Linux следует стандарту POSIX, который обрабатывает все имена файлов как UTF-8.

...