根据 swift 中的特定值拆分或分块 NSData

Splitting or Chunking NSData on specific value(s) in swift

我正在尝试弄清楚如何根据特定值“分块”NSData

输入数据

7E 55 33 22 7E 7E 22 AE BC 7E 7E AA AA 00 20 00 22 53 25 A3 4E 7E

输出数据

Returns 类型为 [NSData] 的 3 个元素的数组,其中元素为:

我在哪里

我知道我可以做类似的事情:

var ptr = UnsafePointer<UInt8>(data.bytes)
var bytes = UnsafeBufferPointer<UInt8>(start: ptr, count: data.length)

而且我想通过进行类似于以下的比较来迭代:

bytes[1] == UInt8(0x7E)

我想建立“范围”,但我想知道是否有更好的方法来解决这个问题?

代码存根

private fund chunkMessage(data: NSData) -> [NSData] {
  var ptr = UnsafePointer<UInt8>(data.bytes)
  var bytes = UnsafeBufferPointer<UInt8>(start: ptr, count: data.length)
  var ret = []

 // DO SOME STUFF

  return ret as! [NSData];

}

可能有很多可能的解决方案。一种直接的方式,使用 NSData 方法,将是

func chunkMessage(data: NSData, var separator : UInt8) -> [NSData] {
    let sepdata = NSData(bytes: &separator, length: 1)
    var chunks : [NSData] = []

    // Find first occurrence of separator:
    var searchRange = NSMakeRange(0, data.length)
    var foundRange = data.rangeOfData(sepdata, options: nil, range: searchRange)
    while foundRange.location != NSNotFound {
        // Append chunk (if not empty):
        if foundRange.location > searchRange.location {
            chunks.append(data.subdataWithRange(NSMakeRange(searchRange.location, foundRange.location - searchRange.location)))
        }
        // Search next occurrence of separator:
        searchRange.location = foundRange.location + foundRange.length
        searchRange.length = data.length - searchRange.location
        foundRange = data.rangeOfData(sepdata, options: nil, range: searchRange)
    }
    // Check for final chunk:
    if searchRange.length > 0 {
         chunks.append(data.subdataWithRange(searchRange))
    }
    return chunks
}

正如评论中已经建议的那样,您可以使用 Swift 数组 反而。这是一个可能的实现:

func chunkMessage(data: NSData, separator : UInt8) -> [[UInt8]] {

    let bytes = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes), count: data.length)

    // Positions of separator bytes:
    let positions = filter(enumerate(bytes), {  == separator } ).map( { [=11=].0 } )

    // Non-empty ranges between the separator bytes:
    let ranges = map(Zip2([-1] + positions, positions + [bytes.count])) {
        (from : Int, to : Int) -> (Int, Int) in
        (from + 1, to - from - 1)
        }.filter( {  > 0 } )

    // Byte chunks between the separator bytes:
    let chunks = map(ranges) {
        (start: Int, count : Int) -> [UInt8] in
        Array(UnsafeBufferPointer(start: bytes.baseAddress + start, count: count))
    }

    return chunks
}

我留给你来测试哪个表现更好:)

我 运行 遇到了类似的情况,但我只是想按特定大小对数据进行分块,下面是我如何让它在 swift 2.0 中工作。这假设 "data" 是 NSData 类型,并且已经填充了您要拆分的信息:

    let length = data.length
    let chunkSize = 1048576      // 1mb chunk sizes
    var offset = 0

    repeat {
        // get the length of the chunk
        let thisChunkSize = ((length - offset) > chunkSize) ? chunkSize : (length - offset);

        // get the chunk
        let chunk = data.subdataWithRange(NSMakeRange(offset, thisChunkSize))

        // -----------------------------------------------
        // do something with that chunk of data...
        // -----------------------------------------------

        // update the offset
        offset += thisChunkSize;

    } while (offset < length);

希望对大家有所帮助

Swift 你使用的基于 adan1985 的 3 个解决方案

  let length = data.count
  let chunkSize = 500
  var offset = 0

  repeat {
    // get the length of the chunk
    let thisChunkSize = ((length - offset) > chunkSize) ? chunkSize : (length - offset);

    // get the chunk
    let chunk = data.subdata(in: offset..<offset + thisChunkSize )

    // -----------------------------------------------
    // do something with that chunk of data...
    // -----------------------------------------------

    // update the offset
    offset += thisChunkSize;

  } while (offset < length);

Swift 3 这行得通,扩展到 Data

//: Playground - noun: a place where people can play

import Cocoa
import Foundation

var str = "Hello, playground"

let d : Data = Data(bytes: [0x7E, 0x55, 0x33, 0x22, 0x7E, 0x7E, 0x22, 0xAE, 0xBC, 0x7E, 0x7E, 0xAA, 0xAA, 0x00, 0x20, 0x00, 0x22, 0x53, 0x25, 0xA3, 0x4E, 0x7E])

let f = d.separateData(bySeparator: 0x7E)
print(f) // [[0x55, 0x33, 0x22],[0x22, 0xAE, 0xBC],[0xAA, 0xAA, 0x00, 0x20, 0x00, 0x22, 0x53, 0x25, 0xA3, 0x4E]
//
//  Data+Separate.swift
//  Created by Julian Bleecker on 6/7/17.
//


public extension Data {

    /// Separate data into an array of an array of Int8
    func separateData(bySeparator : UInt8) -> [[UInt8]] {
        let bytes = [UInt8](self)

        let split = bytes.split(separator: bySeparator)

        let bunks = split.enumerated().map( { [=10=].1 } )

        let chunks = bunks.enumerated().map( {
            Data.init([=10=].element).toArray(type: UInt8.self)
        })

        return chunks
    }
    /// Bonus. Convert to an array of Strings which would be separated by nulls
    func separateDataToStrings(encoding: String.Encoding)  -> [String] {
        let strunks: [String] = self.separateData(bySeparator: 0x00).enumerated().map( {
            let d: Data = Data.init(bytes: [=10=].element)
            return String(data: d, encoding: .utf8)!
        })
        return strunks
    }

    func toArray<T>(type: T.Type) -> [T] {
        return self.withUnsafeBytes {
            [T](UnsafeBufferPointer(start: [=10=], count: self.count/MemoryLayout<T>.stride))
        }
    }
}