iosswiftswift5xcode11.4txt

Loading / Reading a txt file from dropbox into swift


I am trying to load a .txt file that has the following format

Person Position Data Average Goal
Person One Director 37 45 80
Person Two Assistant 23 56 34
Person Three CEO 34 45 67

There are five columns, with the first row being a header. Below is the code I am using within my viewDidLoad:


override func viewDidLoad() {
    super.viewDidLoad()
    // load txt file from dropbox
    let url = URL(string: "https://www.dropbox.com/s/pr0ldvdeab48mpp/prueba.txt?dl=0")
    let task = URLSession.shared.downloadTask(with: url!) {(urlresponse, response, error) in
        guard let originalURL = urlresponse else { return }
        do {
            // get path to directory
            let path = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            // giving name to file
            let newUrl = path.appendingPathComponent("myTextFile")
            // move file from old to new url
            try FileManager.default.moveItem(at: originalURL, to: newUrl)
        } catch { 
            print(error.localizedDescription)
            return
        }
    }
    task.resume()
    //reading the file
    let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
    do {
        let fileUrls = try FileManager.default.contentsOfDirectory(at: path!, includingPropertiesForKeys: nil)
        //read the text
        let textContent = try String(contentsOf: fileUrls[0], encoding: .utf8)
        print(textContent)
    } catch {
        print("ERROR")
    }
}

However, I get the error below on the line

let textContent = try String(contentsOf: fileUrls[0], encoding: .utf8)

Thread 1: Fatal error: Index out of range

My goal is to be able to read the file and access elements of each column/row individually when needed but not able to identify the source of the problem. Appreciate any help.

Note: If it helps, I can be flexible loading the file as a .csv or other format if that is easier.


Solution

  • Your issue is that dl=0 doesn't point to the file. It will point to a html file. You need to use dl=1 to be able to download the file directly. You should also move your loading code inside the completion closure from your download task. You can also get the file name from the url response. Try like this:

    // load txt file from dropbox (make sure you change the string suffix from dl=0 to dl=1)
    let url = URL(string: "https://www.dropbox.com/s/pr0ldvdeab48mpp/prueba.txt?dl=1")!
    let task = URLSession.shared.downloadTask(with: url) { location, response, error in
        guard let location = location else { return }
        do {
            // get the documentDirectory url
            let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            print(documentDirectory.path)
            // get the suggested name fro the url response or the url last path component
            let name = (response as? HTTPURLResponse)?.suggestedFilename ?? location.lastPathComponent
            // create a destination url
            let destination = documentDirectory.appendingPathComponent(name)
            // check if the file already exists
            if FileManager.default.fileExists(atPath: destination.path) {
                // remove the file (if you would like to use the new one)
                try FileManager.default.removeItem(at: destination)
            }
            // move file from the temporary location to the destination
            try FileManager.default.moveItem(at: location, to: destination)
            // reading the downloaded file
            let textContent = try String(contentsOf: destination, encoding: .utf8)
            print(textContent)
        } catch {
            print("ERROR")
        }
    }
    task.resume()