import Foundation class StreamReader { let encoding: NSStringEncoding let chunkSize: Int let fileHandle: NSFileHandle var buffer: NSMutableData let delimPattern : NSData var isAtEOF: Bool = false init?(_ handle: NSFileHandle, delimeter: String = "\n", encoding: NSStringEncoding = NSUTF8StringEncoding, chunkSize: Int = 4096) { self.fileHandle = handle self.chunkSize = chunkSize self.encoding = encoding self.buffer = NSMutableData(capacity: chunkSize)! self.delimPattern = delimeter.dataUsingEncoding(NSUTF8StringEncoding)! } deinit { fileHandle.closeFile() } func rewind() { fileHandle.seekToFileOffset(0) buffer = NSMutableData(capacity: chunkSize)! isAtEOF = false } func nextLine() -> String? { if isAtEOF { return nil } repeat { let range = buffer.rangeOfData(delimPattern, options: [], range: NSRange(location: 0,length: buffer.length)) if range.location != NSNotFound { if range.location == 0 { let remain = NSRange(location: range.length, length: buffer.length - range.length ) buffer = buffer.subdataWithRange(remain).mutableCopy() as! NSMutableData continue } let datarange = NSRange(location: 0, length: range.location) let lengthWithDelimiter = range.location + range.length let subData = buffer.subdataWithRange(datarange) let line = String(data: subData, encoding: encoding) let remain = NSRange(location: datarange.location + lengthWithDelimiter, length: buffer.length - lengthWithDelimiter ) buffer = buffer.subdataWithRange(remain).mutableCopy() as! NSMutableData return line } else { let tempData = fileHandle.readDataOfLength(chunkSize) if tempData.length == 0 { isAtEOF = true return (buffer.length > 0) ? String(data: buffer, encoding: encoding) : nil } buffer.appendData(tempData) } } while true } }