在 iOS 上使用 Swift 使用 zlib 压缩字符串

问题描述 投票:0回答:0

我的 iOS 应用程序从后端获取压缩数据,然后将其解压缩为人类可读的字符串。这是我用来解压的函数:

import Compression

func decompress(_ data: Data) -> String? {
  guard let string = String(data: data, encoding: .utf8),
        let data = Data(base64Encoded: string)
  else { return nil }
  let headerSize = 2
  let size = compression_decode_scratch_buffer_size(COMPRESSION_ZLIB)
  let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
  defer { buffer.deallocate() }
  let result = data.subdata(in: headerSize..<data.count).withUnsafeBytes {
    guard let baseAddress = $0.baseAddress else {
      return ""
    }
    let decompressedSize = compression_decode_buffer(
      buffer,
      size,
      baseAddress.bindMemory(to: UInt8.self, capacity: 1),
      data.count - headerSize,
      nil,
      COMPRESSION_ZLIB
    )
    guard decompressedSize > 0 else {
      return ""
    }
    return String(
      decoding: Data(bytes: buffer, count: decompressedSize),
      as: UTF8.self
    )
  } as String
  guard !result.isEmpty else {
    return nil
  }
  return result
}

我需要一个反向函数,它返回给定未压缩字符串的压缩数据:

func compress(_ string: String) -> Data?

我正在努力实施。这是我试过的:

import Compression

func compress(_ string: String) -> Data? {
  guard let data = string.data(using: .utf8) else {
    return nil
  }
  let bufferSize = data.count + data.count / 2 + 12
  var buffer = [UInt8](repeating: 0, count: bufferSize)
  let compressedSize = data.withUnsafeBytes {
    guard let baseAddress = $0.baseAddress else {
      return 0
    }
    return compression_encode_buffer(
      &buffer,
      buffer.count,
      baseAddress.assumingMemoryBound(to: UInt8.self),
      data.count,
      nil,
      COMPRESSION_ZLIB
    )
  }
  guard compressedSize > 0 else {
    return nil
  }
  return Data(bytes: buffer, count: compressedSize)
}

虽然它确实压缩了字符串,但它不是我使用的

decompress
函数的反向操作:

let string = "Hello, World!"
let compressedData = compress(string)! // Data(74 bytes)
let decompressedString = decompress(compressedData) // nil

根据后端返回的数据,

decompress
函数被证明可以正常工作。我正在使用 Swift 5.8 并以 iOS 16 为目标。

提前感谢您的任何提示和建议。


更新 1.

排查问题后,我想到可以简化功能。我可以删除 base64 字符串转换并仅对原始

Data
类型进行操作。

我让它与以下实现一起工作:

import Foundation
import Compression

func compress(_ data: Data) -> Data? {
  var buffer = [UInt8](
    repeating: 0,
    count: compression_encode_scratch_buffer_size(COMPRESSION_ZLIB)
  )
  let compressedSize = data.withUnsafeBytes {
    guard let baseAddress = $0.baseAddress else {
      return 0
    }
    return compression_encode_buffer(
      &buffer,
      buffer.count,
      baseAddress.assumingMemoryBound(to: UInt8.self),
      data.count,
      nil,
      COMPRESSION_ZLIB
    )
  }
  guard compressedSize > 0 else {
    return nil
  }
  return Data(bytes: buffer, count: compressedSize)
}

func decompress(_ data: Data) -> Data? {
  let headerSize = 0
  var buffer = [UInt8](
    repeating: 0,
    count: compression_decode_scratch_buffer_size(COMPRESSION_ZLIB)
  )
  let subdata = data.subdata(in: headerSize..<data.count)
  let decompressedSize = subdata.withUnsafeBytes { sourcePtr in
    guard let baseAddress = sourcePtr.baseAddress else {
      return 0
    }
    return compression_decode_buffer(
      &buffer,
      buffer.count,
      baseAddress.assumingMemoryBound(to: UInt8.self),
      subdata.count,
      nil,
      COMPRESSION_ZLIB
    )
  }
  guard decompressedSize > 0 else {
    return nil
  }
  return Data(bytes: buffer, count: decompressedSize)
}

适用于以下示例:

let string = "Hello, World!"
let compressed = compress(string.data(using: .utf8)!)!
let decompressed = decompress(compressed)!
let decompressedString = String(data: decompressed, encoding: .utf8)
decompressedString == string // ✅ true

但是,这不适用于后端返回给我的数据。为了让它工作,我需要在

headerSize
函数中将
2
值更改为
decompress
。当我这样做时,我可以从后端解压数据,但我的
compress
功能不再正常工作。我真的不明白标题大小是多少,以及如何更新
compress
函数,因此它与我的
decompress
函数对称,
headerSize
等于
2
.

ios swift compression zlib
© www.soinside.com 2019 - 2024. All rights reserved.