swift 中将 UInt8 数组的一段包装为字符串的正确方法是什么?
What is the correct way in swift to wrap a segment of a UInt8 array as a String?
我要在 iPhone 应用程序中处理一些原始数据。字符串总是来自一个非常大的底层字节数组,所以我希望能够从数组中提取字符串而不触发 内存不足 问题。
我可以在文档中看到一个 String(bytesNoCopy: ...)
,这是我想要的吗,应该如何使用它?
假设一个名为 data
的 uint8 数组,index
是一个数字,显示字符串在数组中的位置。
var myData:[UInt8] = [
4, // String 1 length
65,66,67,68,0, // String 1 data
4, // String 2 length
69,70,71,71,0 // String 2 data
]
var index = 0
let string1 = readString(&myData, &index)
let string2 = readString(&myData, &index)
print(string1, string2)
// Read a string located at a specific
// position in a byte array, and increment
// the pointer into the array into the next
// position
func readString(_ data:inout [UInt8], _ index:inout Int) -> String {
// Read string length out of data array
let l = Int(readUInt8(&data, &index))
// Read string out of data array without copy
let s = String(
bytesNoCopy: UnsafeMutableRawPointer(data + index), // <-- what goes here??
length: l,
encoding: .utf8,
freeWhenDone: false)
index = index + l
if s == nil {
return ""
}
return s!
}
// Read a byte as an integer from a
// data array, and increment the pointer into
// the data array to the next position.
func readUInt8(_ data:inout [UInt8], _ x:inout Int) -> UInt8 {
let v = data[x]
x = x + 1
return v
}
注意: 这个问题已更新为包含示例数据,并将变量 x
重命名为 index
以更清楚地表明问题在问如何从字节数组的 段 创建字符串。
以下是您可以尝试的方法 -
import Foundation
func readString(_ data: inout [UInt8], _ x: inout Int) -> String {
let l = 4
var slice: ArraySlice<UInt8> = data[x..<x+l] // No copy, view into existing Array
x += l
return slice.withUnsafeBytes({ pointer in
// No copy, just making compiler happy (assumption that it is bound to UInt8 is correct
if let bytes = pointer.baseAddress?.assumingMemoryBound(to: UInt8.self) {
return String(
bytesNoCopy: UnsafeMutableRawPointer(mutating: bytes), // No copy
length: slice.count,
encoding: .utf8,
freeWhenDone: false
) ?? ""
} else {
return ""
}
})
}
测试
var a: [UInt8] = [
65, 66, 67, 68,
69, 70, 71, 72
]
var x = 0
let test1 = readString(&a, &x)
print("test1 : \(test1)")
// test1 : ABCD
let test2 = readString(&a, &x)
print("test2 : \(test2)")
// test2 : EFGH
我要在 iPhone 应用程序中处理一些原始数据。字符串总是来自一个非常大的底层字节数组,所以我希望能够从数组中提取字符串而不触发 内存不足 问题。
我可以在文档中看到一个 String(bytesNoCopy: ...)
,这是我想要的吗,应该如何使用它?
假设一个名为 data
的 uint8 数组,index
是一个数字,显示字符串在数组中的位置。
var myData:[UInt8] = [
4, // String 1 length
65,66,67,68,0, // String 1 data
4, // String 2 length
69,70,71,71,0 // String 2 data
]
var index = 0
let string1 = readString(&myData, &index)
let string2 = readString(&myData, &index)
print(string1, string2)
// Read a string located at a specific
// position in a byte array, and increment
// the pointer into the array into the next
// position
func readString(_ data:inout [UInt8], _ index:inout Int) -> String {
// Read string length out of data array
let l = Int(readUInt8(&data, &index))
// Read string out of data array without copy
let s = String(
bytesNoCopy: UnsafeMutableRawPointer(data + index), // <-- what goes here??
length: l,
encoding: .utf8,
freeWhenDone: false)
index = index + l
if s == nil {
return ""
}
return s!
}
// Read a byte as an integer from a
// data array, and increment the pointer into
// the data array to the next position.
func readUInt8(_ data:inout [UInt8], _ x:inout Int) -> UInt8 {
let v = data[x]
x = x + 1
return v
}
注意: 这个问题已更新为包含示例数据,并将变量 x
重命名为 index
以更清楚地表明问题在问如何从字节数组的 段 创建字符串。
以下是您可以尝试的方法 -
import Foundation
func readString(_ data: inout [UInt8], _ x: inout Int) -> String {
let l = 4
var slice: ArraySlice<UInt8> = data[x..<x+l] // No copy, view into existing Array
x += l
return slice.withUnsafeBytes({ pointer in
// No copy, just making compiler happy (assumption that it is bound to UInt8 is correct
if let bytes = pointer.baseAddress?.assumingMemoryBound(to: UInt8.self) {
return String(
bytesNoCopy: UnsafeMutableRawPointer(mutating: bytes), // No copy
length: slice.count,
encoding: .utf8,
freeWhenDone: false
) ?? ""
} else {
return ""
}
})
}
测试
var a: [UInt8] = [
65, 66, 67, 68,
69, 70, 71, 72
]
var x = 0
let test1 = readString(&a, &x)
print("test1 : \(test1)")
// test1 : ABCD
let test2 = readString(&a, &x)
print("test2 : \(test2)")
// test2 : EFGH