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

- 89,880
- 29
- 256
- 218

- 1,468
- 1
- 15
- 31
-
1See this post for an excellent discussion on the options for converting a text file to a line array. http://codereview.stackexchange.com/a/100813/79551 – Suragch Aug 15 '15 at 02:32
9 Answers
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.

- 55,636
- 19
- 86
- 87
-
1What if the file is located outside the main bundle? Assume that I have an `NSString` that contains the full path. – Matt Jul 03 '14 at 22:04
-
2
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 Foundation
let 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 Foundation
let 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 Foundation
let path = Bundle.main.path(forResource: "Lorem Ipsum", ofType: "txt")!
let text = try! String(contentsOfFile: path, encoding: String.Encoding.utf8)
let range = text.startIndex ..< text.endIndex
var 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 Foundation
import NaturalLanguage
let 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 = text
var 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)

- 89,880
- 29
- 256
- 218
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
}
}

- 458
- 5
- 12
-
Not to be nit-picky, but the signature might be better as `func arrayFromContentsOfFile(with fileName: String) -> [String]?`. – ProgrammierTier Feb 05 '17 at 16:01
If you are in Swift 2.0, you should use:
let path = NSBundle.mainBundle().pathForResource(fileName, ofType: nil)
if path == nil {
return nil
}
var fileContents: String? = nil
do {
fileContents = try String(contentsOfFile: path!, encoding: NSUTF8StringEncoding)
} catch _ as NSError {
return nil
}

- 360
- 2
- 12
-
2You forgot `var lineArray = fileContents.componantsSeparedByString("\n")` – Suragch Aug 13 '15 at 03:15
This works only until Xcode 6.1 beta 1. In 6.1 beta 2 you must write this:
var err: NSError? = NSError()
let s = String(contentsOfFile: fullPath, encoding: NSUTF8StringEncoding, error: &err)
Where fullPath
is a string containing the full path to the file and NSUTF8StringEncoding
is a predefined constant for UTF8-Encoding.
You can also use NSMacOSRomanStringEncoding
for Mac files or NSISOLatin1StringEncoding
for Windows files.
s
is an optional String and you can look if reading the file was successful:
if (s != nil)
{
return (s!) // Return the string as "normal" string, not as optional string
}
-
This also seems to have ceased to work as of the final release of Xcode 6. Try let string = String.stringWithContentsOfFile(fullPath, encoding: NSUTF8StringEncoding, error:&error) – Ash Oct 07 '14 at 14:45
My simple coding for you
let path = NSBundle.mainBundle().pathForResource("FileName", ofType: "txt")
var text = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)!
println(text)
var array = text.componentsSeparatedByString("\n")

- 9,459
- 3
- 32
- 39
Swift 3.0
if let path = Bundle.main.path(forResource: <#FileName#>, ofType: "txt")
{
do
{
let str = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
return str.components(separatedBy: "\n")
}
catch
{
}
}
else
{
return nil
}

- 4,557
- 2
- 32
- 31
For me works as follow:
let myFileURL = NSBundle.mainBundle().URLForResource("listacomuni", withExtension: "txt")!
let myText = try! String(contentsOfURL: myFileURL, encoding: NSISOLatin1StringEncoding)
print(String(myText))

- 2,309
- 2
- 18
- 24
If you want to read a csv file of numeric data. (based on Cezar's answer)
func get_csv_data() -> [[Double]] {
guard let path = NSBundle.mainBundle().pathForResource("filename_without_extension", ofType: "csv") else {
return []
}
do {
let content = try String(contentsOfFile:path, encoding: NSUTF8StringEncoding)
let line_str_array = content.componentsSeparatedByString("\n")
return line_str_array.map {
let field_str_array = $0.componentsSeparatedByString(",")
return field_str_array.map {
Double($0)!
}
}
} catch _ as NSError {
return []
}
}

- 6,246
- 1
- 29
- 45