33

我正在使用日期和时间来标记我正在创建的新文件,但是当我查看文件时,冒号是正斜杠。我正在使用 10.7+ 的 Mac 上开发

这是我正在使用的代码:

 File.open("#{time.hour} : 00, #{time.month}-#{time.day}-#{time.year}", "a") do |mFile|
        mFile.syswrite("#{pKey} - #{tKey}: \n") 
        mFile.syswrite("Items closed: #{itemsClosed} | Total items: #{totalItems} | Percent closed: % #{pClosed} \n") 
        mFile.syswrite("\n")
        mFile.close
     end

这是输出(假设时间是下午 1 点):

13 / 00, 11-8-2012

为什么会发生这种情况,我该如何解决?我希望输出为:

13:00, 11-8-2012
4

3 回答 3

50

曾几何时,在 Mac OS X 之前,:是目录分隔符而不是/. 显然 OS X 10.7 仍在尝试修复这样的程序。:如果你真的需要在那里,我不知道你如何解决这个问题。我会省略它:-)。

编辑:经过更多搜索后,这篇 USENIX 论文描述了正在发生的事情。他们使用的规则显然是这样的:

另一个明显的问题是 HFS+(冒号,':')和 UFS(斜杠,'/')之间的路径分隔符不同。这也意味着 HFS+ 文件名可能包含斜杠字符而不是冒号,而 UFS 文件名则相反。这很容易解决,尽管它涉及来回转换字符串。在读取和写入磁盘格式时,内核 VFS 层中的 HFS+ 实现将冒号转换为斜杠,反之亦然。所以在磁盘上,分隔符是一个冒号,但在 VFS 层(因此它上面的任何东西和内核,例如 libc)它是一个斜杠。然而,传统的 Mac OS 工具包需要冒号,因此在 BSD 层之上,核心 Carbon 工具包进行了另一种翻译。结果是 Carbon 应用程序看到冒号,而其他人看到斜杠。

于 2012-11-08T21:54:09.277 回答
17

虽然 OS X“是”一个 unix 操作系统,但它也从 Mac OS 9 派生了相当多的代码、API、标准等。在 unix 中,文件路径以“/”分隔元素,而“:”在单个文件和目录的名称。在 Mac OS 9 中,情况正好相反:文件路径在元素之间使用“:”,而在单个文件名中允许使用“/”。当 Apple 开发 OS X 时,他们最终不得不支持一些使用 unix 风格文件路径的 API,以及一些使用 OS 9 风格路径的 API,并且它们都必须能够在同一个文件系统上工作。

他们所做的是根据上下文交换分隔符和允许的字符。如果您编写(/运行)一个使用 unix API 访问文件系统的程序,您将看到文件名中带有冒号和斜线分隔路径元素的文件。如果您编写(/运行)一个使用旧的 OS 9 API(或其衍生产品)的程序,您会看到文件名中带有斜杠,而冒号分隔路径元素。有关更多讨论,请参阅Apple 的开发人员 Q&A #1392有关在 AppleScript 中指定路径的说明。

(还有一些其他差异。unix 路径如果以分隔符(“/”)开头,则为绝对路径,绝对路径从根卷的顶部开始。OS 9 路径如果开始,则为绝对路径使用分隔符,并且绝对 OS 9 路径以卷名开头。因此,unix 路径“/tmp/foo:bar”等价于 OS 9 路径“Macintosh HD:tmp:foo/bar”。)

那么,文件名中真正的字符是斜线还是冒号?好吧,文件名是一个相当抽象的东西,但是如果您询问实际存储在磁盘上的字节......如果它在 HFS+(又名 Mac OS 扩展)卷上,它被存储在一个文件系统中旨在与 OS 9(好吧,技术上是 Mac OS 8.1)API 一起使用,因此它允许斜杠但禁止冒号,因此在 HFS+ 卷上,文件将“真正”在名称中有斜杠。OTOH,如果您将文件存储在 unixish 卷上,它将使用 unix 约定存储,并且“真正”的名称中有一个冒号。但是除非您从磁盘读取原始字节或编写文件系统驱动程序,否则差异并不重要......

最后,为什么 Finder 将有争议的文件名字符显示为斜杠而不是冒号?我很确定这主要是惯性。Finder 对此甚至不完全一致,因为如果您使用其转到文件夹选项 (Command-Shift-G) 并输入“/Users/Shared”,它会将其视为 unix 路径。如果你输入“Macintosh HD:Users:Shared”,它不知道你在说什么。此外,如果您运行touch /tmp/foo:bar,请尝试使用 Go To Folder 来访问它:

  • 输入“/tmp/foo:bar”有效。
  • 输入“/tmp/fo”,然后按 Tab 将其自动完成为“/tmp/foo/bar/”,这样就可以了。
  • 输入 "/tmp/foo/bar/" 失败,即使它与自动完成功能完全相同。
  • 输入“/tmp/foo”,然后按 tab 自动完成到“/tmp/foo/”,它不能再自动完成,根本不起作用。

更新:正如 Konrad Rudolph 所指出的,从 El Capitan 开始,Go To Folder 行为已经改变,我不再有任何方法可以使用它来访问包含有争议角色的文件夹。

于 2012-11-09T21:46:51.533 回答
4

为了在处理文件名、路径和各种操作系统时尽可能避免出现问题,您确实应该利用内置的File方法,如joindirnamebasenameextnamesplit. 他们试图避免系统依赖,并尝试为您提供一种跨平台生成有效文件名的编程方式。

当Apple使用旧的Macintosh操作系统时,这个问题要严重得多。迁移到 Mac OS 有所帮助,因为他们放弃了使用:作为分隔符,但是那些手动构建文件名的人发现代码破坏,因为它生成了错误的分隔符,而利用库解决了这个问题。

因为这个特殊问题不是错误,也不是 Ruby 的控制而是 Apple 的,所以我想说这根本不是 Ruby 问题,这是一个可视化问题,如果您希望文件名类似于 Finder 显示的相应代码.

于 2012-11-08T23:38:11.287 回答