使用 OutputStream 将 CircularBuffer (swift-nio) 写入 Swift 中的文件?

Write a CircularBuffer (swift-nio) to a file in Swift using OutputStream?

我正在尝试使用 SwiftNIO 中的 CircularBuffer<UInt8> 来存储数据,一旦缓冲区几乎满了,就使用 OutputStream 将内容转储到文件中。不幸的是, OutputStream.write() 方法将 UnsafePointer 作为参数,而 CircularBuffer 可以输出 UnsafeBufferPointer 。有没有办法将 CircularBuffer 转换为 UnsafePointer

我尝试使用以下代码扩展 CircularBuffer,我成功地将结构转换为字节数组,因为有人建议 CircularBuffer 实际上是一个结构,但我的输出文件中出现垃圾:

extension CircularBuffer {
    func toBytes() -> [UInt8] {
        let capacity = MemoryLayout<Self>.size
        var mutableValue = self
        return withUnsafePointer(to: &mutableValue) {
            return [=12=].withMemoryRebound(to: UInt8.self, capacity: capacity) {
                return Array(UnsafeBufferPointer(start: [=12=], count: capacity))
            }
        }
    }
}

有什么想法吗?

CircularBuffer 是一个带有内部 ContiguousArray 元素存储的结构。 ContiguousArray 也是一个结构,具有指向实际元素存储的内部指针。

您当前的代码会产生垃圾,因为它 returns struct CircularBuffer 本身的内存表示,而不是它所表示的元素的字节。

作为一个集合,CircularBuffer 有一个 withContiguousStorageIfAvailable() 方法,它调用一个带有指向元素存储的指针的闭包 如果存在这样的连续存储。使用 UnsafeBufferPointer 参数调用闭包,您可以从中获得 baseAddress:

var buffer: CircularBuffer<UInt8> = ...
let os: OutputStream = ...
// ...
let amountWritten =  buffer.withContiguousStorageIfAvailable {
    os.write([=10=].baseAddress!, maxLength: [=10=].count)
}

但是有一个问题:CircularBuffer只是继承了Sequence的默认实现,而returnsnil没有调用闭包。这是一个known issue。所以上面的代码可以编译,但不能工作。

一种简单的方法(以复制内容为代价)是使用您可以从集合中初始化数组:

var buffer: CircularBuffer<UInt8> = ...
let os: OutputStream = ...
// ...
let contents = Array(buffer)
let amountWritten = os.write(contents, maxLength: contents.count)

您也可以一次一个地循环浏览缓冲区的元素,尽管这可能效率很低:

    var cb = CircularBuffer<UInt8>()
    cb.append(contentsOf:[1,2,3])
    cb.append(contentsOf:[4,5,6])
    let stream = OutputStream.toMemory()
    stream.open()
    for var i in cb {
        stream.write(&i, maxLength:1)
        print(i)
    }
    stream.close()
    print(stream.property(forKey: .dataWrittenToMemoryStreamKey) as Any)