If you need to read a very large file you’ll want to stream it so you’re not loading the entire thing into memory at once. Here’s a snippet for doing that.
class StreamingFileReader {
var fileHandle: FileHandle?
var buffer: Data
let bufferSize: Int = 1024
// Using new line as the delimiter
let delimiter = "\n".data(using: .utf8)!
init(path: String) {
fileHandle = FileHandle(forReadingAtPath: path)
buffer = Data(capacity: bufferSize)
}
func readLine() -> String? {
var rangeOfDelimiter = buffer.range(of: delimiter)
while rangeOfDelimiter == nil {
guard let chunk = fileHandle?.readData(ofLength: bufferSize) else { return nil }
if chunk.count == 0 {
if buffer.count > 0 {
defer { buffer.count = 0 }
return String(data: buffer, encoding: .utf8)
}
return nil
} else {
buffer.append(chunk)
rangeOfDelimiter = buffer.range(of: delimiter)
}
}
let rangeOfLine = 0 ..< rangeOfDelimiter!.upperBound
let line = String(data: buffer.subdata(in: rangeOfLine), encoding: .utf8)
buffer.removeSubrange(rangeOfLine)
return line?.trimmingCharacters(in: .whitespacesAndNewlines)
}
}
To use it:
let fileReader = StreamingFileReader(path: logFile)
while let line = fileReader.readLine() {
// Do something with the line
}
Found exactly what I was looking for. Thank you for sharing this Morgan. I am definitely sharing this with my project team.