Created
July 16, 2016 17:47
-
-
Save sakiwei/afeeaf3e8290820cb98244a717673063 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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