沙盒机制

概念

iOS 沙盒机制是一种安全策略,它将每个应用程序的数据和资源阻隔在一个专用目录中,约束了应用程序访问其他应用程序或体系文件的能力,然后保护了用户数据和体系安全.

目录结构

For security purposes, an iOS app’s interactions with the file system are limited to the directories inside the app’s sandbox directory. During installation of a new app, the installer creates a number of container directories for the app inside the sandbox directory. Each container directory has a specific role. The bundle container directory holds the app’s bundle, whereas the data container directory holds data for both the app and the user. The data container directory is further divided into a number of subdirectories that the app can use to sort and organize its data. The app may also request access to additional container directories—for example, the iCloud container—at runtime.

大约内容讲的是出于安全考虑,iOS应用只能在当时APP的沙盒目录下与文件体系进行交互(读取、创立、删去等).在APP装置时,体系会在当时APP的沙盒目录下创立不同类型不同功能的容器目录(Bundle、Data、iCloud).Data Container又进一步被划分为Documents、Library、temp、System Data.沙盒目录结构如下图所示:

iOS文件系统

各目录描绘如下图所示:

iOS文件系统

下面介绍一些关于文件体系中常用的API.

创立NSFileManager

// 1.创立实例
NSFileManager *fileManager = [[NSFileManager alloc] init];
// 2.获取单例
NSFileManager *fileManager = [NSFileManager defaultManager];
// 3.自定义
自定义NSFileManager完成一些自定义功能.

NSFileManager有一个delegate(NSFileManagerDelegate)特点,完成该协议的对象能够对文件的复制、移动等操作做更多的逻辑处理,同时能在这些操作产生过错时做一些容错的处理.

// 该协议用于操控文件/文件夹,是否答应移动、删去、复制.以及答应这些操作产生过错时进行额外的处理.
@protocol NSFileManagerDelegate <NSObject>
// 操控是否答应该操作:
// 以下每种办法都有一个NSURL和NSString的版本,URL和Path同效果的办法只会调用一次,而且优先调用URL的办法.假如两个办法都没完成,则完成体系的默许值YES.
// 其中srcURL/srcPath分别代表原(文件/文件夹)途径URL(file://xxx)/途径(xxx). xxx为完好途径.
// 其中dstURL/dstPath分别代表方针(文件/文件夹)途径URL(file://xxx)/途径(xxx). xxx为完好途径.
// 过错处理:
// 以下每种办法都有一个NSURL和NSString的版本,URL和Path同效果的办法只会调用一次,而且优先调用URL的办法.假如两个办法都没完成,则不处理过错.
@optional
/// Moving an Item
// 在移动文件/文件夹前调用,操控是否答应移动操作
// 假如两个办法都没有完成,体系默许YES即答应移动. 
- (BOOL)fileManager:(NSFileManager *)fileManager shouldMoveItemAtURL:(NSURL *)srcURL toURL:(NSURL *)dstURL;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldMoveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
// 移动失利时调用 处理过错信息
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error movingItemAtURL:(NSURL *)srcURL toURL:(NSURL *)dstURL;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error movingItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
/// Copy an Item
// 在复制文件/文件夹前调用,操控是否答应复制操作
// 假如两个办法都没有完成,体系默许YES即答应复制. 
- (BOOL)fileManager:(NSFileManager *)fileManager shouldCopyItemAtURL:(NSURL *)srcURL toURL:(NSURL *)dstURL;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldCopyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
// 复制失利时调用 处理过错信息
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error copyingItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error copyingItemAtURL:(NSURL *)srcURL toURL:(NSURL *)dstURL;
/// Delete an Item
// 在复制文件/文件夹前调用,操控是否答应删去操作
// 假如两个办法都没有完成,体系默许YES即答应删去. 
- (BOOL)fileManager:(NSFileManager *)fileManager shouldRemoveItemAtPath:(NSString *)path;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldRemoveItemAtURL:(NSURL *)URL;
// 删去失利时调用 处理过错信息
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error removingItemAtPath:(NSString *)path;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error removingItemAtURL:(NSURL *)URL;
@end

考虑线程安全的问题,假如需要完成NSFileManagerDelegate协议,通常是新创立NSFileManager实例或是承继NSFileManager后新建实例,确保一个一个实例仅对应一个delegate.

创立文件/文件夹

/// 文件
// 创立文件,会掩盖已存在的文件内容.
// path: 文件途径.
// data: 文件内容.
// attr: 文件特点.例如:设置文件夹可读写权限、文件夹创立日期中.传入nil,则运用体系默许的装备.
// return: YES:文件存在或创立成功. NO:文件创立失利
- (BOOL)createFileAtPath:(NSString *)path 
                contents:(NSData *)data 
              attributes:(NSDictionary<NSFileAttributeKey, id> *)attr;
/// 文件夹
// url: 文件夹途径URL.
// createIntermediate: 是否主动创立目录中不存在的中心目录,假如设置为NO,只是会创立途径的最终一级目录,若恣意中心途径不存在,该办法会回来NO.同时假如恣意中心目录是文件也会失利.
// attributes: nil,则运用体系默许的装备.
// error: 过错信息.
// YES: 文件夹创立成功.YES: createIntermediates为YES且文件夹已存在. NO: 过错产生.
- (BOOL)createDirectoryAtURL:(NSURL *)url 
 withIntermediateDirectories:(BOOL)createIntermediates 
                  attributes:(NSDictionary<NSFileAttributeKey, id> *)attributes 
                       error:(NSError * _Nullable *)error;
// 同上
- (BOOL)createDirectoryAtPath:(NSString *)path 
  withIntermediateDirectories:(BOOL)createIntermediates 
                   attributes:(NSDictionary<NSFileAttributeKey, id> *)attributes 
                        error:(NSError * _Nullable *)error;

其他办法写入文件:NSData、NSString、All kinds Of Collections (写入plist).

删去文件/文件夹

删去操作是指将文件/文件夹从指定目录移除去.

// 以file://xxx的方式删去文件/文件夹.
// srcURL: 原文件/文件夹目录URL
// dstURL: 方针目录URL.
// error: 过错信息.
// return: YES: 移动成功或URL为nil或delegate中止删去操作. NO: 过错产生.
- (BOOL)removeItemAtURL:(NSURL *)URL 
                  error:(NSError * _Nullable *)error;
// 同上,不过传入的是xxx完好途径.
- (BOOL)removeItemAtPath:(NSString *)path 
                   error:(NSError * _Nullable *)error;
// 将文件/文件夹移入到废纸篓,适用于Macos.iOS上运用会失利.
- (BOOL)trashItemAtURL:(NSURL *)url 
      resultingItemURL:(NSURL * _Nullable *)outResultingURL 
                 error:(NSError * _Nullable *)error;
// 留意: 
// 1.假如删去的是文件夹,则会删去文件夹中一切的内容. 
// 2.删去文件前会调用delegate的-[fileManager:shouldRemoveItemAtURL:]或-[fileManager:shouldRemoveItemAtPath:]办法,用于操控能否删去.假如都没有完成,则默许能够删去. 
// 3.删去失利时会调用delegate的-[fileManager:shouldProceedAfterError:removingItemAtURL:]或-[fileManager:shouldProceedAfterError:removingItemAtPath:]办法,用于处理过错. 
// 假如2个办法都没有完成则删去失利.而且删去办法会回来相应的error信息. 
// 办法回来YES会以为删去成功,回来NO则删去失利,删去办法接纳error信息.

文件/文件夹是否存在


// path: 文件/文件夹途径.
// isDirectory: YES: 当时为文件夹. NO: 当时为文件.
// return: YES: 文件/文件夹存在. NO: 文件/文件夹不存在.
- (BOOL)fileExistsAtPath:(NSString *)path 
             isDirectory:(BOOL *)isDirectory;
// 同上,不过不能判断当时是文件还是文件夹.
- (BOOL)fileExistsAtPath:(NSString *)path;

遍历文件夹

有时候咱们并不知道文件的具体途径,此刻就需要遍历文件夹去拼接完好途径.

/// 浅度遍历: 回来当时目录下的文件/文件夹(包含躲藏文件).
// 默许带上了options: NSDirectoryEnumerationSkipsSubdirectoryDescendants.
// NSDirectoryEnumerationIncludesDirectoriesPostOrder无效,因为不会遍历子目录.
- (nullable NSArray<NSString *> *)contentsOfDirectoryAtPath:(NSString *)path 
																							        error:(NSError **)error
// url: 文件途径.
// keys: 预恳求每个文件特点的key数组.假如不想预恳求则传入@[],传nil会有默许的预恳求keys.
// options: 遍历时可选掩码.
// error: 过错信息.
- (nullable NSArray<NSURL *> *)contentsOfDirectoryAtURL:(NSURL *)url 
														 includingPropertiesForKeys:(nullable NSArray<NSURLResourceKey> *)keys 
																								options:(NSDirectoryEnumerationOptions)mask 
																									error:(NSError **)error
/// 深度遍历(递归遍历): 回来当时目录下的一切文件/文件夹(包含躲藏文件).
- (nullable NSDirectoryEnumerator<NSString *> *)enumeratorAtPath:(NSString *)path
- (nullable NSDirectoryEnumerator<NSURL *> *)enumeratorAtURL:(NSURL *)url 
																	includingPropertiesForKeys:(nullable NSArray<NSURLResourceKey> *)keys 
																										 options:(NSDirectoryEnumerationOptions)mask 
																								errorHandler:(nullable BOOL (^)(NSURL *url, NSError *error))handler
- (NSArray<NSString *> *)subpathsOfDirectoryAtPath:(NSString *)path 
                                             error:(NSError * _Nullable *)error;
- (NSArray<NSString *> *)subpathsAtPath:(NSString *)path;

获取文件夹

// iOS基本上都是运用NSUserDomainMask.
// 获取指定目录类型和mask的文件夹.类似于NSSearchPathForDirectoriesInDomains办法.
// 常用的directory:
// NSApplicationSupportDirectory -> Library/Application Support.
// NSCachesDirectory -> /Library/Caches.
// NSLibraryDirectory -> /Library.
- (NSArray<NSURL *> *)URLsForDirectory:(NSSearchPathDirectory)directory 
														 inDomains:(NSSearchPathDomainMask)domainMask
// 获取指定directory & domainMask下的文件夹.
// domain: 不能传入NSAllDomainsMask.
// url: 仅当domain = NSUserDomainMask & directory = NSItemReplacementDirectory时有效.
// shouldCreate: 文件不存在时 是否创立.
- (NSURL *)URLForDirectory:(NSSearchPathDirectory)directory 
                  inDomain:(NSSearchPathDomainMask)domain 
         appropriateForURL:(NSURL *)url 
                    create:(BOOL)shouldCreate 
                     error:(NSError * _Nullable *)error;
// 同上
FOUNDATION_EXPORT NSArray<NSString *> *NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);
// 获取/temp目录
FOUNDATION_EXPORT NSString *NSTemporaryDirectory(void);
// 获取沙盒根目录
FOUNDATION_EXPORT NSString *NSHomeDirectory(void);

设置和获取文件/文件夹特点

// 获取指定目录下文件/文件夹的特点[NSFileAttributeKey].(https://developer.apple.com/documentation/foundation/nsfileattributekey).
- (nullable NSDictionary<NSFileAttributeKey, id> *)attributesOfItemAtPath:(NSString *)path 
                                                                    error:(NSError **)error;
// 为指定目录文件/文件夹设置特点.
- (BOOL)setAttributes:(NSDictionary<NSFileAttributeKey, id> *)attributes ofItemAtPath:(NSString *)path error:(NSError * _Nullable *)error;
// 基于NSDictionary供给的便当办法 //
@interface NSDictionary<KeyType, ObjectType> (NSFileAttributes)
// 文件巨细
- (unsigned long long)fileSize;
// 文件创立日期
- (nullable NSDate *)fileCreationDate;
// 文件修改日期
- (nullable NSDate *)fileModificationDate;
// 文件类型.NSFileAttributeType
- (nullable NSString *)fileType;
// 文件权限掩码
- (NSUInteger)filePosixPermissions; // 位掩码 可见文件 _s_ifmt.h eg:S_IRWXU
/* File mode */
/* Read, write, execute/search by owner */
#define S_IRWXU         0000700         /* [XSI] RWX mask for owner */
#define S_IRUSR         0000400         /* [XSI] R for owner */
#define S_IWUSR         0000200         /* [XSI] W for owner */
#define S_IXUSR         0000100         /* [XSI] X for owner */
/* Read, write, execute/search by group */
#define S_IRWXG         0000070         /* [XSI] RWX mask for group */
#define S_IRGRP         0000040         /* [XSI] R for group */
#define S_IWGRP         0000020         /* [XSI] W for group */
#define S_IXGRP         0000010         /* [XSI] X for group */
/* Read, write, execute/search by others */
#define S_IRWXO         0000007         /* [XSI] RWX mask for other */
#define S_IROTH         0000004         /* [XSI] R for other */
#define S_IWOTH         0000002         /* [XSI] W for other */
#define S_IXOTH         0000001         /* [XSI] X for other */
// 当时文件/文件夹所在的文件体系编号
- (NSInteger)fileSystemNumber;
这两个办法能够拼接文件的引用URL -> file:///.file/id=fileSystemNumber.fileSystemFileNumber
// 当时文件/文件夹在文件体系中的编号
- (NSUInteger)fileSystemFileNumber;
// 是否是躲藏文件
- (BOOL)fileExtensionHidden;
...
@end

移动文件/文件夹

移动操作是将文件从一个方位移动到另一个方位.

// 以file://xxx的方式移动文件/文件夹.
// srcURL: 原文件/文件夹方位URL.
// dstURL: 方针方位URL.
// error: 过错信息.
// return: YES: 移动成功或manager的delegate中止移动操作. NO: 过错产生.
- (BOOL)moveItemAtURL:(NSURL *)srcURL 
                toURL:(NSURL *)dstURL 
                error:(NSError * _Nullable *)error;
// 同上,不过传入的是xxx完好途径.
- (BOOL)moveItemAtPath:(NSString *)srcPath 
                toPath:(NSString *)dstPath 
                 error:(NSError * _Nullable *)error;
// 留意:
// 1.srcURL/srcPath、dstURL/dstPath恣意为nil会crash.
// 2.假如方针目录文件已存在会被掩盖.
// 3.移动文件前会调用delegate的-[fileManager:shouldMoveItemAtURL:toURL:]或-[fileManager:shouldMoveItemAtPath:toPath:]办法,用于操控能否移动.假如都没有完成,则默许能够移动.
// 4.移动失利时会调用delegate的-[fileManager:shouldMoveItemAtURL:toURL:]或-[fileManager:shouldMoveItemAtPath:toPath:]办法,用于处理过错.
// 假如2个办法都没有完成则移动失利.而且移动办法会回来相应的error信息.
// 办法回来YES会以为移动成功,回来NO则移动失利,移动办法接纳error信息.

复制文件/文件夹

复制操作是将原文件从一个方位copy到另一个方位,类似于复制粘贴.

// 以file://xxx的方式复制文件/文件夹.
// srcURL: 原文件/文件夹/方位URL.
// dstURL: 方针方位URL.
// error: 过错信息.
// return: YES: 复制成功或manager的delegate中止复制操作. NO: 过错产生.
- (BOOL)copyItemAtURL:(NSURL *)srcURL 
                toURL:(NSURL *)dstURL 
                error:(NSError * _Nullable *)error;
// 同上,不过传入的是xxx完好途径.
- (BOOL)copyItemAtPath:(NSString *)srcPath 
                toPath:(NSString *)dstPath 
                 error:(NSError * _Nullable *)error;
// 留意:
// 1.srcURL/srcPath、dstURL/dstPath恣意为nil会crash.
// 2.假如方针目录已经存在则会产生过错.
// 3.复制文件前会调用delegate的-[fileManager:shouldCopyItemAtURL:toURL:]或-[fileManager:shouldCopyItemAtPath:toPath:]办法,用于操控能否复制.假如都没有完成,则默许能够复制.
// 4.复制失利时会调用delegate的-[fileManager:shouldProceedAfterError:copyingItemAtURL:toURL:]或-[fileManager:shouldProceedAfterError:copyingItemAtPath:toPath:]办法,用于处理过错.
// 假如2个办法都没有完成则复制失利.而且复制办法会回来相应的error信息.
// 办法回来YES会以为复制成功,回来NO则复制失利,复制办法接纳error信息.

参考资料

  1. developer.apple.com/library/arc…
  2. developer.apple.com/documentati…

好物引荐

  1. OpenSim:用于快速定位模拟器中项目沙盒目录.

  2. Flex:用于真机或模拟器Debug环境下调试.