【问题标题】:Write a CircularBuffer (swift-nio) to a file in Swift using OutputStream?使用 OutputStream 将 CircularBuffer (swift-nio) 写入 Swift 中的文件?
【发布时间】:2021-01-15 11:15:59
【问题描述】:

我正在尝试使用来自 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 $0.withMemoryRebound(to: UInt8.self, capacity: capacity) {
                return Array(UnsafeBufferPointer(start: $0, count: capacity))
            }
        }
    }
}

有什么想法吗?

【问题讨论】:

  • 如果你有一个 UnsafeBufferPointer 那么你可以通过它的.baseAddress 来获得一个 UnsafePointer。
  • stackoverflow.com/questions/64120725/… 的副本?你不能通过再次问同样的问题来逃避重复。
  • 抱歉,matt 以为它已经被删除了。
  • 虽然我同意应该改进一个问题(而不是删除并再次询问),但我也认为另一个问题已被错误地关闭为重复。这不是将结构写入文件,而是将循环缓冲区结构的“内容”写入文件。

标签: swift circular-buffer swift-nio


【解决方案1】:

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

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

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

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

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

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

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

【讨论】:

  • 所以目前,除了将内容复制到数组然后输出之外别无选择:(谢谢您的回复。
  • @jiko: 内部存储是Element?的数组,即可选的,所以实际上没有指向Elements的连续存储的指针可以传递给write方法(这在我链接到的 GitHub 问题中进行了讨论)。所以你必须以某种方式提取元素。要么一起作为一个数组,要么按照马特的建议一个接一个。
【解决方案2】:

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

    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)

【讨论】:

    猜你喜欢
    • 2019-09-13
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 2014-09-18
    • 2014-09-01
    • 2016-12-23
    • 1970-01-01
    • 2021-05-30
    相关资源
    最近更新 更多