Mac OS X 下的 _wfopen 等效项
Posted
技术标签:
【中文标题】Mac OS X 下的 _wfopen 等效项【英文标题】:_wfopen equivalent under Mac OS X 【发布时间】:2010-09-05 22:53:55 【问题描述】:我正在寻找相当于 Mac OS X 下的 Windows _wfopen()
。有什么想法吗?
我需要这个来移植一个使用wchar*
作为其文件接口的Windows 库。由于这是一个跨平台库,我无法依赖客户端应用程序如何获取文件路径并将其提供给库。
【问题讨论】:
【参考方案1】: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");
这将适用于读取或写入文件。
【讨论】:
如果删除多余,直接删除【参考方案2】:您只想使用可能包含 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 都对文件系统路径中使用的编码使用特定(但不同)的规范分解规则。
例如,他们需要决定是否将“é”存储为一个或两个代码单元(LATIN SMALL LETTER E WITH ACUTE
或LATIN SMALL LETTER E
后跟COMBINING ACUTE ACCENT
)。这将导致两个不同且不同长度的字节序列,并且 Mac OS X 和 Windows 都避免将多个同名文件(如用户感知的那样)放在同一个目录中。
如何执行这种规范分解的规则可能会变得非常复杂,因此与其尝试自己实现它,不如将其留给系统框架为您提供的功能来完成繁重的工作。
【讨论】:
对于想在代码中尝试这个的人,en.wikipedia.org/wiki/Unicode_equivalence#Example 显示了两种写“é”的方法(不同的字符代码)。它们在显示 unicode 的 Linux 文件管理器上显示相同,但通常不允许使用两个同名文件。例如,bash
中的 touch $'file-\u00e9' $'file-\u0065\u0301'
将显示在 ls
中:file-é file-é
。【参考方案3】:
@JKP:
并非 MacOS X 中的所有函数都接受 UTF8,但文件名和文件路径可能是 UTF8,因此所有处理文件访问(open、fopen、stat 等)的 POSIX 函数都接受 UTF8。
见here。引用:
文件名在 API 级别的外观 取决于 API。当前碳 API 将文件名作为一个数组处理 UTF-16 字符; POSIX 处理 它们是一个 UTF-8 数组,即 为什么 UTF-8 在终端中运行良好。如何 它存储在磁盘上取决于 磁盘格式; HFS+ 使用 UTF-16,但 在大多数情况下,这并不重要。
其他一些 POSIX 函数也处理 UTF8。例如。处理用户名、组名或用户密码的函数使用UTF8存储信息(因此用户名可以是日文,密码可以是中文,没问题)。
但并非所有都处理 UTF8。例如。对于所有字符串函数,UTF8 字符串只是一个普通的 C 字符串,126 以上的字符没有特殊含义。他们不理解形成单个 Unicode 字符的多个字节(C 中的字符)的概念。其他 API 处理传递给它们的 char * 指针的方式因 API 不同而不同。但是,根据经验,您可以说:
该函数要么只接受纯 ASCII 字符的 C 字符串(仅在 0 到 126 范围内),要么接受 UTF8。通常函数不允许超过 126 的字符并以除 UTF8 之外的任何其他编码来解释它们。如果真的是这种情况,它会被记录在案,然后必须有一种方法可以将编码与字符串一起传递。
【讨论】:
【参考方案4】:如果您使用的是 Cocoa,则使用 NSString 相当容易。只需使用 -initWithBytes:length:encoding: (或者可能是 -initWithCString:encoding:) 加载 UTF16 数据,然后通过在结果上调用 UTF8String 来获取 UTF8 版本。然后,只需使用新的 UTF8 字符串作为参数调用 fopen。
您绝对可以使用 UTF-8 字符串调用 fopen,无论使用哪种语言 - 但在 OSX 上无法使用 C++ - 抱歉。
【讨论】:
我没有使用 Cocoa,我使用的是 C++,而不是 Objective-C。如果您对 fopen() 提供一个 UTF-8 字符串是正确的,我可以将我的 UTF-16 字符串转换为 UTF-8,但是这在 Mac OS X 上如何轻松实现(再次使用 C/C++)。 不是一个明确的答案,因为我依赖 CFString 而不是 NSString 但基本思想是相同的。谢谢。【参考方案5】:我已通过 wifstream 从配置 UTF8 文件中读取文件名(它使用 wchar_t 缓冲区)。
Mac 实现不同于 Linux 和 Windows。 wifstream 从文件中读取每个字节以分隔缓冲区中的 wchar_t 单元。所以我们有 3 个空字节,虽然 open 需要 char 字符串。因此程序员可以使用 wcstombs 函数将宽字符串转换为多字节字符串。
API 支持 UTF8。为了更好地理解您的文件,请使用内存观察程序和十六进制编辑器。
【讨论】:
以上是关于Mac OS X 下的 _wfopen 等效项的主要内容,如果未能解决你的问题,请参考以下文章
用核心数据(Mac OS X 可可)对 _ordered_ 项目列表建模的最佳方法是啥?
SQL Server 2008 中的 SQL Server 2008 R2 中的 dm_os_volume_stats 等效项是啥?
如何将Mac OS X10.9下的Python2.7升级到最新的Python3.3