测试已测试 | ✗ |
Lang语言 | SwiftSwift |
许可证 | MIT |
发布最新发布 | 2017年7月 |
SwiftSwift 版本 | 3.0 |
SPM支持 SPM | ✓ |
由 Amir Abbas Mousavian 维护。
该 Swift 库提供了一种统一处理本地和远程文件和目录的方法。
该库实现了 WebDAV、FTP、Dropbox、OneDrive 和 SMB2(不完整)以及本地文件。
所有功能都执行异步调用,不会阻塞您的主线程。
FileManager
的封装,增加了一些功能,如内置协调、搜索和读取文件的一部分。ownCloud
、Box.com
和 Yandex.disk
。onedrive.com
以及兼容(商业)服务器。可以在 swift-2 分支中找到旧的版本。
为了轻松获取最新更新,请在终端中使用此命令以克隆:
git clone https://github.com/amosavian/FileProvider
您可以使用此命令在 FileProvider 文件夹中更新您的库:
git pull
如果您有一个基于 Git 的项目,请在项目目录中使用此命令将此项目作为 submod
git submodule add https://github.com/amosavian/FileProvider
然后您可以执行以下任一操作:
将源文件夹复制到您的项目中,万事大吉!
将FileProvider.xcodeproj
拖放到您的 Xcode 工作区中,并将其框架添加到目标的嵌入式二进制文件中。
每个提供者都有一个特定的类,该类符合 FileProvider 协议,并具有相同的语法
针对 LocalFileProvider,如果您想处理Documents
文件夹
let documentsProvider = LocalFileProvider()
// Equals with:
let documentsProvider = LocalFileProvider(for: .documentDirectory, in: .userDomainMask)
// Equals with:
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let documentsProvider = LocalFileProvider(baseURL: documentsURL)
也适用于使用共享容器
let documentsProvider = LocalFileProvider(sharedContainerId: "group.yourcompany.appContainer")
// Replace your group identifier
之后您无法更改基本 URL。默认情况下,所有路径都与这个基本 URL 相关。
要初始化 iCloud Container 提供者,请参阅这里了解如何更新项目设置,然后使用以下代码,这将自动管理在容器中创建 Documents 文件夹
let documentsProvider = CloudFileProvider(containerId: nil)
对于远程文件提供者,可能需要进行身份验证
let credential = URLCredential(user: "user", password: "pass", persistence: .permanent)
let webdavProvider = WebDAVFileProvider(baseURL: URL(string: "http://www.example.com/dav")!, credential: credential)
如果要在 iOS 9+ / macOS 10.11+ 中连接不安全的 WebDAV (http) 服务器,您应该根据此指南禁用 App Transport Security (ATS)。
对于 Dropbox 和 OneDrive,用户是 clientID,密码是 Token,这两者都必须通过Dropbox 的 OAuth2 API获取。有一些库,例如p2/OAuth2或OAuthSwift,可以简化获取 Token 的过程。后者使用起来更简单,也更为推荐。
要交互 UI,设置 FileProvider
对象的 delegate 变量。
如果提供者支持的话,您可以使用 url(of:)
方法来获取直接访问 URL(本地或远程文件)
为了更新用户界面,请考虑使用委托方法而不是完成处理程序。委托方法保证在主线程中运行,以避免错误。
有三个方法可以表示操作是否失败,是否成功,以及操作已完成的百分比(适用于上传和下载操作)。
您的类应该符合 FileProviderDelegate
类。
override func viewDidLoad() {
documentsProvider.delegate = self as FileProviderDelegate
}
func fileproviderSucceed(_ fileProvider: FileProviderOperations, operation: FileOperationType) {
switch operation {
case .copy(source: let source, destination: let dest):
print("\(source) copied to \(dest).")
case .remove(path: let path):
print("\(path) has been deleted.")
default:
print("\(operation.actionDescription) from \(operation.source!) to \(operation.destination) succeed")
}
}
func fileproviderFailed(_ fileProvider: FileProviderOperations, operation: FileOperationType) {
switch operation {
case .copy(source: let source, destination: let dest):
print("copy of \(source) failed.")
case .remove:
print("file can't be deleted.")
default:
print("\(operation.actionDescription) from \(operation.source!) to \(operation.destination) failed")
}
}
func fileproviderProgress(_ fileProvider: FileProviderOperations, operation: FileOperationType, progress: Float) {
switch operation {
case .copy(source: let source, destination: let dest):
print("Copy\(source) to \(dest): \(progress * 100) completed.")
default:
break
}
}
注意:目前 fileproviderProgress()
委托方法不会被 LocalFileProvider
调用。
建议使用完成处理程序进行错误处理或结果处理。
您还可以实现 FileOperationDelegate
协议来控制文件操作(复制、移动/重命名、删除和链接)的行为,并决定哪些文件应该被删除,哪些不应该。
fileProvider(shouldDoOperation:)
方法在执行操作之前被调用。如果您想执行操作,则应返回 true
;如果您想停止该操作,则应返回 false
。
fileProvider(shouldProceedAfterError:, operation:)
会在文件操作期间发生错误时被调用。如果要在下一文件继续操作,则返回 true
;如果想要停止操作,则返回 false
。如果您不实现委托,默认值是 false
。
注意:在 LocalFileProvider
中,这些方法将递归地适用于目录及其子目录中的文件。
有一个 FileObject
类,持有关于文件的大小的创建日期等文件属性。您可以获取目录中文件的详细信息,或者获取一个文件的详细信息。
对于单个文件
documentsProvider.attributesOfItem(path: "/file.txt", completionHandler: {
attributes, error in
if let attributes = attributes {
print("File Size: \(attributes.size)")
print("Creation Date: \(attributes.creationDate)")
print("Modification Date: \(attributes.modifiedDate)")
print("Is Read Only: \(attributes.isReadOnly)")
}
})
要获取目录中文件的列表
documentsProvider.contentsOfDirectory(path: "/", completionHandler: {
contents, error in
for file in contents {
print("Name: \(attributes.name)")
print("Size: \(attributes.size)")
print("Creation Date: \(attributes.creationDate)")
print("Modification Date: \(attributes.modifiedDate)")
}
})
要获取存储空间的大小和已用/可用空间
func storageProperties(completionHandler: { total, used in
print("Total Storage Space: \(total)")
print("Used Space: \(used)")
print("Free Space: \(total - used)")
})
-1
,已用空间为0
documentsProvider.currentPath = "/New Folder"
// now path is ~/Documents/New Folder
然后,您可以传递空字符串("")到contentsOfDirectory
方法以列出当前目录中的文件。
创建新目录
documentsProvider.create(folder: "new folder", at: "/", completionHandler: { error in
if let error = error {
// Error handling here
} else {
// The operation succeed
}
})
要创建文件,请使用writeContents(path: content: atomically: completionHandler:)
方法。
将文件old.txt从当前路径复制到new.txt
documentsProvider.copyItem(path: "new folder/old.txt", to: "new.txt", overwrite: false, completionHandler: nil)
将文件old.txt从当前路径移动到new.txt
documentsProvider.moveItem(path: "new folder/old.txt", to: "new.txt", overwrite: false, completionHandler: nil)
注意:为了保持一致性,如果需要,请首先创建中间目录。
documentsProvider.removeItem(path: "new.txt", completionHandler: nil)
警告:该方法会递归删除包含所有内容的目录(除了不支持SITE RMDIR
命令的FTP提供方,这将稍后修复)。
有两种方法可以实现这一目的,其中一种将整个文件加载到Data
中,另一种可以加载文件的一部分。
documentsProvider.contents(path: "old.txt", completionHandler: {
contents, error in
if let contents = contents {
print(String(data: contents, encoding: .utf8)) // "hello world!"
}
})
如果您想要检索文件的一部分,可以使用带有偏移和长度参数的contents
方法。请注意,文件的第一字节偏移量为:0。
documentsProvider.contents(path: "old.txt", offset: 2, length: 5, completionHandler: {
contents, error in
if let contents = contents {
print(String(data: contents, encoding: .utf8)) // "llo w"
}
})
let data = "What's up Newyork!".data(encoding: .utf8)
documentsProvider.writeContents(path: "old.txt", content: data, atomically: true, completionHandler: nil)
有两种方法可以在提供方和本地存储之间下载和上传文件。这些方法使用URLSessionDownloadTask
和URLSessionUploadTask
类,允许使用后台会话并通过代理提供进度。
要上传文件
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("image.jpg")
documentsProvider.copyItem(localFile: fileURL, to: "/upload/image.jpg", overwrite: true, completionHandler: nil)
要下载文件
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("image.jpg")
documentsProvider.copyItem(path: "/download/image.jpg", toLocalURL: fileURL, overwrite: true, completionHandler: nil)
URLSessionDownloadTask
或者基于流任务的定制实现方法,这可以通过useAppleImplementation
属性完成。FTP协议不支持后台会话。遵守FileProviderUndoable
的提供方可以对一些操作执行撤消,如移动/重命名、复制和创建(文件或文件夹)。目前,只有LocalFileProvider
支持此功能。要实现
// To setup a new UndoManager:
documentsProvider.setupUndoManager()
// or if you have an UndoManager object already:
documentsProvider.undoManager = self.undoManager
// e.g.: To undo last operation manually:
documentsProvider.undoManager?.undo()
您还可以将UndoManager
对象与视图控制器绑定,以使用摇晃手势和在iOS/macOS中内置的撤销支持,如下面的示例代码将代码添加到您的ViewController类中:
class ViewController: UIViewController
override var canBecomeFirstResponder: Bool {
return true
}
override var undoManager: UndoManager? {
return (provider as? FileProvideUndoable)?.undoManager
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Your code here
UIApplication.shared.applicationSupportsShakeToEdit = true
self.becomeFirstResponder()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Your code here
UIApplication.shared.applicationSupportsShakeToEdit = false
self.resignFirstResponder()
}
// The rest of your implementation
}
创建/复制/删除函数返回一个对远程操作的OperationHandle
。它提供操作类型、进度和允许您在中途取消操作的.cancel()
方法。
原生(NS)FileManager
不支持此功能,因此LocalFileProvider
不支持,但此功能将添加到未来的PosixFileProvider
类。
LocalFileProvider
及其子类都有一个isCoordinating
属性。通过设置这个属性,提供者将使用NSFileCoordinating
类来进行所有的文件操作。对于iCloud是强制性的,当使用共享容器或在通常对文件/文件夹进行并行操作的任何地方,则强烈推荐使用。
您可以在某些文件系统(本地和SMB2)中监控更新,在支持提供者的三个方法中,您可以用来注册处理程序、注销注册以及检查是否正在监控。当需要在目录中添加或删除新文件以及更新用户界面时,这个功能很有用。处理程序将被调度到主线程,以避免与UI相关的错误,延迟为0.25秒。
// to register a new notification handler
documentsProvider.registerNotifcation(path: provider.currentPath) {
// calling functions to update UI
}
// To discontinue monitoring folders:
documentsProvider.unregisterNotifcation(path: provider.currentPath)
符合ExtendedFileProvider
规范的提供者能够为图像、媒体和PDF文件生成缩略图或提供文件元信息。
Local、OneDrive和Dropbox提供者支持此功能。
要检查文件是否支持缩略图并获取缩略图,请使用(并修改)以下示例代码
let path = "/newImage.jpg"
let thumbSize = CGSize(width: 64, height: 64)
if documentsProvider.thumbnailOfFileSupported(path: path {
documentsProvider.thumbnailOfFile(path: file.path, dimension: thumbSize, completionHandler: { (image, error) in
DispatchQueue.main.async {
self.previewImage.image = image
}
}
}
要获取类似图像/视频拍摄日期、位置、尺寸等元信息,请使用(并修改)以下示例代码
if documentsProvider..propertiesOfFile(path: file.path, completionHandler: { (propertiesDictionary, keys, error) in
for key in keys {
print("\(key): \(propertiesDictionary[key])")
}
}
LocalFileInformationGenerator
的静态变量和方法来修改/扩展Local提供者生成器我们非常欢迎您为FileProvider贡献力量,更多详情请查看LICENSE
文件。
您可以考虑去做的一些事情来帮助我们
SMBClient
的请求/响应堆栈如果您在使用此库的项目中,您可以打开一个issue来通知我们。
Amir-Abbas Mousavian – @amosavian
感谢Hootan Moradi设计标志。
在MIT许可证下分发。更多信息请参阅LICENSE
文件。