我正在寻找相当于_wfopen()
Mac OS X 下的 Windows。知道吗?
我需要这个来移植一个wchar*
用于其文件接口的 Windows 库。由于这是一个跨平台库,我无法依赖客户端应用程序如何获取文件路径并将其提供给库。
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");
这将适用于读取或写入文件。
您只想使用可能包含 Unicode 字符的路径打开文件句柄,对吗?只需将文件系统表示中的路径传递给fopen
.
如果路径来自现有的 Mac OS X 框架(例如,无论是 Carbon 还是 Cocoa 的 Open 面板),您不需要对其进行任何转换,并且可以按原样使用它。
如果您自己生成路径的一部分,您应该从您的路径创建一个 CFStringRef,然后在文件系统表示中获取它以传递给 POSIX API,如open
或fopen
.
一般来说,对于大多数应用程序,您不必做很多这样的事情。例如,许多应用程序可能将辅助数据文件存储在用户的应用程序支持目录中,但只要这些文件的名称是 ASCII,并且您使用标准 Mac OS X API 来定位用户的应用程序支持目录,则不需要对用这两个组件构建的路径进行一堆偏执的转换。
编辑添加: 我强烈警告不要使用类似的东西任意将所有内容转换为 UTF-8,wcstombs
因为文件系统编码不一定与生成的 UTF-8 相同。Mac OS X 和 Windows 都对文件系统路径中使用的编码使用特定(但不同)的规范分解规则。
例如,他们需要决定是否将“é”存储为一个或两个代码单元(LATIN SMALL LETTER E WITH ACUTE
或者LATIN SMALL LETTER E
后跟COMBINING ACUTE ACCENT
)。这将导致两个不同且长度不同的字节序列,并且 Mac OS X 和 Windows 都努力避免将多个具有相同名称的文件(如用户感知的那样)放在同一目录中。
如何执行这种规范分解的规则可能会变得非常复杂,因此与其尝试自己实现它,最好将其留给系统框架为您提供的功能来完成繁重的工作。
@JKP:
并非 MacOS X 中的所有函数都接受 UTF8,但文件名和文件路径可能是 UTF8,因此所有处理文件访问(open、fopen、stat 等)的 POSIX 函数都接受 UTF8。
见这里。引用:
文件名在 API 级别的外观取决于 API。当前的 Carbon API 将文件名处理为 UTF-16 字符数组;POSIX 将它们作为 UTF-8 数组处理,这就是 UTF-8 在终端中运行良好的原因。它在磁盘上的存储方式取决于磁盘格式;HFS+ 使用 UTF-16,但这在大多数情况下并不重要。
其他一些 POSIX 函数也处理 UTF8。例如处理用户名、组名或用户密码的函数使用UTF8 来存储信息(因此用户名可以是日语,密码可以是中文,没问题)。
但并非所有人都处理 UTF8。例如,对于所有字符串函数,UTF8 字符串只是一个普通的 C 字符串,126 以上的字符没有特殊含义。他们不理解形成单个 Unicode 字符的多个字节(C 中的字符)的概念。其他 API 处理传递给它们的 char * 指针的方式因 API 不同而不同。但是,根据经验,您可以说:
该函数要么只接受带有纯 ASCII 字符(仅在 0 到 126 范围内)的 C 字符串,要么接受 UTF8。通常函数不允许超过 126 的字符并以除 UTF8 之外的任何其他编码来解释它们。如果确实是这种情况,则会记录在案,然后必须有一种方法可以将编码与字符串一起传递。
如果您使用的是 Cocoa,则使用 NSString 相当容易。只需使用 -initWithBytes:length:encoding: (或者可能是 -initWithCString:encoding:) 加载 UTF16 数据,然后通过在结果上调用 UTF8String 来获取 UTF8 版本。然后,只需使用新的 UTF8 字符串作为参数调用 fopen。
无论语言如何,您绝对可以使用 UTF-8 字符串调用 fopen - 虽然在 OSX 上无法使用 C++ - 抱歉。
我已经通过wifstream从配置 UTF8 文件中读取了文件名(它使用wchar_t缓冲区)。
Mac 实现不同于 Linux 和 Windows。wifstream 从文件中读取每个字节以分隔缓冲区中的 wchar_t 单元。所以我们有 3 个空字节,尽管open需要char字符串。因此程序员可以使用wcstombs函数将宽字符串转换为多字节字符串。
API 支持 UTF8。为了更好地理解您的文件,请使用内存观察程序和十六进制编辑器。