How do I load a text file line by line into an array with Swift? How do I load a text file line by line into an array with Swift? ios ios

How do I load a text file line by line into an array with Swift?


Something along the lines of:

func arrayFromContentsOfFileWithName(fileName: String) -> [String]? {    guard let path = NSBundle.mainBundle().pathForResource(fileName, ofType: "txt") else {        return nil    }    do {        let content = try String(contentsOfFile:path, encoding: NSUTF8StringEncoding)        return content.componentsSeparatedByString("\n")    } catch _ as NSError {        return nil    }}

This approach assumes the file in question is located in your app bundle.


With Swift 5, according to your needs, you can choose one of the 3 following ways in order to solve your problem.


#1. Using StringProtocol's components(separatedBy:) method

Foundation provides String a method called components(separatedBy:) with the following declaration:

func components(separatedBy separator: CharacterSet) -> [String]

Returns an array containing substrings from the string that have been divided by characters in the given set.

The code sample below shows how to use components(separatedBy:) with its parameter set to CharacterSet.newlines in order to load the content of a text file line by line into an array:

import Foundationlet path = Bundle.main.path(forResource: "Lorem Ipsum", ofType: "txt")!let text = try! String(contentsOfFile: path, encoding: String.Encoding.utf8)let lines = text.components(separatedBy: CharacterSet.newlines)print(lines)

As an alternative, you can use the overloading of components(separatedBy:) that takes a parameter of type String. The code sample below shows how to use it:

import Foundationlet path = Bundle.main.path(forResource: "Lorem Ipsum", ofType: "txt")!let text = try! String(contentsOfFile: path, encoding: String.Encoding.utf8)let lines = text.components(separatedBy: "\n")print(lines)

⚠️ You should however prefer the overloading of components(separatedBy:) that takes a CharacterSet parameter and use it with the value CharacterSet.newlines as this will manage all new line characters (U+000A ~ U+000D, U+0085, U+2028, and U+2029).


#2. Using StringProtocol's enumerateSubstrings(in:options:_:) method

Foundation provides String a method called enumerateSubstrings(in:options:_:). The code sample below shows how to use enumerateSubstrings(in:options:_:) with options parameter value set to String.EnumerationOptions.byLines in order to load the content of a text file line by line into an array:

import Foundationlet path = Bundle.main.path(forResource: "Lorem Ipsum", ofType: "txt")!let text = try! String(contentsOfFile: path, encoding: String.Encoding.utf8)let range = text.startIndex ..< text.endIndexvar lines = [String]()text.enumerateSubstrings(in: range, options: String.EnumerationOptions.byLines) {    (substring, range, enclosingRange, stop) in    guard let substring = substring else { return }    lines.append(substring)}print(lines)

#3. Using NLTokenizer's enumerateTokens(in:using:) method

NLTokenizer has a method called enumerateTokens(in:using:). enumerateTokens(in:using:) has the following declaration:

@nonobjc func enumerateTokens(in range: Range<String.Index>, using block: (Range<String.Index>, NLTokenizer.Attributes) -> Bool)

Enumerates over a given range of the string and calls the specified block for each token.

The code sample below shows how to use enumerateTokens(in:using:) in order to load the content of a text file line by line into an array:

import Foundationimport NaturalLanguagelet path = Bundle.main.path(forResource: "Lorem Ipsum", ofType: "txt")!let text = try! String(contentsOfFile: path, encoding: String.Encoding.utf8)let tokenizer = NLTokenizer(unit: .paragraph)tokenizer.setLanguage(.english)tokenizer.string = textvar lines = [String]()tokenizer.enumerateTokens(in: text.startIndex ..< text.endIndex) { (range, attributes) -> Bool in    let line = String(text[range])    lines.append(line)    return true}print(lines)


Swift 3 version based on the accepted answer:

func arrayFromContentsOfFileWithName(fileName: String) -> [String]? {    guard let path = Bundle.main.path(forResource: fileName, ofType: "txt") else {        return nil    }    do {        let content = try String(contentsOfFile:path, encoding: String.Encoding.utf8)        return content.components(separatedBy: "\n")    } catch {        return nil    }}