如何用字符串,浮点数解析十六进制

耶尔比

我有二进制文件,其中包含位置和坐标(纬度,经度)的名称,每当我将其解析为String使用编码时,.ascii它都无法很好地解析它。我认为从Float值(坐标)进行解析失败。

InputStream

extension Data {
    init(reading input: InputStream) {
        self.init()
        input.open()

        let bufferSize = 1024
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
        while input.hasBytesAvailable {
            let read = input.read(buffer, maxLength: bufferSize)
            self.append(buffer, count: read)
        }
        buffer.deallocate()

        input.close()
    }
}

档案解析

let filepath = Bundle.main.path(forResource: "MN", ofType: "dat")
let data = Data.init(reading: InputStream(fileAtPath: filepath)!)
let parsedData = String.init(data: data, encoding: .ascii)

解析结果

有什么想法可以正确地解析吗?

例如,JavaObjectInputStream具有称为:

inputStreamObj.readUTF()
inputStreamObj.readFloat()

爪哇

在此处输入图片说明

OOPer

正如我在评论中所写,您需要阅读规范Object Serialization Stream Protocol

因此,前4个字节代表STREAM_MAGIC,STREAM_VERSION,应始终为相同值。5字节序列0x7A 0xhh 0xhh 0xhh 0xhh表示TC_BLOCKDATALONG(0xhhhhhhhh)。

并且在解析字符串和浮点数之前,需要将所有块连接在一起。

因此,准备DataReader

(与Sulthan's几乎相同,但这正确地对待了Modified UTF-8。)

struct DataReader {
    enum DataReaderError: Error {
        case invalidFirstByte(byte: UInt16, offset: Int)
        case invalidFollowingByte
        case missingFollowingByte
        case insufficientData
    }
    var data: Data
    var currentPosition: Int

    init(data: Data) {
        self.data = data
        self.currentPosition = 0
    }

    mutating func skipBytes(_ n: Int) {
        currentPosition += n
    }

    private mutating func readBigEndian<T: FixedWidthInteger>() throws -> T {
        guard currentPosition + MemoryLayout<T>.size <= data.count else {
            throw DataReaderError.insufficientData
        }
        var fixedWithInteger: T = 0
        let range: Range<Int> = currentPosition ..< currentPosition + MemoryLayout<T>.size
        withUnsafeMutableBytes(of: &fixedWithInteger) {ptrT in
            let uint8Ptr = ptrT.baseAddress!.assumingMemoryBound(to: UInt8.self)
            data.copyBytes(to: uint8Ptr, from: range)
        }
        currentPosition += MemoryLayout<T>.size
        return fixedWithInteger.bigEndian
    }

    mutating func readFloat() throws -> Float {
        let floatBits: UInt32 = try readBigEndian()
        return Float(bitPattern: floatBits)
    }

    mutating func readUnsignedShort() throws -> Int {
        let ushortValue: UInt16 = try readBigEndian()
        return Int(ushortValue)
    }

    mutating func readInt() throws -> Int {
        let intValue: Int32 = try readBigEndian()
        return Int(intValue)
    }

    mutating func readUnsignedByte() throws -> Int {
        guard currentPosition < data.count else {
            throw DataReaderError.insufficientData
        }
        let byte = data[currentPosition]
        currentPosition += 1
        return Int(byte)
    }

    mutating func readBytes(_ n: Int) throws -> Data {
        guard currentPosition + n <= data.count else {
            throw DataReaderError.insufficientData
        }
        let subdata = data[currentPosition ..< currentPosition+n]
        currentPosition += n
        return subdata
    }

    mutating func readUTF() throws -> String {
        //Get byte size of the string
        let count = try readUnsignedShort()
        //Decoding Modified UTF-8
        var utf16: [UInt16] = []
        var offset = 0
        while offset < count {
            let firstByte = UInt16(data[currentPosition + offset])
            if firstByte & 0b1_0000000 == 0b0_0000000 {
                utf16.append(firstByte)
                offset += 1
            } else if firstByte & 0b111_00000 == 0b110_00000 {
                guard offset + 1 < count else {throw DataReaderError.missingFollowingByte}
                let secondByte = UInt16(data[currentPosition + offset + 1])
                guard secondByte & 0b11_000000 == 0b10_000000 else {throw DataReaderError.invalidFollowingByte}
                let codeUnit = ((firstByte & 0b000_11111) << 6) | (secondByte & 0b00_111111)
                utf16.append(codeUnit)
                offset += 2
            } else if firstByte & 0b1111_0000 == 0b1110_0000 {
                guard offset + 2 < count else {throw DataReaderError.missingFollowingByte}
                let secondByte = UInt16(data[currentPosition + offset + 1])
                guard secondByte & 0b11_000000 == 0b10_000000 else {throw DataReaderError.invalidFollowingByte}
                let thirdByte = UInt16(data[currentPosition + offset + 2])
                guard thirdByte & 0b11_000000 == 0b10_000000 else {throw DataReaderError.invalidFollowingByte}
                let codeUnit = ((firstByte & 0b0000_1111) << 12) | ((secondByte & 0b00_111111) << 6) | (thirdByte & 0b00_111111)
                utf16.append(codeUnit)
                offset += 3
            } else {
                throw DataReaderError.invalidFirstByte(byte: firstByte, offset: currentPosition+offset)
            }
        }
        currentPosition += offset
        return String(utf16CodeUnits: &utf16, count: utf16.count)

    }

    var isAtEnd: Bool {
        return currentPosition == data.count
    }
}

我们可以将您解析MN.dat如下:

let mnUrl = Bundle.main.url(forResource: "MN", withExtension: "dat")!
do {
    let data = try Data(contentsOf: mnUrl)
    var reader = DataReader(data: data)
    reader.skipBytes(4)

    //First collect all blocks
    var blockData = Data()
    while !reader.isAtEnd {
        let contentType = try reader.readUnsignedByte()
        if contentType == 0x7A {//TC_BLOCKDATALONG
            let size = try reader.readInt()
            let block = try reader.readBytes(size)
            blockData.append(block)
        } else if contentType == 0x77 {//TC_BLOCKDATA
            let size = try reader.readUnsignedByte()
            let block = try reader.readBytes(size)
            blockData.append(block)
        } else {
            print("Unsupported content type")
            break
        }
    }
    //Then read the contents of blockData
    var blockReader = DataReader(data: blockData)
    while !blockReader.isAtEnd {
        let string = try blockReader.readUTF()
        print(string)
        let float1 = try blockReader.readFloat()
        print(float1)
        let float2 = try blockReader.readFloat()
        print(float2)
        //Use string, float1, float2 as you like
    }
} catch {
    print(error)
}

输出:

Albert Lea
43.648
-93.3683
Albertville
45.2377
-93.6544
Alexandria
45.8852
-95.3775
(... no errors...)
Woodbury
44.9239
-92.9594
Worthington
43.62
-95.5964
Wyoming
45.3364
-92.9972
Zimmerman
45.4433
-93.59

如果您的二进制数据可能包含其他内容类型,则可能需要修改上面的代码。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章