_wfopen在Mac OS X下等效

时间:2020-03-05 18:39:53  来源:igfitidea点击:

我正在寻找Mac OS X下与Windows_wfopen()类似的东西。

为了移植使用wchar *的Windows库作为File接口,我需要此库。由于这是一个跨平台的库,因此我无法依靠客户端应用程序如何获取文件路径并将其提供给库。

解决方案

回答

如果我们使用的是Cocoa,则使用NSString非常简单。只需使用-initWithBytes:length:encoding:(或者-initWithCString:encoding :)加载UTF16数据,然后通过对结果调用UTF8String来获取UTF8版本。然后,只需使用新的UTF8字符串作为参数调用fopen。

绝对可以用UTF-8字符串调用fopen,尽管语言对不起OSX上的C ++。

回答

我们只想使用可能包含Unicode字符的路径打开文件句柄,对吗?只需将文件系统表示形式的路径传递给fopen

  • 如果路径来自现有的Mac OS X框架(例如,无论是Carbon还是Cocoa的Open面板),我们都不需要进行任何转换,就可以按原样使用它。
  • 如果我们自己生成路径的一部分,则应该从路径创建一个CFStringRef,然后以文件系统表示形式获取它,以传递给POSIX API,例如" open"或者" fopen"。

一般来说,对于大多数应用程序,我们不必做很多事情。例如,许多应用程序可能在用户的"应用程序支持"目录中存储了辅助数据文件,但是只要这些文件的名称为ASCII,并且我们使用标准的Mac OS X API来查找用户的"应用程序支持"目录,就不需要对使用这两个组件构建的路径进行一堆偏执的转换。

编辑添加:我强烈警告不要使用诸如wcstombs之类的东西将所有内容任意转换为UTF-8,因为文件系统编码不一定与生成的UTF-8相同。 Mac OS X和Windows都对文件系统路径中使用的编码使用特定(但不同)的规范分解规则。

例如,他们需要决定将""存储为一个还是两个代码单元("带小号的拉丁小写字母E"或者"带小号的拉丁小写字母E",然后是"合并重音")。这些将导致两个不同且长度不同的字节序列,Mac OS X和Windows都可以避免将多个具有相同名称的文件(用户认为它们相同)放在同一目录中。

如何执行此规范分解的规则可能很繁琐,因此与其尝试自己实现,不如将其交给系统框架提供给繁重工作。

回答

@JKP:

并非MacOS X中的所有功能都接受UTF8,但是文件名和文件路径可能是UTF8,因此所有处理文件访问的POSIX函数(打开,打开,打开等)都接受UTF8.

看这里。引用:

How a file name looks at the API level
  depends on the API. Current Carbon
  APIs handle file names as an array of
  UTF-16 characters; POSIX ones handle
  them as an array of UTF-8, which is
  why UTF-8 works well in Terminal. How
  it's stored on disk depends on the
  disk format; HFS+ uses UTF-16, but
  that's not important in most cases.

其他一些POSIX函数也可以处理UTF8. 例如。处理用户名,组名或者用户密码的函数使用UTF8来存储信息(因此,用户名可以是日语,而密码可以是中文,没问题)。

但并非所有人都能处理UTF8. 例如。对于所有字符串函数,UTF8字符串只是普通的C字符串,并且126以上的字符没有特殊含义。他们不了解形成单个Unicode字符的多个字节(C中的字符)的概念。其他API处理传递给它们的char *指针的方式因API而异。但是,通常,我们可以说:

该函数仅接受具有纯ASCII字符的C字符串(仅在0到126之间),或者它将接受UTF8. 通常,函数不允许使用126以上的字符,并以UTF8以外的任何其他编码方式对其进行解释。如果确实如此,则将其记录在案,然后必须有一种将编码与字符串一起传递的方法。

回答

Mac OS X中的POSIX API可与UTF-8字符串一起使用。为了将wchar_t字符串转换为UTF-8,可以使用Mac OS X中的CoreFoundation框架。

这是一个将从wchar_t字符串包装UTF-8生成的字符串的类。

class Utf8
{
public:
    Utf8(const wchar_t* wsz): m_utf8(NULL)
    {
        // OS X uses 32-bit wchar
        const int bytes = wcslen(wsz) * sizeof(wchar_t);
        // comp_bLittleEndian is in the lib I use in order to detect PowerPC/Intel
        CFStringEncoding encoding = comp_bLittleEndian ? kCFStringEncodingUTF32LE
                                                       : kCFStringEncodingUTF32BE;
        CFStringRef str = CFStringCreateWithBytesNoCopy(NULL, 
                                                       (const UInt8*)wsz, bytes, 
                                                        encoding, false, 
                                                        kCFAllocatorNull
                                                        );

        const int bytesUtf8 = CFStringGetMaximumSizeOfFileSystemRepresentation(str);
        m_utf8 = new char[bytesUtf8];
        CFStringGetFileSystemRepresentation(str, m_utf8, bytesUtf8);
        CFRelease(str);
    }   

    ~Utf8() 
    { 
        if( m_utf8 )
        {
            delete[] m_utf8;
        }
    }

public:
    operator const char*() const { return m_utf8; }

private:
    char* m_utf8;
};

用法:

const wchar_t wsz = L"Here is some Unicode content: éà??";
const Utf8 utf8 = wsz;
FILE* file = fopen(utf8, "r");

这将适用于读取或者写入文件。