6

环境:Gcc/G++ Linux

我在文件系统中有一个非 ascii 文件,我将打开它。

现在我有一个 wchar_t*,但我不知道如何打开它。(我信任的 fopen 只打开 char* 文件)

请帮忙。非常感谢。

4

6 回答 6

15

有两种可能的答案:

如果您想确保所有 Unicode 文件名都是可表示的,您可以硬编码文件系统使用 UTF-8 文件名的假设。这是“现代”Linux 桌面应用程序方法。只需将字符串从wchar_t(UTF-32) 转换为 UTF-8,使用库函数(iconv会很好用)或您自己的实现(但要查找规范,这样您就不会像 Shelwien 那样弄错了),然后使用fopen.

如果你想以更面向标准的方式做事,你应该使用wcsrtombswchar_t字符串转换为语言环境编码中的多字节char字符串(希望在任何现代系统上都是 UTF-8)并使用fopen. 请注意,这要求您之前使用setlocale(LC_CTYPE, "")或设置区域设置setlocale(LC_ALL, "")

最后,不完全是一个答案,而是一个建议:

将文件名存储为wchar_t字符串可能是一个可怕的错误。相反,您应该将文件名存储为抽象字节字符串,并且只将它们转换为wchar_t即时显示它们以在用户界面中显示它们(如果它甚至有必要的话;许多 UI 工具包本身使用纯字节字符串并将解释作为字符你)。通过这种方式,您消除了许多可能令人讨厌的极端情况,并且您永远不会遇到某些文件因其名称而无法访问的情况。

于 2011-01-13T04:11:58.770 回答
4

Linux 不是 UTF-8,但无论如何它是文件名的唯一选择

(文件中可以包含您想要的任何内容


关于文件名,linux 并没有真正需要担心的字符串编码。文件名是需要以空值结尾的字节字符串。

这并不完全意味着 Linux 是 UTF-8,但它确实意味着它与宽字符不兼容,因为它们可能在一个不是结束字节的字节中有一个零。

但是 UTF-8 保留了 no-nulls-except-at-the-end 模型,所以我必须相信实用的方法是文件名“转换为 UTF-8”。

文件的内容是高于 Linux 内核级别的标准的问题,所以这里没有任何 Linux-y 可以或想要做的事情。文件的内容将完全由读写它们的程序关心。Linux 只是存储和返回字节流,它可以拥有你想要的所有嵌入式 nuls。

于 2011-01-13T03:40:18.800 回答
1

将 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;
}
于 2011-01-13T03:14:19.017 回答
0

看看这个文件

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

我认为 Linux 遵循 POSIX 标准,它将所有文件名都视为 UTF-8。

于 2011-01-13T03:03:15.380 回答
0

当您说“文件系统中的非 ascii 文件”时,我认为它是包含非 ascii 字符的文件的名称,而不是文件本身。文件包含什么并不重要。

您可以使用普通的 fopen 执行此操作,但您必须匹配文件系统使用的编码。

这取决于 Linux 的版本和使用的文件系统以及设置方式,但如果幸运的话,文件系统很可能使用 UTF-8。所以把你的 wchar_t(它可能是一个 UTF-16 编码的字符串?),把它转换成一个用 UTF-8 编码的 char 字符串,然后把它传递给 fopen。

于 2011-01-13T03:03:22.587 回答
0
// 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
于 2014-08-25T20:37:38.140 回答