Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sakiwei/afeeaf3e8290820cb98244a717673063 to your computer and use it in GitHub Desktop.
Save sakiwei/afeeaf3e8290820cb98244a717673063 to your computer and use it in GitHub Desktop.
import Foundation
// ref: http://stackoverflow.com/questions/3707427/how-to-read-data-from-nsfilehandle-line-by-line
class FileReader {
private let fileHanlde: NSFileHandle
private let lineDelimiter = "\n"
private let chunkSize: Int = 16
private let totalFileLen: UInt64
private var currentOffset: UInt64 = 0
init?(path: String) {
guard let fh = NSFileHandle(forReadingAtPath: path) else { return nil }
fileHanlde = fh
fileHanlde.seekToEndOfFile()
totalFileLen = fileHanlde.offsetInFile
}
deinit {
fileHanlde.closeFile()
}
func readLine() -> String? {
guard let newLineData = lineDelimiter.dataUsingEncoding(NSUTF8StringEncoding) where currentOffset < totalFileLen else { return nil }
fileHanlde.seekToFileOffset(currentOffset)
let currentData = NSMutableData()
var shouldReadMore = true
autoreleasepool {
while (shouldReadMore) {
if currentOffset >= totalFileLen {
break;
}
var chunk = fileHanlde.readDataOfLength(chunkSize);
let newLineRange = chunk.rangeOfData_dd(newLineData)
if newLineRange.location != NSNotFound {
// include the length so we can include the delimiter in the string
chunk = chunk.subdataWithRange(NSMakeRange(0, newLineRange.location + newLineData.length))
shouldReadMore = false
}
currentData.appendData(chunk)
currentOffset += UInt64(chunk.length)
}
}
return NSString(data: currentData, encoding: NSUTF8StringEncoding) as? String
}
func readTrimmedLine() -> String? {
return self.readLine()?.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
}
func enumerateLines(callback: (String) -> Bool) {
var stop = false
while !stop {
if let l = self.readLine() {
// if returns false from callback, the loop will exit
stop = !callback(l)
} else {
break;
}
}
}
}
extension NSData {
func rangeOfData_dd(dataToFind: NSData) -> NSRange {
let bytes = self.bytes
let len = self.length
let searchBytes = dataToFind.bytes
let searchLen = dataToFind.length
var searchIndex = 0
var foundRange = NSMakeRange(NSNotFound, searchLen)
for i in 0..<len {
if UnsafePointer<CChar>(bytes)[i] == UnsafePointer<CChar>(searchBytes)[searchIndex] {
if foundRange.location == NSNotFound {
foundRange.location = i
}
searchIndex += 1
if searchIndex >= searchLen {
return foundRange
}
} else {
searchIndex = 0
foundRange.location = NSNotFound
}
}
return foundRange
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment