如何将选定的文件复制到应用程序的目录
How to copy selected file to app's directory
我是 iOS 中 FileManager
的新手。
我正在尝试创建一个简单的应用程序:有一个文件列表,当用户按下一个单元格时,该文件将打开。用户还可以添加新文件。
这是我目前拥有的:
class TableViewController: UITableViewController, UIDocumentPickerDelegate {
var urls: [URL] = []
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
@IBAction func newButtonPressed(_ sender: Any) {
let types = UTType(tag: "pdf", tagClass: .filenameExtension, conformingTo: nil)!
let controller = UIDocumentPickerViewController(forOpeningContentTypes: [types])
controller.delegate = self
self.present(controller, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
for url in urls {
self.storeAndShare(withURL: url)
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return urls.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = urls[indexPath.row].localizedName
return cell
}
lazy var documentInteractionController: UIDocumentInteractionController = {
let vc = UIDocumentInteractionController()
vc.delegate = self
return vc
}()
func share(url: URL) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentPreview(animated: true)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
share(url: self.urls[indexPath.row])
}
func storeAndShare(withURL url: URL) {
/// START YOUR ACTIVITY INDICATOR HERE
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let direcotryURL = URL(string: FileManager.default.currentDirectoryPath)!
let newURL = direcotryURL.appendingPathComponent(response?.suggestedFilename ?? "fileName.pdf")
do {
try data.write(to: newURL)
} catch let err {
print("ERROR: \(err).")
// Error Domain=NSCocoaErrorDomain Code=518 "The file couldn’t be saved because the specified URL type isn’t supported." UserInfo={NSURL=/doc.pdf}
return
}
DispatchQueue.main.async {
/// STOP YOUR ACTIVITY INDICATOR HERE
self.urls.append(newURL)
self.share(url: newURL)
self.tableView.reloadData()
}
}.resume()
}
}
extension TableViewController: UIDocumentInteractionControllerDelegate {
/// If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let navVC = self.navigationController else {
return self
}
return navVC
}
}
extension URL {
var typeIdentifier: String? {
return (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
}
var localizedName: String? {
return (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName
}
}
我在使用 storeAndShare()
功能时遇到问题。我试图将选定的文件复制到应用程序的目录,然后将新的 URL 添加到 urls 列表 (self.urls
)。
但它不起作用,并在 data.write:
中给我一个错误
Error Domain=NSCocoaErrorDomain Code=518 "The file couldn’t be saved because the specified URL type isn’t supported." UserInfo={NSURL=/doc.pdf}
为什么会这样?我怎样才能达到我的需要?提前致谢
最严重的错误是currentDirectoryPath
。您不能使用它来获取 Documents 目录的路径。您必须调用 url(for:in:appropriateFor:create:
或 urls(for:in:)
或 FileManager
而且 - 如果我们谈论的是本地文件 - URLSession
也是错误的方式。
func storeAndShare(with url: URL) {
let directoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let newURL = directoryURL.appendingPathComponent(url.lastPathComponent)
do {
try FileManager.default.copyItem(at: url, to: newURL)
DispatchQueue.main.async {
self.urls.append(newURL)
self.share(url: newURL)
self.tableView.reloadData()
}
} catch {
print("ERROR: \(error).")
}
}
"/doc.pdf"
对你来说是不可写的。
获取文档目录:
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
并将文件保存在那里(而不是使用 currentDirectoryPath
)。
我是 iOS 中 FileManager
的新手。
我正在尝试创建一个简单的应用程序:有一个文件列表,当用户按下一个单元格时,该文件将打开。用户还可以添加新文件。
这是我目前拥有的:
class TableViewController: UITableViewController, UIDocumentPickerDelegate {
var urls: [URL] = []
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
@IBAction func newButtonPressed(_ sender: Any) {
let types = UTType(tag: "pdf", tagClass: .filenameExtension, conformingTo: nil)!
let controller = UIDocumentPickerViewController(forOpeningContentTypes: [types])
controller.delegate = self
self.present(controller, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
for url in urls {
self.storeAndShare(withURL: url)
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return urls.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = urls[indexPath.row].localizedName
return cell
}
lazy var documentInteractionController: UIDocumentInteractionController = {
let vc = UIDocumentInteractionController()
vc.delegate = self
return vc
}()
func share(url: URL) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentPreview(animated: true)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
share(url: self.urls[indexPath.row])
}
func storeAndShare(withURL url: URL) {
/// START YOUR ACTIVITY INDICATOR HERE
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let direcotryURL = URL(string: FileManager.default.currentDirectoryPath)!
let newURL = direcotryURL.appendingPathComponent(response?.suggestedFilename ?? "fileName.pdf")
do {
try data.write(to: newURL)
} catch let err {
print("ERROR: \(err).")
// Error Domain=NSCocoaErrorDomain Code=518 "The file couldn’t be saved because the specified URL type isn’t supported." UserInfo={NSURL=/doc.pdf}
return
}
DispatchQueue.main.async {
/// STOP YOUR ACTIVITY INDICATOR HERE
self.urls.append(newURL)
self.share(url: newURL)
self.tableView.reloadData()
}
}.resume()
}
}
extension TableViewController: UIDocumentInteractionControllerDelegate {
/// If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let navVC = self.navigationController else {
return self
}
return navVC
}
}
extension URL {
var typeIdentifier: String? {
return (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
}
var localizedName: String? {
return (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName
}
}
我在使用 storeAndShare()
功能时遇到问题。我试图将选定的文件复制到应用程序的目录,然后将新的 URL 添加到 urls 列表 (self.urls
)。
但它不起作用,并在 data.write:
Error Domain=NSCocoaErrorDomain Code=518 "The file couldn’t be saved because the specified URL type isn’t supported." UserInfo={NSURL=/doc.pdf}
为什么会这样?我怎样才能达到我的需要?提前致谢
最严重的错误是currentDirectoryPath
。您不能使用它来获取 Documents 目录的路径。您必须调用 url(for:in:appropriateFor:create:
或 urls(for:in:)
或 FileManager
而且 - 如果我们谈论的是本地文件 - URLSession
也是错误的方式。
func storeAndShare(with url: URL) {
let directoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let newURL = directoryURL.appendingPathComponent(url.lastPathComponent)
do {
try FileManager.default.copyItem(at: url, to: newURL)
DispatchQueue.main.async {
self.urls.append(newURL)
self.share(url: newURL)
self.tableView.reloadData()
}
} catch {
print("ERROR: \(error).")
}
}
"/doc.pdf"
对你来说是不可写的。
获取文档目录:
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
并将文件保存在那里(而不是使用 currentDirectoryPath
)。