Swift 5.5
The solution below shows how to read one line at a time. This is quite different from reading the entire contents into memory. Reading line-by-line scales well if you have a large file to read. Putting an entire file into memory does not scale well for large files.
The example below uses a while loop that quits when there are no more lines, but you can choose a different number of lines to read if you wish.
The code works as follows:
- create a URL that tells where the file is located
- make sure the file exists
- open the file for reading
- set up some initial variables for reading
- read each line using
getLine() - close the file and free the buffer when done
You could make the code less verbose if you wish; I have included comments to explain what the variables' purposes are.
Swift 5.5
import Cocoa // get URL to the the documents directory in the sandbox let home = FileManager.default.homeDirectoryForCurrentUser // add a filename let fileUrl = home .appendingPathComponent("Documents") .appendingPathComponent("my_file") .appendingPathExtension("txt") // make sure the file exists guard FileManager.default.fileExists(atPath: fileUrl.path) else { preconditionFailure("file expected at \(fileUrl.absoluteString) is missing") } // open the file for reading // note: user should be prompted the first time to allow reading from this location guard let filePointer:UnsafeMutablePointer<FILE> = fopen(fileUrl.path,"r") else { preconditionFailure("Could not open file at \(fileUrl.absoluteString)") } // a pointer to a null-terminated, UTF-8 encoded sequence of bytes var lineByteArrayPointer: UnsafeMutablePointer<CChar>? = nil // see the official Swift documentation for more information on the `defer` statement // https://docs.swift.org/swift-book/ReferenceManual/Statements.html#grammar_defer-statement defer { // remember to close the file when done fclose(filePointer) // The buffer should be freed by even if getline() failed. lineByteArrayPointer?.deallocate() } // the smallest multiple of 16 that will fit the byte array for this line var lineCap: Int = 0 // initial iteration var bytesRead = getline(&lineByteArrayPointer, &lineCap, filePointer) while (bytesRead > 0) { // note: this translates the sequence of bytes to a string using UTF-8 interpretation let lineAsString = String.init(cString:lineByteArrayPointer!) // do whatever you need to do with this single line of text // for debugging, can print it print(lineAsString) // updates number of bytes read, for the next iteration bytesRead = getline(&lineByteArrayPointer, &lineCap, filePointer) }