Файловые дескрипторы и файловые указатели - это не одно и то же . Это сбивает с толку, и еще более расстраивает тот факт, что FILE *
действительно сложно для Google из-за символа.
Вам нужно fdopen
дескриптор файла (pipe.fileHandleForWriting.fileDescriptor
), чтобы получить FILE *
(UnsafeMutablePointer<FILE>
в Swift). Это то, что вы затем передаете на agwrite
.
Важно fclose
указатель файла, когда вы закончите запись в него, иначе .readDataToEndOfFile()
никогда не прекратит работу. Я сделал вспомогательную функцию, чтобы гарантировать, что fclose
не может быть забыт. Возможно, что agwrite
закрывает сам указатель файла, внутренне. Если это так, вы должны удалить этот код и просто дать ему результат fdopen
, простой и понятный.
import Foundation
public typealias Agraph_t = Int // Dummy value
public struct AGWriteWrongEncoding: Error { }
func agwrite(_: UnsafeMutablePointer<Agraph_t>, _ filePointer: UnsafeMutablePointer<FILE>) {
let message = "This is a stub."
_ = message.withCString { cString in
fputs(cString, stderr)
}
}
@discardableResult
func use<R>(
fileDescriptor: Int32,
mode: UnsafePointer<Int8>!,
closure: (UnsafeMutablePointer<FILE>) throws -> R
) rethrows -> R {
// Should prob remove this `!`, but IDK what a sensible recovery mechanism would be.
let filePointer = fdopen(fileDescriptor, mode)!
defer { fclose(filePointer) }
return try closure(filePointer)
}
public extension UnsafeMutablePointer where Pointee == Agraph_t {
func asString() throws -> String {
let pipe = Pipe()
use(fileDescriptor: pipe.fileHandleForWriting.fileDescriptor, mode: "w") { filePointer in
agwrite(self, filePointer)
}
let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let output = String(data: data, encoding: .utf8) else {
throw AGWriteWrongEncoding()
}
return output
}
}
let ptr = UnsafeMutablePointer<Agraph_t>.allocate(capacity: 1) // Dummy value
print(try ptr.asString())
Несколько других вещей:
- Выдача ошибки вероятно, лучший выбор, чем возвращение
""
. Пустые строки не являются хорошим механизмом обработки ошибок. Возврат необязательного также будет работать, но, в любом случае, он всегда будет принудительно развернут. readDataToEndOfFile
- это блокирующий вызов, который может привести к неправильному использованию. Вероятно, лучше всего, чтобы этот код выполнялся в фоновом потоке или использовал FileHandle.readabilityHandler
для асинхронного потребления данных по мере их поступления.