iOS文件系统基础
文件系统基础
OS X和iOS中的文件系统处理数据文件,应用程序和与操作系统本身相关联的文件的持久存储。因此,文件系统是所有进程使用的基本资源之一。
iOS中的文件系统和OS X中的主要格式是HFS Plus。OS X还支持各种其他格式,如中所述Supported File Systems。无论底层格式如何,附加到设备的所有磁盘 - 无论它们是物理插入还是通过网络间接连接 - 贡献空间来创建单个文件集合。因为文件数量可以容易地达到数百万,所以文件系统使用目录来创建分层组织。尽管基本的目录结构在iOS和OS X中是类似的,但是每个系统组织应用程序和用户数据的方式都有所不同。
在开始编写与文件系统交互的代码之前,应首先了解文件系统的组织以及适用于代码的规则。除了您不能将文件写入您没有适当安全权限的目录的基本原则外,应用程序也应该是良好的公民并将文件放在适当的位置。精确地放置文件的位置取决于平台,但总体目标是确保用户的文件保持容易被发现,并且您的代码在内部使用的文件不在用户的方式。
关于iOS文件系统
iOS文件系统适用于自行运行的应用程序。为了保持系统简单,iOS设备的用户没有对文件系统的直接访问,应用程序应该遵循这个约定。
iOS标准目录:文件所在位置
出于安全考虑,iOS应用程序与文件系统的交互仅限于应用程序的沙箱目录中的目录。在安装新应用程序期间,安装程序会在沙箱目录中为应用程序创建多个容器目录。每个容器目录都有一个特定的角色。bundle容器目录包含应用程序的包,而数据容器目录包含应用程序和用户的数据。数据容器目录进一步分为多个子目录,应用程序可以使用这些子目录对其数据进行排序和组织。应用程序还可以在运行时请求访问其他容器目录,例如iCloud容器。
这些容器目录构成应用程序对文件系统的主视图。图1-1显示了应用程序的沙箱目录的表示。

应用程序通常禁止在其容器目录之外访问或创建文件。此规则的一个例外是应用程序使用公共系统界面访问诸如用户的联系人或音乐等内容。在这些情况下,系统框架使用助手应用程序来处理读取或修改相应数据存储所需的任何文件相关操作。
表1-1列出了沙箱目录中的一些更重要的子目录,并描述了它们的预期用途。此表还描述了每个子目录的任何其他访问限制,并指出目录的内容是否由iTunes和iCloud备份。
表1-1 iOS应用的常用目录

OS应用程序可以在,和目录中创建其他目录。您可以这样做以更好地组织这些位置中的文件。DocumentsLibrarytmp
有关如何从iOS应用程序获取对上述目录的引用的信息,请参阅在标准目录中查找项目。有关放置文件位置的提示,请参阅应将应用程序文件放在哪里。
你应该把你的应用程序的文件
为了防止iOS设备上的同步和备份过程需要很长时间,请选择放置文件的位置。存储大文件的应用程序可能会减慢备份到iTunes或iCloud的过程。这些应用程序还可能消耗大量用户可用的存储空间,这可能会鼓励用户删除应用程序或禁用将该应用程序的数据备份到iCloud。考虑到这一点,您应该根据以下准则存储应用数据:
-
将用户数据放入
Documents/。用户数据通常包括您可能希望向用户公开的任何文件 - 您可能希望用户创建,导入,删除或编辑的任何文件。对于绘图应用程序,用户数据包括用户可能创建的任何图形文件。对于文本编辑器,它包括文本文件。视频和音频应用甚至可以包括用户下载以观看或稍后收听的文件。 -
将应用程序创建的支持文件放在
Library/Application support/目录中。一般来说,此目录包含应用程序用于运行但应保持对用户隐藏的文件。此目录还可以包括从应用程序包加载的数据文件,配置文件,模板和修改的资源版本。 -
请记住,默认情况下备份文件。您可以通过使用键调用从备份中排除文件。任何可以重新创建或下载的文件都必须从备份中排除。这对大型媒体文件特别重要。如果您的应用程序下载视频或音频文件,请确保它们不包含在备份中。
Documents/Application Support/-[NSURL setResourceValue:forKey:error:]NSURLIsExcludedFromBackupKey -
将临时数据放在目录中
tmp/。临时数据包括您不需要在较长时间内保留的任何数据。记住在完成这些文件后删除这些文件,以使它们不会继续占用用户设备上的空间。当应用程序未运行时,系统将定期清除这些文件; 因此,您不能依赖这些文件在应用程序终止后仍然存在。 -
将数据高速缓存文件放在目录中
Library/Caches/。缓存数据可用于需要持久于临时数据的任何数据,但不能长于支持文件。一般来说,应用程序不需要缓存数据正常操作,但它可以使用缓存数据来提高性能。高速缓存数据的示例包括(但不限于)数据库高速缓存文件和瞬态,可下载内容。请注意,系统可能会删除Caches/目录以释放磁盘空间,因此您的应用程序必须能够根据需要重新创建或下载这些文件。
关于OS X文件系统
OS X文件系统是为Macintosh计算机设计的,用户和软件都可以访问文件系统。用户通过Finder直接访问文件系统,通过隐藏或重命名一些文件和目录来呈现文件系统的面向用户的视图。应用程序使用系统接口访问文件系统,这些接口显示完整的文件系统,就像它出现在磁盘上一样。
域确定文件的放置
在OS X中,文件系统分为多个域,根据其预期用途分离文件和资源。这种分离为用户提供了简单性,他们只需要担心特定的文件子集。按域安排文件还可以让系统对该域中的文件应用无掩蔽访问权限,防止未经授权的用户有意或无意更改文件。
-
用户域包含特定于登录到系统的用户的资源。虽然它在技术上包含所有用户,但此域在运行时仅反映当前用户的主目录。用户主目录可以驻留在计算机的引导卷(在
/Users目录中)或网络卷上。每个用户(无论权限)都可以访问和控制自己的主目录中的文件。 -
本地域包含诸如当前计算机本地并在该计算机的所有用户之间共享的应用程序等资源。本地域不对应于单个物理目录,而是由本地引导(和根)卷上的多个目录组成。此域通常由系统管理,但具有管理权限的用户可以添加,删除或修改此域中的项目。
-
网络域包含在局域网的所有用户之间共享的诸如应用和文档的资源。此域中的项通常位于网络文件服务器上,并受网络管理员的控制。
-
系统域包含由Apple安装的系统软件。系统域中的资源是系统运行所必需的。用户无法添加,删除或更改此域中的项目。
图1-2显示了本地,系统和用户域如何映射到OS X安装的本地文件系统。(网络域未显示,但在很多方面类似于本地域。)此图显示用户可能看到的可见目录。根据用户的系统,其他目录可能是可见的,或者这里显示的某些目录可能被隐藏。
图1-2 本地OS X文件系统

有关OS X中目录的内容的信息,请参阅OS X标准目录:文件所在的位置。有关OS X通常对用户隐藏的目录(以及为什么)的信息,请参阅隐藏的文件和目录:简化用户体验。
OS X标准目录:文件所在位置
无论是由系统提供还是由应用程序创建,每个文件都在OS X中具有其位置。表1-2列出了OS X安装中的一些顶级目录以及每个文件包含的内容类型

要点: 用户Documents和目录中的文件Desktop应仅反映用户创建并直接使用的文档。类似地,媒体目录应仅包含用户的媒体文件。这些目录绝不能用于存储应用程序自动创建和管理的数据文件。如果您需要一个地方来存储自动生成的文件,请使用Library专门为此目的指定的目录。有关将文件放在库目录中的位置的信息,请参阅库目录存储应用程序特定的文件。
虽然表1-2中的目录是OS X用户看到的,但它们不是文件系统中存在的唯一目录。OS X隐藏许多目录,以防止用户访问他们不需要的文件。
沙盒OS X应用程序文件容器
沙箱中的OS X应用程序将所有的Application Support,Cache临时目录和其他相关文档存储在位于系统定义路径的目录中,您可以通过调用该NSHomeDirectory函数来获取这些文件。
有关详细信息,请参阅应用程序沙盒设计指南。
隐藏的文件和目录:简化用户体验
为了简化用户,Finder和一些特定的面向用户的界面(例如打开和保存面板)的体验,隐藏用户不应该使用的许多文件和目录。许多隐藏项是系统或应用程序特定的资源,用户不能(或不应该)直接访问。隐藏的文件和目录如下:
-
点目录和文件。任何以period(
.)字符开头的文件或目录都会自动隐藏。这个约定取自UNIX,它使用它来隐藏系统脚本和其他特殊类型的文件和目录。此类别中的两个特殊目录是.和..目录,它们分别是对当前目录和父目录的引用。 -
UNIX特定目录。此类别中的目录继承自传统的UNIX安装。它们是系统BSD层的重要组成部分,但对软件开发人员来说比最终用户更有用。一些更重要的隐藏目录包括:
-
/bin- 包含基本的命令行二进制文件。通常,您可以从命令行脚本执行这些二进制文件。 -
/dev- 包含必要的设备文件,如连接硬件的安装点。 -
/etc- 包含主机特定的配置文件。 -
/sbin- 包含必要的系统二进制文件。 -
/tmp- 包含由应用和系统创建的临时文件。 -
/usr- 包含非必需的命令行二进制文件,库,头文件和其他数据。 -
/var- 包含日志文件和内容可变的其他文件。(通常使用控制台应用查看日志文件。)
-
-
显式隐藏的文件和目录。Finder可能会隐藏用户不应直接访问的特定文件或目录。最显着的例子是
/Volumes目录,其中包含本地文件系统中从命令行安装的每个磁盘的子目录。(Finder提供了用于访问本地磁盘的不同用户界面。)在OS X 10.7及更高版本中,Finder还隐藏~/Library目录,即Library位于用户主目录中的目录。 -
包和包。软件包和软件包是Finder向用户呈现的目录,就像它们是文件一样。软件包隐藏可执行文件(例如应用程序)的内部工作,只是呈现可以轻松移动到文件系统周围的单个实体。类似地,包允许应用程序实现由多个单独文件组成的复杂文档格式,同时仍然向用户呈现似乎是单个文档。
虽然Finder和其他系统界面从用户隐藏文件和目录,但Cocoa接口NSFileManager不过滤掉用户通常不可见的文件或目录。因此,使用这些接口的代码理论上具有文件系统及其内容的完整视图。(当然,一个进程只能访问那些具有适当权限的文件和目录)。
文件和目录可以有替代名称
在某些情况下,Finder会向用户显示与文件系统中显示的实际名称不匹配的文件或目录名称。这些名称称为显示名称,仅在向用户显示文件和目录信息时由Finder和特定系统组件(例如打开和保存面板)使用。显示名称通过以更友好的方式呈现用户的内容来改善用户体验。例如,OS X在以下情况下使用显示名称:
-
本地化名称。系统为许多系统目录提供本地化名称,例如,,,。应用程序可以类似地为其自身和其创建的任何目录提供本地化名称。
ApplicationsLibraryMusicMovies -
文件名扩展隐藏。默认情况下,系统隐藏所有文件的文件扩展名。用户可以更改选项,但是当文件名扩展隐藏有效时,不显示文件名中的最后一个周期之后的字符(和句点本身)。
显示名称不影响文件系统中文件的实际名称。在使用文件系统接口打开或操作项目时,以编程方式访问文件或目录的代码必须指定项目的实际名称。应用程序唯一应该使用显示名称的时间是向用户显示文件或目录的名称。您可以使用的displayNameAtPath:方法获取任何文件或目录的显示名称NSFileManager。
重要提示: 您的代码不应允许用户直接修改显示名称。当您希望用户指定文件的名称时,使用保存面板。
有关如何本地化您的应用程序创建的目录的信息,请参阅文件系统高级编程主题。有关本地化应用内容的详细信息,请参阅国际化和本地化指南。
库目录存储应用程序特定的文件
该Library目录是应用程序和其他代码模块存储其自定义数据文件的位置。无论您是为iOS还是OS X编写代码,理解目录的Library结构都很重要。在某些特定情况下,您可以使用此目录来存储数据文件,缓存,资源,首选项,甚至用户数据。
在Library整个系统中有几个目录,但只有几个你的代码应该需要访问:
-
Library在当前主目录中 - 这是您使用最多的目录的版本,因为它是包含所有用户特定文件的目录。在iOS中,Library放置在应用程序数据包内。在OS X中,它是应用程序的沙箱目录或当前用户的主目录(如果应用程序不在沙箱中)。 -
/Library(仅限OS X) - 用户之间共享资源的应用程序在此版本的目录中存储这些Library资源。沙箱应用程式不允许使用这个目录。 -
/System/Library(仅限OS X) - 此目录保留供Apple使用。
选择要使用的库目录的哪个版本后,您仍然需要知道在哪里存储文件。Library目录本身包含几个子目录,将应用程序特定的内容细分为几个着名的类别。表1-3列出了您可能使用的最常见的子目录。虽然OS X中的库目录包含比列出的子目录更多的子目录,但大多数子目录仅由系统使用。如果你想要一个更完整的子目录列表,请参阅OS X库目录详细信息。
Library子目录

iCloud文件存储容器
iCloud提供了一个结构化系统,用于存储使用iCloud的应用程序的文件:
-
应用程序具有用于存储其本机文件的主iCloud容器目录。他们还可以访问其应用程序权利中列出的辅助iCloud容器目录。
-
在每个容器目录中,文件被分隔为“文档”和数据。位于
Documents子目录(或其子目录中的一个)中的每个文件或文件包都作为可单独删除的单独文档呈现给用户(通过OS X和iOS中的iCloud UI)。任何不在Documents其中或其子目录中的任何内容将被视为数据,并在iCloud UI中显示为单个条目。
用户在应用程序的用户界面中创建和查看的文档(例如Pages,Numbers和Keynote中的文档浏览器)应存储在Documents目录中。可能进入目录的文件的另一个例子Documents是保存的游戏,也是因为它们是应用程序可能提供某种选择方法的东西。
应用程序不希望用户直接查看或修改的任何内容都应放在Documents目录外。应用程序可以在容器目录中创建任何子目录,以便他们可以根据需要排列私有文件。
应用程序在iCloud容器目录中创建文件和目录的方式与创建本地文件和目录的方式完全相同。并且保存所有文件的属性,如果他们向文件添加扩展属性,这些属性也被复制到iCloud和用户的其他设备。
iCloud容器还允许存储可以轻松访问的键值对,而无需创建文档格式。
系统如何识别文件中内容的类型
有两种主要技术用于识别文件中的内容类型:
-
统一类型标识符(UTI)
-
文件扩展名
统一类型标识符是唯一标识被认为具有“类型”的实体的类的字符串.UTI为所有应用和服务可以识别和依赖的数据提供一致的标识符。它们也比大多数其他技术更灵活,因为您可以使用它们来表示任何类型的数据,而不仅仅是文件和目录。UTI的示例包括:
-
public.text- 标识文本数据的公共类型。 -
public.jpeg- 标识JPEG图像数据的公共类型。 -
com.apple.bundle- 标识软件包目录的Apple类型。 -
com.apple.application-bundle- 标识捆绑应用的Apple类型。
每当基于UTI的接口可用于指定文件类型时,您应该优先于任何其他接口。许多OS X接口允许您指定与要使用的文件或目录对应的UTI。例如,在“打开”面板中,您可以将UTI用作文件过滤器,并将用户选择的文件类型限制为应用程序可以处理的文件类型。几个AppKit类,包括,和,和支持UTI。在iOS中,UTI仅用于指定粘贴板类型。NSDocumentNSPasteboardNSImage
系统确定给定文件的UTI的一种方式是通过查看其文件扩展名。文件扩展名是附加到文件末尾并与主文件名以句点分隔的字符串。每个唯一的字符串标识特定类型的文件。例如,.strings扩展识别具有可本地化字符串数据的资源文件,而.png扩展识别具有便携式网络图形格式的图像数据的文件。
如果您的应用定义了自定义文件格式,则应在应用Info.plist文件中注册这些格式和任何相关的文件扩展名。CFBundleDocumentTypes键指定您的应用程序识别并能够打开的文件格式。任何自定义文件格式的条目应包括文件扩展名和与文件内容相对应的UTI。系统使用该信息将具有适当类型的文件定向到您的应用程序。
有关UTI及其使用方法的更多信息,请参阅统一类型标识符概述。有CFBundleDocumentTypes关键的详细信息 ,请参阅信息属性列表键参考。
安全:保护您创建的文件
因为所有用户数据和系统代码都存储在磁盘上,保护文件和文件系统的完整性是一项重要工作。因此,有几种方法来保护内容并防止其被其他进程窃取或损坏。
有关使用文件时的安全编码实践的一般信息,请参阅安全编码指南。
沙箱限制伤害的蔓延
在iOS和OS X v10.7及更高版本中,沙箱阻止应用程序写入文件系统中不应写入的部分。每个沙盒应用程序接收一个或多个容器,它可以写入。应用程式无法写入其他应用程式的容器或沙箱以外的大多数目录。这些限制限制了在应用程序的安全性被破坏的情况下可能造成的潜在损害。
为OS X v10.7及更高版本编写应用程序的开发人员被鼓励将他们的应用程序放在沙盒中以增强安全性。iOS应用程序的开发人员不必将其应用程序显式地放置在沙盒中,因为系统会在安装时自动为其执行。
有关沙箱及其对文件系统访问的限制类型的更多信息,请参阅Mac App Programming Guide和App Sandbox设计指南。
权限和访问控制列表控制对文件的所有访问
对文件和目录的访问由访问控制列表(ACL)和BSD权限的混合控制。访问控制列表是一组细粒度控制,用于精确定义可以和不能对文件或目录以及由谁执行的操作。使用访问控制列表,您可以向单个用户授予对给定文件或目录的不同级别的访问权限。相比之下,BSD权限只允许您授予对三类用户的访问权限:文件的所有者,您指定的一组用户和所有用户。有关详细信息,请参阅安全概述。
由于iOS应用程序始终在沙盒中运行,系统会为每个应用程序创建的文件分配特定的ACL和权限。但是,OS X应用程序可以使用身份服务来管理他们有权访问的文件的访问控制列表。有关如何使用身份服务(和协作框架)的信息,请参阅身份服务编程指南。
可以在磁盘上加密文件
OS X和iOS都支持在磁盘上加密文件:
-
iOS。iOS应用程序可以指定其想要在磁盘上加密的文件。当用户解锁包含加密文件的设备时,系统创建允许应用访问其加密文件的解密密钥。然而,当用户锁定设备时,解密密钥被破坏以防止对文件的未授权访问。
-
OS X.用户可以使用磁盘实用程序应用程序加密卷的内容。(他们也可以只从安全和隐私系统首选项加密启动卷。)加密磁盘的内容只有在计算机运行时才可用于应用程序。当用户使计算机休眠或将其关闭时,解密密钥被破坏以防止对盘的内容的未授权访问。
在iOS中,利用基于磁盘加密的应用程序需要在用户锁定设备时停止使用加密文件。由于锁定设备会销毁解密密钥,因此只有在设备解锁时才能访问加密文件。如果您的iOS应用程序可以在设备锁定时在后台运行,则必须这样做,无需访问任何加密文件。由于OS X中的加密磁盘在计算机运行时始终可访问,因此OS X应用程序不需要执行任何特殊操作来处理磁盘级加密。
有关在iOS中使用加密文件的详细信息,请参阅iOS 应用程序编程指南。
同步确保文件相关代码的鲁棒性
文件系统是由第三方应用和系统应用共享的资源。由于多个应用程序能够同时访问文件和目录,因此一个应用程序可能会进行更改,使第二个应用程序的文件系统视图过时。如果第二个应用程序不准备处理这样的更改,它可能进入未知状态,甚至崩溃。如果您的应用程序依赖于特定文件的存在,您可以使用同步接口通知这些文件的更改。
文件系统同步主要是OS X中的一个问题,用户可以直接使用Finder或任何数量的其他应用程序同时操作文件。幸运的是,OS X提供了以下接口来帮助解决同步问题:
-
文件协调器。在OS X v10.7及更高版本中,文件协调器是将细粒度同步支持直接并入应用程序对象的一种方式; 请参阅文件协调器和演示者的角色。
-
FSEvents。在OS X v10.5及更高版本中,文件系统事件允许您监视对目录或其内容的更改; 请参阅文件系统事件编程指南。
文件,并发和线程安全
因为文件相关操作涉及与硬盘交互,因此与大多数其他操作相比,iOS和OS X中的大多数与文件相关的界面都设计为并发性。几种技术将异步操作并入其设计中,并且大多数技术可以从调度队列或次级线程安全地执行。表1-4列出了本文档中讨论的一些关键技术,以及它们是否可以从特定线程或任何线程安全使用。有关任何接口的功能的特定信息,请参阅该接口的参考文档。
|
课程/技术 |
笔记 |
|---|---|
|
对于大多数任务,可以安全地 |
|
|
大中央调度 |
GCD本身可以安全地使用任何线程。但是,你仍然负责以线程安全的方式编写块。 |
|
|
您用于读取和写入文件数据的大多数Foundation对象可以从任何单个线程使用,但不应同时从多个线程使用。 |
|
打开和保存面板 |
因为它们是您的用户界面的一部分,所以您应该总是显示和操作应用程序主线程中的打开和保存面板。 |
|
POSIX例程 |
用于操作文件的POSIX例程通常被设计为从任何线程安全操作。有关详细信息,请参阅相应的手册页。 |
|
用于指定路径的不可变对象可以安全地从任何线程使用。因为它们是不可变的,你也可以从多个线程同时引用它们。当然,这些对象的可变版本应该一次只使用一个线程。 |
|
|
|
枚举器对象可以安全地从任何单个线程使用,但不应同时从多个线程使用。 |
即使您使用线程安全的接口来处理文件,当多个线程或多个进程尝试对同一个文件执行操作时,仍然会出现问题。虽然有保护措施以防止多个客户端同时修改文件,但这些安全措施并不总是保证始终对文件进行独占访问。(也不应尝试阻止其他进程访问共享文件。)要确保您的代码知道对共享文件所做的更改,请使用文件协调器来管理对这些文件的访问。有关文件协调器的详细信息,请参阅文件协调器和演示器的角色
以上信息翻译至苹果官方文档. 地址:https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW2

浙公网安备 33010602011771号