在Swift和Java中将字符串转换为Base64字节数组会得到不同的值

6

对于安卓系统,一切都运作得很好。我希望也能在iOS系统中实现相同的功能,但是得到了不同的结果值。请查看下面附带图片的描述。

Java/Android情况:

我尝试在Java中将字符串转换为base64字节数组,如下所示:

 byte[] data1 = Base64.decode(balance, Base64.DEFAULT);

输出结果: 在此输入图像描述

在Swift3/iOS中:

我尝试将字符串转换为base64字节数组,Swift代码如下:

let data:Data = Data(base64Encoded: balance, options: NSData.Base64DecodingOptions(rawValue: 0))!
let data1:Array = (data.bytes)

输出: 在此输入图片描述


1
不同的值?-55201看起来几乎是“相等”的,不是吗?我的意思是在iOS中,它是UInt8(在您的屏幕截图中可以看到),而在Java中我猜它是Int8,意味着无符号与有符号(因此为0到255和-127到128)。 - Larme
1
非常感谢您的回答,@Larme。 - jazzbpn
1
@Larme,我还想知道另一件事。如何将Int8/UInt8字节数组转换为可读的字符串格式?我尝试使用以下方式进行字符串转换。但它打印出来的不是有效的UTF-8序列。如果让字符串等于String(data: data, encoding: .utf8),{打印字符串}否则{打印“不是有效的UTF-8序列”} - jazzbpn
1
请参考以下链接:https://dev59.com/sFkT5IYBdhLWcg3wFryj。如果您想使用“int”而不是“hex”,则可使用不同的格式,详见 https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1。 - Larme
2个回答

6

问题终于解决了:

这是由于有符号和无符号整数的原因,即无符号与有符号(因此为0到255和-127到128)。在这里,我们需要将UInt8数组转换为Int8数组,问题就会得到解决。

let intArray = data1.map { Int8(bitPattern: $0) }

0
在任何情况下都不应该像你刚才做的那样比较两个系统上的数据,无论是哪种类型,尤其是原始数据。
原始数据在没有附加环境的情况下是不可展示的,这意味着任何显示它们的系统都可以选择如何显示它们(原始数据可能代表UTF8或ASCII中的一些文本、JPEG图像或PNG或原始RGB像素数据,可能是一个音频样本或其他什么)。在你的情况下,一个系统将它们显示为有符号的8位整数列表,而另一个系统则使用相同内容的无符号8位整数。另一个系统可能会以十六进制字符串的形式显示,这看起来完全不同。
正如@Larme已经提到的,这些看起来是相同的,因为可以安全地假定一个系统使用了有符号值,而另一个系统使用了无符号值。因此,要从有符号(Android)转换为无符号(iOS),需要将负值转换为unsigned = 256+signed,例如-55 => 256 + (-55) = 201
如果你真的需要比较数据,在你的情况下最好将它们保存为某些文件作为原始数据。然后将该文件传输到另一个系统,并将本机原始数据与文件中的数据进行比较,以检查是否真的存在差异。
编辑(来自评论):

将原始数据作为字符串打印是一个问题,但有几种方法可以解决。问题在于许多字节不能作为字符串打印,可能是空格或一些保留代码,但大多数问题在于值为0的情况,在大多数情况下表示字符串的结尾,这可能存在于您的字节序列中间。

因此,您已经有了两种逐字节打印的方式,即显示Int8Uint8相应的值。如评论所述,直接转换为字符串可能不像想象的那么容易。

let string = String(data: data, encoding: .utf8) // Will return nil for strange strings

一种将数据转换为字符串的方法可能是将每个字节转换为相应的字符。请检查以下代码:
let characterSequence = data.map { UnicodeScalar($0) } // Create an array of characters from bytes
let stringArray = characterSequence.map { String($0) } // Create an array of strings from array of characters
let myString = stringArray.reduce("", { $0 + $1 }) // Convert an array of strings to a single string

let myString2 = data.reduce("", { $0 + String(UnicodeScalar($1)) }) // Same thing in a single line

然后我使用以下代码进行测试:

let data = Data(bytes: Array(0...255)) // Generates with byte values of 0, 1, 2... up to 255
let myString2 = data.reduce("", { $0 + String(UnicodeScalar($1)) })
print(myString2)

打印结果为:

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ

另一种流行的方法是使用十六进制字符串。它可以显示为:

let hexString = data.reduce("", { $0 + String(format: "%02hhx",$1) })
print(hexString)

使用之前相同的数据,结果为:

000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff

我希望这已经足够了,但总的来说,你可以用字节数组做任何事情并展示它们。例如,如果有意义的话,你可以将字节视为RGB 8位每个分量的图像进行创建。这听起来可能很傻,但如果你正在寻找一些模式,这可能是一个相当机智的解决方案。


Matic非常感谢您的回答,我还想知道一件事。如何将Int8 / UInt8字节数组转换为可读的字符串格式?在这里,我尝试使用以下方式将其转换为字符串。但它打印出无效的UTF-8序列。 如果让字符串= String(data:data,encoding:.utf8),则{             打印(字符串)         }否则{             打印(“不是有效的UTF-8序列”)         } - jazzbpn
@jazzbpn,请检查我的编辑并让我知道这是否解释清楚了。 - Matic Oblak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接