Как открыть файл с помощью wchar_t*, содержащей строку не ASCII в Linux?

StackOverflow https://stackoverflow.com/questions/4676327

  •  10-10-2019
  •  | 
  •  

Вопрос

Среда: 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top