将字符数组转换为字节数组,然后再返回

我正在寻找转换Java字符数组到一个字节数组而不创build一个中间String ,因为字符数组包含一个密码。 我查了一些方法,但他们似乎都失败了:

 char[] password = "password".toCharArray(); byte[] passwordBytes1 = new byte[password.length*2]; ByteBuffer.wrap(passwordBytes1).asCharBuffer().put(password); byte[] passwordBytes2 = new byte[password.length*2]; for(int i=0; i<password.length; i++) { passwordBytes2[2*i] = (byte) ((password[i]&0xFF00)>>8); passwordBytes2[2*i+1] = (byte) (password[i]&0x00FF); } String passwordAsString = new String(password); String passwordBytes1AsString = new String(passwordBytes1); String passwordBytes2AsString = new String(passwordBytes2); System.out.println(passwordAsString); System.out.println(passwordBytes1AsString); System.out.println(passwordBytes2AsString); assertTrue(passwordAsString.equals(passwordBytes1) || passwordAsString.equals(passwordBytes2)); 

断言总是失败(而且,批判地说,当代码在生产中被使用时,密码被拒绝),然而打印语句打印出三次密码。 为什么passwordBytes1AsStringpasswordBytes2AsString不同于passwordAsString ,但看起来是相同的? 我错过了一个空终止符或什么? 我能做些什么来使转换和非转换工作?

问题是你使用String(byte[])构造函数,它使用平台的默认编码。 这几乎从来没有你应该做的 – 如果你传递“UTF-16”作为字符编码工作,你的testing可能会通过。 目前我怀疑passwordBytes1AsStringpasswordBytes2AsString是每个16个字符长,其他每个字符是U + 0000。

字符和字节之间的转换是字符集编码和解码。我希望在代码中尽可能清楚。 这并不意味着额外的代码量:

  Charset latin1Charset = Charset.forName("ISO-8859-1"); charBuffer = latin1Charset.decode(ByteBuffer.wrap(byteArray)); // also decode to String byteBuffer = latin1Charset.encode(charBuffer); // also decode from String 

在旁边:

java.nio类和java.io Reader / Writer类使用ByteBuffer&CharBuffer(使用byte []和char []作为后备数组)。 所以如果你直接使用这些类,通常更可取。 但是,您始终可以这样做:

  byteArray = ByteBuffer.array(); byteBuffer = ByteBuffer.wrap(byteArray); byteBuffer.get(byteArray); charBuffer.put(charArray); charArray = CharBuffer.array(); charBuffer = ByteBuffer.wrap(charArray); charBuffer.get(charArray); charBuffer.put(charArray); 

如果你想使用ByteBuffer和CharBuffer,不要做简单的.asCharBuffer() ,它只是简单地做一个UTF-16(LE或BE,取决于你的系统 – 你可以用order方法设置字节order )转换(因为Javastring,因此你的char[]内部使用这种编码)。

使用Charset.forName(charsetName) ,然后使用其encodedecode方法,或newEncoder / newDecoder

将byte []转换为String时,还应指明编码(它应该是相同的)。

我会做的是使用循环转换为字节和另一个转换回char。

 char[] chars = "password".toCharArray(); byte[] bytes = new byte[chars.length*2]; for(int i=0;i<chars.length;i++) { bytes[i*2] = (byte) (chars[i] >> 8); bytes[i*2+1] = (byte) chars[i]; } char[] chars2 = new char[bytes.length/2]; for(int i=0;i<chars2.length;i++) chars2[i] = (char) ((bytes[i*2] << 8) + (bytes[i*2+1] & 0xFF)); String password = new String(chars2); 

你应该使用getBytes()而不是toCharArray()

更换线路

 char[] password = "password".toCharArray(); 

 byte[] password = "password".getBytes(); 

这是Peter Lawrey的答案的延伸。 为了在字符的整个范围内正确地转换(字节到字符)转换,代码应该如下:

 char[] chars = new char[bytes.length/2]; for (int i = 0; i < chars.length; i++) { chars[i] = (char) (((bytes[i*2] & 0xff) << 8) + (bytes[i*2+1] & 0xff)); } 

在使用( & 0xff )之前,我们需要“取消”字节。 否则,所有可能的char值中的一半将无法正确恢复。 例如, [0x80..0xff]范围内的字符将受到影响。

  public byte[] charsToBytes(char[] chars){ Charset charset = Charset.forName("UTF-8"); ByteBuffer byteBuffer = charset.encode(CharBuffer.wrap(chars)); return Arrays.copyOf(byteBuffer.array(), byteBuffer.limit()); } public char[] bytesToChars(byte[] bytes){ Charset charset = Charset.forName("UTF-8"); CharBuffer charBuffer = charset.decode(ByteBuffer.wrap(bytes)); return Arrays.copyOf(charBuffer.array(), charBuffer.limit()); } 

当您在Java中使用GetBytes时,返回结果将取决于计算机设置的默认编码(例如:StandardCharsetsUTF-8或StandardCharsets.ISO_8859_1etc …)。

所以,每当你想从一个string对象getBytes。 确保给一个编码。 喜欢 :

 String sample = "abc"; Byte[] a_byte = sample .getBytes(StandardCharsets.UTF_8); 

让我们来看看代码发生了什么。 在java中,名为sample的String是通过Unicode存储的。 string中的每个字符以2个字节存储。

 sample : value: "abc" in Memory(Hex): 00 61 00 62 00 63 a -> 00 61 b -> 00 62 c -> 00 63 

但是,当我们从string中获取字节时,我们有

 Byte[] a_byte = sample .getBytes(StandardCharsets.UTF_8) //result is : 61 62 63 //length: 3 bytes Byte[] a_byte = sample .getBytes(StandardCharsets.UTF_16BE) //result is : 00 61 00 62 00 63 //length: 6 bytes 

为了得到string的单个字节。 我们可以只读取string的内存并获取String.Below的每个字节是示例代码:

 public static byte[] charArray2ByteArray(char[] chars){ int length = chars.length; byte[] result = new byte[length*2+2]; int i = 0; for(int j = 0 ;j<chars.length;j++){ result[i++] = (byte)( (chars[j] & 0xFF00) >> 8 ); result[i++] = (byte)((chars[j] & 0x00FF)) ; } return result; } 

用途:

 String sample = "abc"; //First get the chars of the String,each char has two bytes(Java). Char[] sample_chars = sample.toCharArray(); //Get the bytes byte[] result = charArray2ByteArray(sample_chars). //Back to String. //Make sure we use UTF_16BE. Because we read the memory of Unicode of //the String from Left to right. That's the same reading //sequece of UTF-16BE. String sample_back= new String(result , StandardCharsets.UTF_16BE);