29

I'm trying to learn the new Swift programming language. It looks great, but I'm having a difficult time doing something as simple as reading the content of a local .txt file.

I have tried the few examples I could find through Google, but they give compile errors, like this answer here: Read and write data from text file If I tweak the code a bit, it works, but can only read from a special location within the project.

Why isn't it just as simple to read a .txt file with Swift as it is with for instance Ruby? And how would I go about reading the content of a file located at ~/file.txt?

Thnx

eivindml
  • 1,319
  • 3
  • 25
  • 49

8 Answers8

37

If you have a tilde in your path you can try this:

let location = "~/file.txt".stringByExpandingTildeInPath
let fileContent = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)

otherwise just use this:

let location = "/Users/you/Desktop/test.txt"
let fileContent = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)

This gives you a string representation of the file, which I assumed is what you want. You can use NSData(contentsOfFile: location) to get a binary representation, but you would normally do that for, say, music files and not a text file.


Update: With Xcode 7 and Swift 2 this doesn't work anymore. You can now use

let location = NSString(string:"~/file.txt").stringByExpandingTildeInPath
let fileContent = try? NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding)
Atomix
  • 12,019
  • 9
  • 36
  • 43
  • I got this error: `Cannot invoke initializer for type 'NSString' with an argument list of type '(contentsOfFile: String, encoding: Ulnt, error: NilLiteralConvertible)' – O.rka Sep 21 '15 at 00:44
  • let location = NSString(string:"/Users/you/Desktop/myCSVfile.csv") let fileContent = try? NSString(contentsOfFile: location as String, encoding: NSUTF8StringEncoding) – Naishta Dec 26 '15 at 11:02
15

This would work:

let path = "~/file.txt"
let expandedPath = path.stringByExpandingTildeInPath
let data: NSData? = NSData(contentsOfFile: expandedPath)

if let fileData = data {
    let content = NSString(data: fileData, encoding:NSUTF8StringEncoding) as String
}

Note that data may be nil, so you should check for that.

EDIT: Don't forget conditional unwrapping - looks much nicer ;)

borchero
  • 4,555
  • 6
  • 39
  • 70
Grimxn
  • 20,778
  • 9
  • 67
  • 80
  • I don't get the "if let fileData = data" part? What is going on here? – O.rka Sep 21 '15 at 01:00
  • 4
    `data` is an optional. It's declared as one on the line above. To quote from "A Swift Tour", the first chapter of the book: "You can use if and let together to work with values that might be missing. These values are represented as optionals. An optional value either contains a value or contains nil to indicate that a value is missing. Write a question mark (?) after the type of a value to mark the value as optional." – Grimxn Sep 21 '15 at 07:24
12
    let file = "/Users/user/Documents/text.txt"
    let path=URL(fileURLWithPath: file)
    let text=try? String(contentsOf: path)
Amirhossein72
  • 361
  • 5
  • 7
  • 1
    This deserves way more +1. simple, clean, and no need for NS. Am I missing something? Someone enlighten me if this is flawed? – rayepps Dec 05 '19 at 09:11
3

Relative path tip:

Instead of doing this:
NSString("~/file.txt").stringByExpandingTildeInPath

You can do this:
"\(NSHomeDirectory())/file.txt"

Sentry.co
  • 4,132
  • 38
  • 30
2

You may find this tool useful to not only read from file in Swift but also parse it simultaneously: https://github.com/shoumikhin/StreamScanner

Just specify the file path and data delimiters like this (see readme for more options):

import StreamScanner

if let input = NSFileHandle(forReadingAtPath: "/file/path")
{
     let scanner = StreamScanner(source: input, delimiters: NSCharacterSet(charactersInString: ":\n"))  //separate data by colons and newlines

     while let field: String = scanner.read()
     {
        //use field
     }
}

Hope, this helps.

shoumikhin
  • 1,229
  • 15
  • 22
1

This worked for me in Swift 2.1, XCode7 to get the location and print the contents of CSV. ( you can create a simple CSV in Text Wrangler)

override func viewDidLoad() {
    super.viewDidLoad()

    let location = NSString(string:"/Users/*Myusername*/Documents/myCSVfile.csv")
    let fileContent = try? NSString(contentsOfFile: location as String, encoding: NSUTF8StringEncoding)
    print(fileContent)

}
Naishta
  • 9,905
  • 4
  • 60
  • 49
  • I haven't tested the code but thanks, this helped me decide where to read files directly after starting the app. – Neph Jun 18 '19 at 11:04
0

Using the answer by Atomix, this will work in Swift 4:

let location = NSString(string: "~/test.txt").expandingTildeInPath    
let fileContent = try? NSString(contentsOfFile: location, encoding: String.Encoding.utf8.rawValue)
NeRa
  • 81
  • 5
0

Swift 4:

 let filePath = "/Users/UserName/Desktop/FolderName/FileName.txt"
 let fullPath = NSString(string: filePath).expandingTildeInPath
 do
 {
     let fileContent = try NSString(contentsOfFile: fullPath, encoding: String.Encoding.utf8.rawValue)
     print(fileContent)
 }
 catch
 {
     print(error)
 }
Nilanshu Jaiswal
  • 1,265
  • 3
  • 15
  • 31