Skip to content

Instantly share code, notes, and snippets.

@oliverepper
Last active February 20, 2021 09:21
Show Gist options
  • Save oliverepper/6cc6302fd8a27e4dfb2c44c4804cc85b to your computer and use it in GitHub Desktop.
Save oliverepper/6cc6302fd8a27e4dfb2c44c4804cc85b to your computer and use it in GitHub Desktop.
ReadOperation
//
// Created by Oliver Epper on 16.02.21.
//
//
import Combine
import Foundation
final class ReadOperation: Operation {
enum ReadOperationError: Error {
case cannotOpenFile(URL)
}
private let url: URL
private let linesToRead: Int?
private let subject = PassthroughSubject<String, ReadOperationError>()
var linePublisher: AnyPublisher<String, ReadOperationError> {
subject.eraseToAnyPublisher()
}
init(url: URL, lines linesToRead: Int? = nil) {
self.url = url
self.linesToRead = linesToRead
super.init()
}
override func main() {
guard !isCancelled else {
return
}
guard let filePointer: UnsafeMutablePointer<FILE> = fopen(url.path, "r") else {
subject.send(completion: .failure(.cannotOpenFile(url)))
return
}
var buffer: UnsafeMutablePointer<CChar>?
var lineCap: Int = 0
var bytes = 0
var readLines = 0
defer {
free(buffer)
fclose(filePointer)
}
bytes = getline(&buffer, &lineCap, filePointer)
while bytes > 0, !isCancelled {
if readLines == linesToRead {
break
}
let line = String(cString: buffer!).trimmingCharacters(in: .newlines)
subject.send(line)
bytes = getline(&buffer, &lineCap, filePointer)
readLines += 1
}
subject.send(completion: .finished)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment