Swift CSVImporter не может прочитать файл CSV
Я использую модуль CSVImporter, чтобы проанализировать файл CSV, загруженный с диска iCloud. Цель каждой проанализированной строки должна быть загружена в мою базу данных.
Когда importFile()
выполняется печатает путь, но затем печатает "The CSV file couldn't be read."
Q1: что я делаю не так?
import UIKit
import MobileCoreServices
import CSVImporter
class importBatchVC: UIViewController,UIDocumentPickerDelegate,UINavigationControllerDelegate {
var path=""
var docURL = URL(string: "")
@IBAction func chooseDoc(_ sender: Any) {
let importMenu = UIDocumentPickerViewController(documentTypes: [String(kUTTypeContent),String(kUTTypePlainText)], in: .import)
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
self.present(importMenu, animated: true, completion: nil
}
@IBAction func importFile(_ sender: Any) {
if docURL==nil {
let alert = UIAlertController(title: "Error", message: "Please select a spreadsheet.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
} else {
do {
self.path = String(describing:docURL)
print(path)
let importer = CSVImporter<[String]>(path: path)
importer.startImportingRecords { $0 }.onFail {
print("The CSV file couldn't be read.")
}.onProgress { importedDataLinesCount in
print("\(importedDataLinesCount) lines were already imported.")
}.onFinish { importedRecords in
print("Did finish import with \(importedRecords.count) records.")
}
}
}
}
@IBAction func cancel(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
print("The Url is : \(String(describing: url))")
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
try FileManager.default.moveItem(at: url.standardizedFileURL, to: documentDirectory.appendingPathComponent(url.lastPathComponent))
self.docURL = documentDirectory.appendingPathComponent(url.lastPathComponent)
print("now check this: \(docURL!)")
} catch {
print(error)
}
}
func documentMenu(_ documentMenu: UIDocumentPickerViewController, didPickDocumentPicker documentPicker: UIDocumentPickerViewController) {
documentPicker.delegate = self
present(documentPicker, animated: true, completion: nil)
}
}
Примечание: это вопрос репоста, который был закрыт как "дубликат", и приведенный выше код является предложенной реализацией.
Моя первоначальная и предпочтительная реализация заключалась в том, чтобы получить ссылку на файл диска iCloud через documentPicker
и проанализировать / загрузить его в базу данных на лету, но я получаю ту же ошибку, что и сейчас: "Файл CSV не может быть прочитан".
Объяснение, которое было дано Лео Дабусом, было: "UIDocumentPickerModeImport The URL refers to a copy of the selected document. This document is a temporary file. It remains available only until your application terminates. To keep a permanent copy, you must move this file to a permanent location inside your sandbox."
Q2: Учитывая, что мне не нужно хранить постоянный файл - просто нужно сохранить его до его анализа, а затем он будет в моей базе данных, почему мне нужно импортировать его в documentDirectory
Есть ли способ, я мог бы разобрать его по ссылке, которую я получаю из DocumentPicker?
Код для моей первоначальной реализации:
import UIKit
import MobileCoreServices
import CSVImporter
class importBatchVC: UIViewController,UIDocumentPickerDelegate,UINavigationControllerDelegate {
var path=""
var docURL = URL(string: "")
@IBAction func chooseDoc(_ sender: Any) {
let importMenu = UIDocumentPickerViewController(documentTypes: [String(kUTTypeContent),String(kUTTypePlainText)], in: .import)
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
self.present(importMenu, animated: true, completion: nil)
}
@IBAction func importFile(_ sender: Any) {
if docURL==nil {
let alert = UIAlertController(title: "Error", message: "Please select a spreadsheet.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
else{
do {
self.path = docURL!.path
print(path)
let importer = CSVImporter<[String]>(path: path)
importer.startImportingRecords { $0 }.onFinish { importedRecords in
for record in importedRecords {
// record is of type [String] and contains all data in a line
print(record)
}
}
}
}
}
@IBAction func cancel(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
docURL = url as URL
print("The Url is : \(String(describing: url))")
}
func documentMenu(_ documentMenu: UIDocumentPickerViewController, didPickDocumentPicker documentPicker: UIDocumentPickerViewController) {
documentPicker.delegate = self
present(documentPicker, animated: true, completion: nil)
}
}
1 ответ
Q1:
Проблема, которую я вижу при попытке разобрать файл в docURL
это следующая строка:
self.path = String(describing:docURL)
Это неправильный способ преобразования URL-адреса файла в путь. Правильный код:
self.path = docURL.path
Q2:
Когда вы используете UIDocumentPickerViewController
в import
В этом режиме URL, указанный вами в методе делегата, действителен только до конца метода делегата. Вот почему вы должны скопировать / переместить выбранный файл.
Из документации:
URL-адреса относятся к копии выбранных документов. Эти документы являются временными файлами. Они остаются доступными только до тех пор, пока ваше приложение не прекратит работу. Чтобы сохранить постоянную копию, переместите эти файлы в постоянное место внутри своей песочницы.
Так что да, вы должны сделать копию. Но вы можете удалить файл, когда закончите его разбор.