从字节数据

时间:2017-01-09 13:18:06

标签: swift swift3 type-conversion endianness

我需要从二进制文件格式中提取一些listmode bigEndian Float数据。我最初使用以下方法,它工作得很好,但我无法将其转换为Swift 3 ...

原文:(包含15个数据的20行的示例,在300个字节的标题之后开始)

let fileData: NSData = NSData(contentsOfFile: fileInfo.path)!
let ptr = UnsafePointer<UInt8>(fileData.bytes)
let byteOffset = 300
for i in 0..<20 {

    let byteOffset2 = byteOffset + (i * 15 * 4)

    for p in 0..<15 {
        let bits = UnsafePointer<Float._BitsType>(ptr + byteOffset2)[p].bigEndian
        let f = Float._fromBitPattern(bits)
        eventData[p] = f
    }
} 

新:(在自动Xcode转换和一些尝试调整以消除Xcode中的错误之后)

let fileData: Data = try! Data(contentsOf: URL(fileURLWithPath: fileInfo.path))
let ptr = (fileData as NSData).bytes.bindMemory(to: UInt32.self, capacity: fileData.count)
let byteOffset = 300

for i in 0..<20 {

    let byteOffset2 = byteOffset + (i * 15 * 4)

    for p in 0..<15 {
        let bits = UnsafePointer<UInt32>(ptr + byteOffset2)[p].bigEndian 
        let f = Float(bitPattern: bits)
        eventData[p] = f
    }
}

从新方法生成的值现在不正确...我已经摆弄了很长一段时间而且我很难过 - 任何建议都会非常感激。我在这个问题/答案中找到了我的原始方法:Swift: extract float from byte data但似乎Float._BitsType在Swift 3中不起作用。任何建议都将不胜感激......

2 个答案:

答案 0 :(得分:2)

问题(如果我猜对了)是您尝试的ptr Swift 3代码是指向UInt32的指针,而不是指向UInt8的指针 Swift 2版本。因此ptr + byteOffset2使指针前进 按4 * byteOffset2个字节,计算时必须考虑 补偿。

通常,您可以像这样简化对Data的访问:

data.withUnsafeBytes { (ptr: UnsafePointer<UInt32>) in

    let uint32Offset = 300/MemoryLayout<UInt32>.stride // 300/4 = 75

    for i in 0 ..< 20 {
        for p in 0 ..< 15 {

            let offset = uint32Offset + i * 15 + p
            let u32Value = UInt32(bigEndian: ptr[offset])
            let floatValue = Float(bitPattern: u32Value)
            // ...
        }
    }
}

答案 1 :(得分:0)

在没有任何建议的情况下,这对我有用。我可以看到它非常难看,可以做一些清理工作。除了使用UInt8指针(无论我如何调整偏移量),我似乎无法以其他方式获取数据。由于endian问题,我尝试创建一个[UInt8]数组,然后将其转换为UInt32。这是有效的,但任何改进都会非常受欢迎......

fileData.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) in
let byteOffset = 300
for i in 0..<20 {
    let byteOffset2 = byteOffset + (i * 15 * 4)
    for p in 0..<15 {
            var bitsArray = [UInt8]()
            for b in 0..<4 {
                let bits4 = UnsafePointer<UInt8>(ptr + byteOffset2 + b)[p * 4]
                bitsArray.append(bits4)
            }
            let bigEndianValue = bitsArray.withUnsafeBufferPointer {
                            ($0.baseAddress!.withMemoryRebound(to: UInt32.self, capacity: 1) { $0 })
                            }.pointee
            let u32Value = UInt32(bigEndian: bigEndianValue)
            let f = Float(bitPattern: u32Value)
            eventData[p] = f
        }
    }
}