0

In the previous version of swift I was able to use the answer form this post: Read a file/URL line-by-line in Swift

to do line by line reading of a file in swift. Now that I've upgraded to 1.2 this no longer seems to compile. Is there an updated way to read a file line by line in swift 1.2?

Community
  • 1
  • 1
Jeef
  • 26,861
  • 21
  • 78
  • 156

2 Answers2

3

Here is an updated version of StreamReader for Swift 1.2 (which, if someone wants to review it to make sure it's OK, should probably be edited into the original answer now that 1.2 is the current released version):

class StreamReader  {

    let encoding : UInt
    let chunkSize : Int

    var fileHandle : NSFileHandle!
    let buffer : NSMutableData!
    let delimData : NSData!
    var atEof : Bool = false

    init?(path: String, delimiter: String = "\n", encoding : UInt = NSUTF8StringEncoding, chunkSize : Int = 4096) {
        self.chunkSize = chunkSize
        self.encoding = encoding

        if let fileHandle = NSFileHandle(forReadingAtPath: path),
               delimData = delimiter.dataUsingEncoding(NSUTF8StringEncoding),
               buffer = NSMutableData(capacity: chunkSize)
        {
            self.fileHandle = fileHandle
            self.delimData = delimData
            self.buffer = buffer
        } else {
            self.fileHandle = nil
            self.delimData = nil
            self.buffer = nil
            return nil
        }
    }

    deinit {
        self.close()
    }

    /// Return next line, or nil on EOF.
    func nextLine() -> String? {
        precondition(fileHandle != nil, "Attempt to read from closed file")

        if atEof {
            return nil
        }

        // Read data chunks from file until a line delimiter is found:
        var range = buffer.rangeOfData(delimData, options: nil, range: NSMakeRange(0, buffer.length))
        while range.location == NSNotFound {
            var tmpData = fileHandle.readDataOfLength(chunkSize)
            if tmpData.length == 0 {
                // EOF or read error.
                atEof = true
                if buffer.length > 0 {
                    // Buffer contains last line in file (not terminated by delimiter).
                    let line = NSString(data: buffer, encoding: encoding)

                    buffer.length = 0
                    return line as String?
                }
                // No more lines.
                return nil
            }
            buffer.appendData(tmpData)
            range = buffer.rangeOfData(delimData, options: nil, range: NSMakeRange(0, buffer.length))
        }

        // Convert complete line (excluding the delimiter) to a string:
        let line = NSString(data: buffer.subdataWithRange(NSMakeRange(0, range.location)),
            encoding: encoding)
        // Remove line (and the delimiter) from the buffer:
        buffer.replaceBytesInRange(NSMakeRange(0, range.location + range.length), withBytes: nil, length: 0)

        return line as String?
    }

    /// Start reading from the beginning of file.
    func rewind() -> Void {
        fileHandle.seekToFileOffset(0)
        buffer.length = 0
        atEof = false
    }

    /// Close the underlying file. No reading must be done after calling this method.
    func close() -> Void {
        fileHandle?.closeFile()
        fileHandle = nil
    }
}
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • Thanks for doing my work :) (Jeef could have notified directly.) I will have a look at it and update the original answer when I am back at my computer. – Martin R Apr 09 '15 at 18:06
  • np, btw did you mean to write `delimData = delimiter.dataUsingEncoding(encoding)` or am I confused? – Airspeed Velocity Apr 09 '15 at 18:14
  • You are of course right, that error occurred when I added the `delimiter` parameter in revision 2. – Your code looks perfect. Is it OK if I use it to update my answer? – Martin R Apr 09 '15 at 19:57
  • also, nice to see legit uses of implicitly-unwrapped optionals for a change – Airspeed Velocity Apr 09 '15 at 19:59
0

Apple is tightening up the syntax of the language, so things that were allowed in previous versions are no longer allowed in Swift version 1.2. You will have to go through and clean up the code so that it compiles.

Duncan C
  • 128,072
  • 22
  • 173
  • 272