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-адреса относятся к копии выбранных документов. Эти документы являются временными файлами. Они остаются доступными только до тех пор, пока ваше приложение не прекратит работу. Чтобы сохранить постоянную копию, переместите эти файлы в постоянное место внутри своей песочницы.

Так что да, вы должны сделать копию. Но вы можете удалить файл, когда закончите его разбор.

Другие вопросы по тегам