解码某些 Base64 字符串时出错,但其他字符串则不会出错

Pan*_*man 1 arrays base64 ios swift

为了保持简单,我将只编码/解码单个字节。

\n\n

如果我对字节 127 进行编码,我会得到 base64 字符串“fw==”,它可以成功解码回字节 127。但是,如果我对字节 \xe2\x89\xa5 128 进行编码,那么即使我可以生成没有错误的 Base64 字符串(例如,字节 128 给出字符串“gA==”),当我尝试对其进行解码时出现错误。

\n\n

这是我的代码,可以将其复制粘贴到任何 Xcode Playground 中以重现该问题:

\n\n
func stringToByteArray(string: String) -> [UInt8] {\n    var bytes: [UInt8] = [];\n    for code in string.utf8 {\n        bytes.append(UInt8(code));\n    }\n    return bytes;\n}\n\nfunc byteArrayToBase64(bytes: [UInt8]) -> String {\n    let nsdata: NSData = NSData(bytes: bytes as [Byte], length: bytes.count)\n    let base64Encoded: NSString = nsdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0));\n    return String(base64Encoded);\n}\n\nfunc base64ToByteArray(base64String: String) -> [UInt8] {\n    let nsdata: NSData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))!\n    let base64Decoded: NSString = NSString(data: nsdata, encoding: NSUTF8StringEncoding)!\n    return stringToByteArray(String(base64Decoded));\n}\n\n/* Replacing 127 with 128 below or greater produces an error */\nvar testString = byteArrayToBase64([127]);\nbase64ToByteArray(testString)\n
Run Code Online (Sandbox Code Playgroud)\n

Mar*_*n R 5

问题就在这里:

let base64Decoded: NSString = NSString(data: nsdata, encoding: NSUTF8StringEncoding)!
Run Code Online (Sandbox Code Playgroud)

您将解码后的数据转换为字符串。此操作失败, [128]因为它不代表有效的 UTF-8 序列。

这是避免中间字符串的版本:

func base64ToByteArray(base64String: String) -> [UInt8] {
    let nsdata: NSData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))!
    // Create array of the required size ...
    var bytes = [UInt8](count: nsdata.length, repeatedValue: 0)
    // ... and fill it with the data
    nsdata.getBytes(&bytes)
    return bytes
}
Run Code Online (Sandbox Code Playgroud)

评论:

  • options: NSDataBase64DecodingOptions(rawValue: 0)可以简化为options: nil.
  • 您的代码中有一些不必要的类型注释和转换。
  • baseString如果不是有效的 Base64 字符串,您的函数将崩溃。您可以更改它以返回可选值。

然后它看起来像这样:

func byteArrayToBase64(bytes: [UInt8]) -> String {
    let nsdata = NSData(bytes: bytes, length: bytes.count)
    let base64Encoded = nsdata.base64EncodedStringWithOptions(nil);
    return base64Encoded;
}

func base64ToByteArray(base64String: String) -> [UInt8]? {
    if let nsdata = NSData(base64EncodedString: base64String, options: nil) {
        var bytes = [UInt8](count: nsdata.length, repeatedValue: 0)
        nsdata.getBytes(&bytes)
        return bytes
    }
    return nil // Invalid input
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

let testString = byteArrayToBase64([127, 128, 0, 130]);
println(testString) // Output: f4AAgg==
if let result = base64ToByteArray(testString) {
    println(result) // Output: [127, 128, 0, 130]
} else {
    println("failed")
}
Run Code Online (Sandbox Code Playgroud)

Swift 2 / Xcode 7更新:

func byteArrayToBase64(bytes: [UInt8]) -> String {
    let nsdata = NSData(bytes: bytes, length: bytes.count)
    let base64Encoded = nsdata.base64EncodedStringWithOptions([]);
    return base64Encoded;
}

func base64ToByteArray(base64String: String) -> [UInt8]? {
    if let nsdata = NSData(base64EncodedString: base64String, options: []) {
        var bytes = [UInt8](count: nsdata.length, repeatedValue: 0)
        nsdata.getBytes(&bytes, length: bytes.count)
        return bytes
    }
    return nil // Invalid input
}

let testString = byteArrayToBase64([127, 128, 0, 130]);
print(testString) // Output: f4AAgg==
if let result = base64ToByteArray(testString) {
    print(result) // Output: [127, 128, 0, 130]
} else {
    print("failed")
}
Run Code Online (Sandbox Code Playgroud)

Swift 3及更高版本的更新:

func byteArrayToBase64(bytes: [UInt8]) -> String {
    let data = Data(bytes)
    let base64Encoded = data.base64EncodedString()
    return base64Encoded;
}

func base64ToByteArray(base64String: String) -> [UInt8]? {
    guard let data = Data(base64Encoded: base64String)  else {
        return nil
    }
    return Array(data)
}

let testString = byteArrayToBase64(bytes: [127, 128, 0, 130]);
print(testString) // Output: f4AAgg==
if let result = base64ToByteArray(base64String: testString) {
    print(result) // Output: [127, 128, 0, 130]
} else {
    print("failed")
}
Run Code Online (Sandbox Code Playgroud)