Logo
Section 1 / 3

在 Swift 中操作目录

了解如何编写 Swift 代码来操作文件系统,包括更改、创建和删除目录。

检查点

在 Swift 中操作目录

了解如何编写 Swift 代码来操作文件系统,包括更改、创建和删除目录。

本课的目标是概述如何操作本地文件系统目录。涵盖的主题包括:识别用户的文档目录和临时目录、查找当前工作目录、创建、删除和重命名目录,以及获取目录内容的列表。在完成目录管理主题后,下一课将介绍文件处理。

FileManager、FileHandle 和 Data 类

Foundation 框架提供了三个在处理文件和目录时不可或缺的类:

  • FileManager:FileManager 类可用于执行基本的文件和目录操作,例如创建、移动、读取和写入文件,以及读取和设置文件属性。此外,该类还提供了一些方法,用于(除其他任务外)识别当前工作目录、切换到新目录、创建目录,以及列出目录的内容。
  • FileHandle:FileHandle 类用于对文件执行低级别操作,例如定位到文件中的特定位置,按指定字节数块读取和写入文件内容,以及向现有文件追加数据。
  • Data:Data 类提供了一个有用的存储缓冲区,可用于读取文件内容,或从动态存储的数据写入文件。

所有这些类都属于 Foundation 框架,因此在处理文件和目录时必须导入该框架:

1import Foundation

理解 Swift 中的路径名

Swift 使用标准的 UNIX 命名约定来定义路径名。因此,路径的每个组成部分之间用正斜杠(/)分隔。路径名开头的 / 指的是文件系统的根目录。

以 / 开头的路径称为绝对路径,因为它们相对于根目录指定了文件系统的位置。例如,/home/demo 是一个绝对路径。

不以斜杠开头的路径则被解释为相对于当前工作目录。例如,如果当前工作目录是 /home/demo,而路径名为 mapdata/local.xml,那么该文件的完整且绝对路径等价于 /home/demo/mapdata/local.xml。

获取默认 FileManager 对象的引用

FileManager 类包含一个名为 default 的属性,用于获取应用程序默认文件管理器实例的引用:

1let filemgr = FileManager.default

获取对象引用后,即可开始使用它来操作文件和目录。

识别当前工作目录

当应用程序首次加载时,它将在当前工作目录中运行。该位置取决于操作系统以及应用程序的启动方式。iOS 应用程序的工作目录会被设置为用户的根目录(/)。而从 Linux 命令行运行的 Swift 程序,则会被设置为程序启动时所在的目录。

可以通过访问文件管理器对象的 currentDirectoryPath 属性随时识别当前工作目录。例如,以下代码片段用于识别当前工作目录:

1import Foundation 2 3let filemgr = FileManager.default 4let currentPath = filemgr.currentDirectoryPath 5 6print("当前目录 = \(currentPath)")

识别文档目录

大多数操作系统都有“文档”目录的概念。例如,在 macOS 上,它可能位于 /Users/<username>/Documents,而在 Ubuntu Linux 上,它可能位于 /home/<username>/Documents。

在 iOS 上,设备上的每个应用都有自己的私有文档目录和临时目录,允许其读写数据。实际上,确切位置还会因应用运行在真实 iPhone 或 iPad 设备上,还是在 iOS 模拟器中而有所不同。

鉴于这些差异,唯一可靠地找到用户文档目录路径的方法是向 Swift 文件管理器查询。

可以通过调用文件管理器的方法 urls(for:) 来获取应用程序的文档目录,传入参数 .documentDirectory 表示需要文档目录的路径。.userDomainMask 参数表示我们正在查找位于应用程序主目录中的文档目录。该方法返回一个数组形式的结果对象,因此我们可以如下获取当前应用程序文档目录的路径:

1let dirPaths = filemgr.urls(for: .documentDirectory, in: .userDomainMask) 2 3let docsDir = dirPaths[0].path 4 5print("文档目录路径 = \(docsDir)")

识别临时目录

除了文档目录外,大多数操作系统还提供一个临时目录,用于临时文件存储。当前应用程序的临时目录路径可通过调用 NSTemporaryDirectory C 函数获得:

1let tmpDir = NSTemporaryDirectory() 2 3print("临时目录 = \(tmpDir)")

更改目录

运行中的应用程序的当前工作目录可以通过调用 FileManager 实例的 changeCurrentDirectoryPath 方法进行更改。目标目录路径作为参数以字符串对象的形式传递给该实例方法。请注意,此方法返回布尔值 true 或 false,表示请求的目录更改是否成功。返回 false 通常表示指定的目录不存在,或应用程序缺少相应的访问权限:

1let tmpDir = NSTemporaryDirectory() 2 3print("更改前的当前目录 = \(filemgr.currentDirectoryPath)") 4 5if filemgr.changeCurrentDirectoryPath(tmpDir) { 6 print("更改后的当前目录 = \(filemgr.currentDirectoryPath)") 7} else { 8 print("无法更改为目录 \(tmpDir)") 9}

在上述示例中,首先获取用户临时目录的路径,然后将其作为参数传递给文件管理器对象的 changeCurrentDirectoryPath 方法,从而将当前工作目录更改为该位置。

列出目录内容

可以使用 contentsOfDirectory(atPath:) 方法获取指定目录中包含的文件列表。该方法接收目录路径作为参数,并返回一个数组对象,其中包含该目录中的文件和子目录名称。以下示例获取 /SampleCode 目录的内容列表并逐项显示:

1do { 2 let filelist = try filemgr.contentsOfDirectory(atPath: "/SampleCode") 3 4 for filename in filelist { 5 print(filename) 6 } 7} catch let error { 8 print("错误: \(error.localizedDescription)") 9}

创建新目录

在 Swift 中,使用 FileManager 类的 createDirectory(atPath:) 实例方法创建新目录。该方法以新目录的路径作为第一个参数,创建失败时会抛出错误。该方法的第二个参数定义是否自动创建任何中间目录层级。例如,如果我们希望创建路径为 /tmp/mydata/maps 的目录,而 mydata 子目录尚不存在,将 withIntermediateDirectories 参数设为 true 将会自动创建该目录,然后再在其内部创建 maps 子目录。如果此参数设为 false,则创建尝试将失败,因为 mydata 不存在,且我们未授权自动创建它。

该方法还接受一组属性作为额外参数,用于新目录。指定 nil 将使用默认属性。

以下代码片段在 /SampleCode 目录中创建一个名为 DATA 的新子目录:

1let newDir = "/SampleCode/DATA" 2 3do { 4 try filemgr.createDirectory(atPath: newDir, 5 withIntermediateDirectories: true, attributes: nil) 6} catch let error as NSError { 7 print("错误: \(error.localizedDescription)") 8} 9 10// 输出目录内容以验证 DATA 子目录的创建 11 12do { 13 let filelist = try filemgr.contentsOfDirectory(atPath: "/SampleCode") 14 15 for filename in filelist { 16 print(filename) 17 } 18} catch let error { 19 print("错误: \(error.localizedDescription)") 20}

删除目录

可以使用 removeItem(atPath:) 方法从文件系统中删除一个已存在的目录,将要删除的目录路径作为参数传递。例如,要删除前面示例中创建的 DATA 目录,可以编写如下代码:

1do { 2 try filemgr.removeItem(atPath: newDir) 3} catch let error { 4 print("错误: \(error.localizedDescription)") 5} 6 7// 输出目录内容以验证 DATA 子目录的删除 8 9do { 10 let filelist = try filemgr.contentsOfDirectory(atPath: "/SampleCode") 11 12 for filename in filelist { 13 print(filename) 14 } 15} catch let error { 16 print("错误: \(error.localizedDescription)") 17}

课程小结

  • Swift 中的文件和目录处理涉及使用 FileManager、FileHandle 和 Data 类。

  • 在操作文件和目录之前,必须获取默认 FileManager 实例的引用。

  • FileManager 可用于识别用户的临时目录和文档目录。

  • FileManager 实例还可用于更改目录、创建和删除目录,以及生成目录内容列表。

测验

通过完成以下测验,测试你对 Swift 中文件系统目录操作的掌握程度。

练习

完成以下练习,将你对目录处理的知识付诸实践。

练习 1

修复以下代码中的编译错误:

练习

1let filemgr = FileManager.default

解答

1import Foundation // FileManager 类属于 Foundation 框架 2 3let filemgr = FileManager.default

练习 2

在以下示例中添加代码,以识别并显示当前工作目录:

练习

1import Foundation 2 3let filemgr = FileManager.default

解答

1import Foundation 2 3let filemgr = FileManager.default 4 5print("当前工作目录 = \(filemgr.currentDirectoryPath)")

练习 3

以下代码试图在一个尚未存在 /departments 目录的文件系统上创建路径为 /departments/accounts 的新子目录。

当前实现下,该代码无法成功创建子目录。请修改代码,使其能够成功创建:

练习

1import Foundation 2 3let filemgr = FileManager.default 4 5let newDir = "/departments/accounts" 6 7do { 8 try filemgr.createDirectory(atPath: newDir, 9 withIntermediateDirectories: false, attributes: nil) 10 } catch let error as NSError { 11 print("错误: \(error.localizedDescription)") 12}

解答

1import Foundation 2 3let filemgr = FileManager.default 4 5let newDir = "/departments/accounts" 6 7do { 8 // 由于 /departments 目录尚不存在,必须将 withIntermediateDirectories 参数设为 true 9 try filemgr.createDirectory(atPath: newDir, 10 withIntermediateDirectories: true, attributes: nil) 11 } catch let error as NSError { 12 print("错误: \(error.localizedDescription)") 13}

Quiz

单选题

路径 "data/files/xml" 属于以下哪种路径?

1 / 3

Swift 错误处理

使用 FileManager 在 Swift 中处理文件