java 将字节数组放入JSON,反之亦然

lpwwtiir  于 2023-01-07  发布在  Java
关注(0)|答案(6)|浏览(271)

是否可以将byte[](字节数组)放入JSON
如果是这样话,如何在Java中做到这一点?然后读取JSON并将该字段再次转换为byte[]

lc8prwob

lc8prwob1#

下面是base64编码字节数组的一个很好的例子。当你在发送PDF文档时使用unicode字符时,它会变得更加复杂。在编码字节数组之后,编码后的字符串可以用作JSON属性值。
Apache commons提供了很好的实用程序:

byte[] bytes = getByteArr();
 String base64String = Base64.encodeBase64String(bytes);
 byte[] backToBytes = Base64.decodeBase64(base64String);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
Java服务器端示例:

public String getUnsecureContentBase64(String url)
        throws ClientProtocolException, IOException {

            //getUnsecureContent will generate some byte[]
    byte[] result = getUnsecureContent(url);

            // use apache org.apache.commons.codec.binary.Base64
            // if you're sending back as a http request result you may have to
            // org.apache.commons.httpclient.util.URIUtil.encodeQuery
    return Base64.encodeBase64String(result);
}

JavaScript解码:

//decode URL encoding if encoded before returning result
var uriEncodedString = decodeURIComponent(response);

var byteArr = base64DecToArr(uriEncodedString);

//from mozilla
function b64ToUint6 (nChr) {

  return nChr > 64 && nChr < 91 ?
      nChr - 65
    : nChr > 96 && nChr < 123 ?
      nChr - 71
    : nChr > 47 && nChr < 58 ?
      nChr + 4
    : nChr === 43 ?
      62
    : nChr === 47 ?
      63
    :
      0;

}

function base64DecToArr (sBase64, nBlocksSize) {

  var
    sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
    nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);

  for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
    nMod4 = nInIdx & 3;
    nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
    if (nMod4 === 3 || nInLen - nInIdx === 1) {
      for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
        taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
      }
      nUint24 = 0;

    }
  }

  return taBytes;
}
t5zmwmid

t5zmwmid2#

在json中发送二进制的典型方法是base64编码。
Java提供了不同的方法来对byte[]进行Base64编码和解码,其中之一就是DatatypeConverter
很简单

byte[] originalBytes = new byte[] { 1, 2, 3, 4, 5};
String base64Encoded = DatatypeConverter.printBase64Binary(originalBytes);
byte[] base64Decoded = DatatypeConverter.parseBase64Binary(base64Encoded);

您必须根据您使用的json解析器/生成器库来进行这种转换。

ax6ht2ek

ax6ht2ek3#

令人惊讶的是,现在org.json允许你把byte[]对象直接放到一个json中,并且它仍然是可读的。你甚至可以通过一个WebSocket发送结果对象,它在另一端也是可读的。但是我还不确定结果对象的大小是大于还是小于你将byte数组转换为base64时的大小,如果它小一点肯定会很整洁。
要衡量这样一个json对象在java中占用了多少空间似乎是难以置信的困难。如果你的json仅仅由字符串组成,那么通过简单地将它字符串化就可以很容易地实现,但是如果它里面有一个字节数组,我担心它就不那么简单了。
在java中对json进行字符串化会将bytearray替换为一个10个字符的字符串,看起来像一个id。在node.js中执行相同的操作会将byte[]替换为一个无引号的值阅读读作<Buffered Array: f0 ff ff ...>,后者的长度表明大小增加了大约300%,这是可以预期的

bqucvtff

bqucvtff4#

与@Qwertie的建议一致,但在懒惰的一面更进一步,你 * 可以 * 假装每个字节都是一个ISO-8859-1字符。对于门外汉来说,ISO-8859-1是一个单字节编码,与Unicode的前256个码位匹配。
所以@Ash的答案实际上可以用字符集来弥补:

byte[] args2 = getByteArry();
String byteStr = new String(args2, Charset.forName("ISO-8859-1"));

这种编码具有与BAIS相同的可读性,其优点是处理速度比BAIS或base64都快,因为需要的分支更少。看起来JSON解析器做得更多,但这没关系,因为通过转义或UTF-8处理非ASCII是JSON解析器工作的一部分。它 * 可以 * 更好地Map到一些格式,如带有配置文件的MessagePack。
然而,在空间方面,这通常是一个损失,因为没有人会在JSON中使用UTF-16。在UTF-8中,每个非ASCII字节将占用2个字节,而BAIS使用(2+4n + r?(r+1):0)个字节来表示每3n+r 个这样的字节(r是余数)。

pbpqsu0x

pbpqsu0x5#

如果您的字节数组可能包含您希望能够看到的ASCII字符串,那么您可能更喜欢BAIS(字符串中的字节数组)格式,而不是Base64。BAIS的好处是,如果所有字节碰巧都是ASCII,它们会被一对一地转换为字符串(例如,字节数组{65,66,67}变成简单的"ABC")而且,BAIS通常给你一个比Base64更小的文件大小(这是不能保证的)。
在将字节数组转换为BAIS字符串之后,像处理任何其他字符串一样将其写入JSON。
下面是一个Java类(从original C#移植而来),用于将字节数组转换为字符串。

import java.io.*;
import java.lang.*;
import java.util.*;

public class ByteArrayInString
{
  // Encodes a byte array to a string with BAIS encoding, which 
  // preserves runs of ASCII characters unchanged.
  //
  // For simplicity, this method's base-64 encoding always encodes groups of 
  // three bytes if possible (as four characters). This decision may 
  // unfortunately cut off the beginning of some ASCII runs.
  public static String convert(byte[] bytes) { return convert(bytes, true); }
  public static String convert(byte[] bytes, boolean allowControlChars)
  {
    StringBuilder sb = new StringBuilder();
    int i = 0;
    int b;
    while (i < bytes.length)
    {
      b = get(bytes,i++);
      if (isAscii(b, allowControlChars))
        sb.append((char)b);
      else {
        sb.append('\b');
        // Do binary encoding in groups of 3 bytes
        for (;; b = get(bytes,i++)) {
          int accum = b;
          if (i < bytes.length) {
            b = get(bytes,i++);
            accum = (accum << 8) | b;
            if (i < bytes.length) {
              b = get(bytes,i++);
              accum = (accum << 8) | b;
              sb.append(encodeBase64Digit(accum >> 18));
              sb.append(encodeBase64Digit(accum >> 12));
              sb.append(encodeBase64Digit(accum >> 6));
              sb.append(encodeBase64Digit(accum));
              if (i >= bytes.length)
                break;
            } else {
              sb.append(encodeBase64Digit(accum >> 10));
              sb.append(encodeBase64Digit(accum >> 4));
              sb.append(encodeBase64Digit(accum << 2));
              break;
            }
          } else {
            sb.append(encodeBase64Digit(accum >> 2));
            sb.append(encodeBase64Digit(accum << 4));
            break;
          }
          if (isAscii(get(bytes,i), allowControlChars) &&
            (i+1 >= bytes.length || isAscii(get(bytes,i), allowControlChars)) &&
            (i+2 >= bytes.length || isAscii(get(bytes,i), allowControlChars))) {
            sb.append('!'); // return to ASCII mode
            break;
          }
        }
      }
    }
    return sb.toString();
  }

  // Decodes a BAIS string back to a byte array.
  public static byte[] convert(String s)
  {
    byte[] b;
    try {
      b = s.getBytes("UTF8");
    } catch(UnsupportedEncodingException e) { 
      throw new RuntimeException(e.getMessage());
    }
    for (int i = 0; i < b.length - 1; ++i) {
      if (b[i] == '\b') {
        int iOut = i++;

        for (;;) {
          int cur;
          if (i >= b.length || ((cur = get(b, i)) < 63 || cur > 126))
            throw new RuntimeException("String cannot be interpreted as a BAIS array");
          int digit = (cur - 64) & 63;
          int zeros = 16 - 6; // number of 0 bits on right side of accum
          int accum = digit << zeros;

          while (++i < b.length)
          {
            if ((cur = get(b, i)) < 63 || cur > 126)
              break;
            digit = (cur - 64) & 63;
            zeros -= 6;
            accum |= digit << zeros;
            if (zeros <= 8)
            {
              b[iOut++] = (byte)(accum >> 8);
              accum <<= 8;
              zeros += 8;
            }
          }

          if ((accum & 0xFF00) != 0 || (i < b.length && b[i] != '!'))
            throw new RuntimeException("String cannot be interpreted as BAIS array");
          i++;

          // Start taking bytes verbatim
          while (i < b.length && b[i] != '\b')
            b[iOut++] = b[i++];
          if (i >= b.length)
            return Arrays.copyOfRange(b, 0, iOut);
          i++;
        }
      }
    }
    return b;
  }

  static int get(byte[] bytes, int i) { return ((int)bytes[i]) & 0xFF; }

  public static int decodeBase64Digit(char digit)
    { return digit >= 63 && digit <= 126 ? (digit - 64) & 63 : -1; }
  public static char encodeBase64Digit(int digit)
    { return (char)((digit + 1 & 63) + 63); }
  static boolean isAscii(int b, boolean allowControlChars)
    { return b < 127 && (b >= 32 || (allowControlChars && b != '\b')); }
}

另请参阅:C# unit tests

gjmwrych

gjmwrych6#

简单地说

byte[] args2 = getByteArry();
String byteStr = new String(args2);

相关问题