swift - 如何使用文件描述符快速转移写入文件?
问题描述
我想使用一些使用文件描述符的 C 代码。背景是我想从 cgraph 库中读取一些数据。
public extension UnsafeMutablePointer where Pointee == Agraph_t {
func saveTo(fileName: String) {
let f = fopen(cString(fileName), cString("w"))
agwrite(self,f)
fsync(fileno(f))
fclose(f)
}
}
我想要文件输出,但不写入临时文件。因此,我想做这样的事情:
public extension UnsafeMutablePointer where Pointee == Agraph_t {
var asString: String {
let pipe = Pipe()
let fileDescriptor = UnsafeMutablePointer<Int32>.allocate(capacity: 1)
fileDescriptor.pointee = pipe.fileHandleForWriting.fileDescriptor
agwrite(self, fileDescriptor)
let data = pipe.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: data, encoding: .utf8) {
return output
}
return ""
}
}
但它不起作用,导致 agwrite(,) 中出现 EXC_BAD_ACCESS。我需要做什么?提前谢谢了!
解决方案
文件描述符和文件指针不是一回事。FILE *
这很令人困惑,并且因为这个符号而对谷歌来说真的很难的事实更加令人沮丧。
您需要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
是阻塞调用,会导致不好的使用体验。最好将此代码在后台线程上运行,或者使用 aFileHandle.readabilityHandler
异步使用传入的数据。
推荐阅读
- android-studio - Android Studio 中关于 Spinners 和 `clickable` 属性的明确错误?
- flutter - 是否可以在文本和下划线之间有一定高度的文本下划线?
- spartacus-storefront - 自定义某些似乎不可覆盖的 cmsComponents
- mongodb - 只允许在内部服务调用上创建多个条目
- android - Here maps Premium SDK 中的渲染问题
- python - 如何在 TkInter 的函数中设置我的文本的字体大小和字体?
- java - 我有比 CopyOnWriteArrayList 和 Collections.synchronizedList 更好的选择吗?
- c# - C# Activator.CreateInstance 抽象类找不到构造函数
- python - 我正在尝试从 html 页面中检索当前页码,以便在 update_table 函数上针对分页进行 url 路由
- python - 以编程方式为视频添加一个简单的暂停