0

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

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

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

有什么想法吗?

4

2 回答 2

1

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

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

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

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

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

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

var buffer: CircularBuffer<UInt8> = ...
let os: OutputStream = ...
// ...
let contents = Array(buffer)
let amountWritten = os.write(contents, maxLength: contents.count)
于 2020-09-29T20:20:38.970 回答
1

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

    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)
于 2020-09-29T20:48:10.530 回答