Read text file line by line

If you read a file line-by-line, it’s critical to do user-space buffering to avoid hitting the kernel for each line. Swift doesn’t have that facility, and neither does Foundation.

Implementing line buffering yourself (on top of, say, InputStream or FileHandle) is quite tricky. Rather than rolling my own, I typically use the C standard library for this. That is, I use FILE * with a Swift wrapper. Here’s an example of how you might do that.

A Swift wrapper around C’s `FILE *`
class QFile {

    init(fileURL: URL) {
        self.fileURL = fileURL
    }

    deinit {
        // You must close before releasing the last reference.
        precondition(self.file == nil)
    }

    let fileURL: URL

    private var file: UnsafeMutablePointer<FILE>? = nil

    func open() throws {
        guard let f = fopen(fileURL.path, "r") else {
            throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
        }
        self.file = f
    }

    func close() {
        if let f = self.file {
            self.file = nil
            let success = fclose(f) == 0
            assert(success)
        }
    }

    func readLine(maxLength: Int = 1024) throws -> String? {
        guard let f = self.file else {
            throw NSError(domain: NSPOSIXErrorDomain, code: Int(EBADF), userInfo: nil)
        }
        var buffer = [CChar](repeating: 0, count: maxLength)
        guard fgets(&buffer, Int32(maxLength), f) != nil else {
            if feof(f) != 0 {
                return nil
            } else {
                throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
            }
        }
        return String(cString: buffer)
    }
}

Reading whole file into memory will cause bigger resource problem in
some case.

If the text file is sufficiently big to cause memory problems, you’ll probably want to store it compressed on disk. That becomes a whole different kettle of fish.


Personally, I’d love to see improvements in how Swift handle files, including this specific case. If you think likewise, consider engaging with Swift Evolution.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

20 Likes