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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20706783/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 03:43:12  来源:igfitidea点击:

Put byte array to JSON and vice versa

javajsonbytearray

提问by Amin Sh

Is it possible to put a byte[](byte array) to JSON?

是否可以将byte[](字节数组)放入JSON

if so, how can I do that in java? then read that JSON and convert that field again to byte[]?

如果是这样,我怎么能在java中做到这一点?然后读取该 JSON 并将该字段再次转换为byte[]?

采纳答案by Sam Nunnally

Here is a good example of base64 encoding byte arrays. It gets more complicated when you throw unicode characters in the mix to send things like PDF documents. After encoding a byte array the encoded string can be used as a JSON property value.

这是 base64 编码字节数组的一个很好的例子。当您将 unicode 字符混入以发送 PDF 文档之类的内容时,情况会变得更加复杂。在对字节数组进行编码后,编码后的字符串可以用作 JSON 属性值。

Apache commons offers good utilities:

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

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding

Java server side example:

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:

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;
}

回答by Sotirios Delimanolis

The typical way to send binary in json is to base64 encode it.

在 json 中发送二进制文件的典型方法是对它进行 base64 编码。

Java provides different ways to Base64 encode and decode a byte[]. One of these is DatatypeConverter.

Java 提供了不同的 Base64 编码和解码方式byte[]。其中之一是DatatypeConverter

Very simply

很简单

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

You'll have to make this conversion depending on the json parser/generator library you use.

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

回答by Ash

what about simply this:

简单的这个怎么样:

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

回答by Qwertie

If your byte array may contain runs of ASCII characters that you'd like to be able to see, you might prefer BAIS (Byte Array In String) format instead of Base64. The nice thing about BAIS is that if all the bytes happen to be ASCII, they are converted 1-to-1 to a string (e.g. byte array {65,66,67}becomes simply "ABC") Also, BAIS often gives you a smaller file size than Base64 (this isn't guaranteed).

如果您的字节数组可能包含您希望能够看到的 ASCII 字符,您可能更喜欢 BAIS(字符串中的字节数组)格式而不是 Base64。BAIS 的好处是,如果所有字节碰巧都是 ASCII,它们会被 1 对 1 转换为字符串(例如,字节数组{65,66,67}变得简单"ABC")此外,BAIS 通常为您提供比 Base64 更小的文件大小(这不是t保证)。

After converting the byte array to a BAIS string, write it to JSON like you would any other string.

将字节数组转换为 BAIS 字符串后,像写入任何其他字符串一样将其写入 JSON。

Here is a Java class (ported from the original C#) that converts byte arrays to string and back.

这是一个 Java 类(从原始 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;
          System.out.println("i="+i);
          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')); }
}

See also: C# unit tests.

另请参阅:C# 单元测试

回答by quealegriamasalegre

Amazingly now org.json now lets you put a byte[] object directly into a json and it remains readable. you can even send the resulting object over a websocket and it will be readable on the other side. but i am not sure yet if the size of the resulting object is bigger or smaller than if you were converting your byte array to base64, it would certainly be neat if it was smaller.

令人惊讶的是,现在 org.json 现在允许您将 byte[] 对象直接放入 json 并且它仍然可读。您甚至可以通过 websocket 发送结果对象,并且在另一端可读。但我不确定结果对象的大小是否比将字节数组转换为 base64 时更大或更小,如果它更小肯定会很整洁。

It seems to be incredibly hard to measure how much space such a json object takes up in java. if your json consists merely of strings it is easily achievable by simply stringifying it but with a bytearray inside it i fear it is not as straightforward.

衡量这样一个 json 对象在 java 中占用多少空间似乎非常困难。如果您的 json 仅由字符串组成,则可以通过简单地将其字符串化来轻松实现,但是在其中包含一个字节数组,我担心它并不那么简单。

stringifying our json in java replaces my bytearray for a 10 character string that looks like an id. doing the same in node.js replaces our byte[]for an unquoted value reading <Buffered Array: f0 ff ff ...>the length of the latter indicates a size increase of ~300% as would be expected

在java中字符串化我们的json会将我的bytearray替换为一个看起来像id的10个字符的字符串。在 node.js 中做同样的事情替换了我们byte[]的一个不带引号的值,读取<Buffered Array: f0 ff ff ...>后者的长度表明大小增加了 ~300%,正如预期的那样