문제

그만큼 JSON 형식 기본적으로 이진 데이터를 지원하지 않습니다. 바이너리 데이터는 JSON의 문자열 요소 (즉, 백 슬래시 탈출을 사용하여 이중 인용구로 제로 또는 더 많은 유니 코드 숯)에 배치 할 수 있도록 이진 데이터를 피해야합니다.

이진 데이터를 탈출하는 명백한 방법은 Base64를 사용하는 것입니다. 그러나 Base64는 높은 처리 오버 헤드를 갖습니다. 또한 3 바이트를 4 자로 확장하여 데이터 크기가 약 33%증가합니다.

이것에 대한 하나의 사용 사례는 V0.8 초안입니다. CDMI 클라우드 스토리지 API 사양. JSON을 사용하여 REST-WEBSERVICE를 통해 데이터 객체를 만듭니다.

PUT /MyContainer/BinaryObject HTTP/1.1
Host: cloud.example.com
Accept: application/vnd.org.snia.cdmi.dataobject+json
Content-Type: application/vnd.org.snia.cdmi.dataobject+json
X-CDMI-Specification-Version: 1.0
{
    "mimetype" : "application/octet-stream",
    "metadata" : [ ],
    "value" :   "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
    IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
    dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu
    dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
    ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=",
}

이진 데이터를 JSON 문자열로 인코딩하는 더 좋은 방법과 표준 방법이 있습니까?

도움이 되었습니까?

해결책

JSON 사양에 따라 1 바이트로 표시 될 수있는 94 개의 유니 코드 문자가 있습니다 (JSON이 UTF-8으로 전송되는 경우). 그것을 염두에두고, 나는 당신이 우주에서 할 수있는 최선은 베이스 85 이는 4 배로 4 바이트를 나타냅니다. 그러나 이것은 Base64보다 7% 개선에 불과하며, 계산하는 데 더 비싸며 구현은 Base64보다 일반적이지 않으므로 아마도 승리가 아닐 것입니다.

또한 모든 입력 바이트를 U+0000-U+00FF의 해당 문자에 매핑 한 다음 JSON 표준에 필요한 최소 인코딩을 수행하여 해당 문자를 전달할 수 있습니다. 여기서 장점은 필요한 디코딩이 내장 함수를 넘어서는 것이 아니라 공간 효율이 나쁘다는 것입니다. Base 85의 경우 105% 확장 (모든 입력 바이트가 동일하게 가능할 경우)이 25% 또는 Base64의 경우 33%입니다.

최종 평결 : Base64는 내 의견으로는 일반적이고 쉽고 나쁘지 않다는 근거로 승리합니다. 충분한 교체를 보증합니다.

또한보십시오: 베이스 91

다른 팁

나는 같은 문제를 겪었고 해결책을 공유 할 것이라고 생각했다. 멀티 파트/형태-데이터.

멀티 파트 양식을 보내면 먼저 string으로 보내십시오. JSON 메타 데이터, 그런 다음 별도로 생물 바이너리 (이미지 (S), Wavs 등)로 별도로 전송됩니다. 내용화 이름.

여기 좋은 일이 있습니다 지도 시간 OBJ-C 에서이 작업을 수행하는 방법에 대해 블로그 기사 이는 문자열 데이터를 양식 경계로 분할하고 이진 데이터와 분리하는 방법을 설명합니다.

당신이 실제로해야 할 유일한 변화는 서버 측면입니다. 게시 된 바이너리 데이터를 적절하게 참조 해야하는 메타 데이터를 캡처해야합니다 (콘텐츠 공연 경계를 사용하여).

서버 측에서 추가 작업이 필요하지만 많은 이미지 나 큰 이미지를 보내면 그만한 가치가 있습니다. 원하는 경우 gzip 압축과 결합하십시오.

IMHO Base64 인코딩 된 데이터를 보내는 것은 해킹입니다. RFC 멀티 파트/양식 데이터는 다음과 같은 문제에 대해 생성되었습니다 : 텍스트 또는 메타 데이터와 함께 이진 데이터를 보내는 것.

BSON (Binary JSON)이 당신을 위해 일할 수 있습니다.http://en.wikipedia.org/wiki/bson

편집 : fyi .net 라이브러리 json.net C# 서버 측 사랑을 찾고 있다면 BSON 읽기 및 쓰기를 지원합니다.

UTF-8의 문제점은 가장 공간 효율적인 인코딩이 아니라는 것입니다. 또한 일부 랜덤 바이 테이트 시퀀스는 유효하지 않은 UTF-8 인코딩입니다. 따라서 무작위 바이 테이트 시퀀스를 일부 UTF-8 데이터로 해석 할 수는 없습니다. UTF-8 인코딩에 대한 이러한 제약의 이점은 우리가보기 시작하는 바이트를 시작하고 끝내는 것이 강력하고 찾을 수 있다는 것입니다.

결과적으로, 범위 [0..127]의 바이트 값을 인코딩하는 경우 UTF-8 인코딩에서 하나의 바이트 만 필요하면 범위 [128..255]의 바이트 값을 인코딩하면 2 바이트가 필요합니다! 그보다 더 나쁘다. JSON에서는 컨트롤 char "및 가 문자열에 나타날 수 없습니다. 따라서 이진 데이터는 올바르게 인코딩되도록 약간의 변환이 필요합니다.

보자. 이진 데이터에서 균일하게 분산 된 랜덤 바이트 값을 가정하면 평균적으로 바이트의 절반은 하나의 바이트로, 나머지 절반은 두 바이트로 인코딩됩니다. UTF-8 인코딩 된 이진 데이터는 초기 크기의 150%를 갖습니다.

Base64 인코딩은 초기 크기의 133%에 불과합니다. 따라서 Base64 인코딩이 더 효율적입니다.

다른베이스 인코딩을 사용하는 것은 어떻습니까? UTF-8에서 128 ASCII 값을 인코딩하는 것이 가장 공간 효율적입니다. 8 비트로 7 비트를 저장할 수 있습니다. 따라서 이진 데이터를 7 비트 덩어리로 자르면 UTF-8 인코딩 된 문자열의 각 바이트에 저장하면 인코딩 된 데이터는 초기 크기의 114%로 만 증가합니다. Base64보다 낫습니다. 불행히도 JSON은 일부 ASCII 숯을 허용하지 않기 때문에이 쉬운 트릭을 사용할 수 없습니다. ASCII ([0..31] 및 127)의 33 개의 제어 문자와 "및 는 제외되어야합니다. 이것은 우리에게 128-35 = 93 숯 만 남습니다.

따라서 이론적으로 우리는 인코딩 된 크기를 8/log2 (93) = 8*log10 (2)/log10 (93) = 122%로 늘리는 Base93 인코딩을 정의 할 수 있습니다. 그러나 Base93 인코딩은 Base64 인코딩만큼 편리하지 않습니다. Base64는 간단한 비트가 작동하는 6 비트 청크에서 입력 바이트 시퀀스를 절단해야합니다. 133%는 122%를 넘지 않습니다.

이것이 바로 Base64가 실제로 JSON에서 이진 데이터를 인코딩하는 최선의 선택이라는 일반적인 결론에 독립적으로 온 이유입니다. 내 대답은 그것에 대한 정당성을 제시합니다. 나는 그것이 성능 관점에서 그다지 매력적이지 않다는 데 동의하지만, 모든 프로그래밍 언어에서 쉽게 조작하기 쉬운 인간 읽기 가능한 문자열 표현으로 JSON을 사용하는 이점도 고려합니다.

순수한 이진 인코딩보다 성능이 중요한 경우 JSON의 대체물로 간주해야합니다. 그러나 JSON과 함께 내 결론은 Base64가 최고라는 것입니다.

대역폭 문제를 처리하는 경우 먼저 클라이언트 측에서 데이터를 압축하여 Base64-IT를 압축하십시오.

그런 마법의 좋은 예가 있습니다 http://jszip.stuartk.co.uk/ 이 주제에 대한 더 많은 토론이 있습니다 GZIP의 JavaScript 구현

Yenc은 당신을 위해 일할 수 있습니다 :

http://en.wikipedia.org/wiki/yenc

"YENC는 [텍스트]에서 이진 파일을 전송하기위한 이진-텍스트 인코딩 체계입니다. 8 비트 확장 ASCII 인코딩 방법을 사용하여 이전의 미국 ASCII 기반 인코딩 방법에 대한 오버 헤드가 줄어 듭니다. 각 바이트 값은 Uuencode 및 Base64와 같은 6 비트 인코딩 방법에 대해 33%–40%오버 헤드에 비해 평균 1-2%정도의 빈도로 대략 1-2%로 나타납니다. ... 2003 년까지 Yenc는 사실상 표준이되었습니다. USENET의 이진 파일 용 인코딩 시스템. "

그러나 YENC는 8 비트 인코딩이므로 JSON 문자열에 저장하는 것은 원래 이진 데이터를 저장하는 것과 동일한 문제가 있습니다. 순진한 방법을 수행하는 것은 100% 확장을 의미하며 이는 Base64보다 나쁩니다.

미소 형식

인코딩, 디코딩 및 컴팩트하는 것은 매우 빠릅니다.

속도 비교 (Java 기반이지만 의미있는) : https://github.com/eishay/jvm-serializers/wiki/

또한 바이트 어레이를위한 Base64 인코딩을 건너 뛸 수있는 JSON으로의 확장입니다.

공간이 중요 할 때 미소 인코딩 된 줄은 gzipped 할 수 있습니다.

Base64가 ~ 33%의 확장률을 가지고 있다는 것은 사실이지만, 오버 헤드 처리 처리가 이것보다 훨씬 더 큰 것은 아닙니다. 실제로 사용중인 JSON 라이브러리/툴킷에 달려 있습니다. 인코딩 및 디코딩은 간단한 간단한 작업이며, 최적화 된 WRT 문자 인코딩도 할 수 있습니다 (JSON은 UTF-8/16/32 만 지원하므로 Base64 문자는 항상 JSON 문자열 항목의 단일 바이트입니다. 예를 들어 Java 플랫폼에서는 작업을 다소 효율적으로 수행 할 수있는 라이브러리가 있으므로 오버 헤드는 주로 크기가 확장 되었기 때문입니다.

나는 두 가지 이전 답변에 동의합니다.

  • Base64는 간단하고 일반적으로 사용되는 표준이므로 JSON과 함께 사용하기에 더 나은 것을 찾을 수는 없습니다 (Base-85는 PostScript 등에 사용되지만 생각할 때 혜택은 가장 한계입니다).
  • 인코딩 전 압축 (및 디코딩 후)은 사용하는 데이터에 따라 많은 의미가있을 수 있습니다.

(7 년 후 편집 : Google 기어가 사라졌습니다. 이 대답을 무시하십시오.)


Google Gears 팀은 이진 부족 유형의 문제에 부딪 히고이를 해결하려고 시도했습니다.

Blob API

JavaScript에는 텍스트 문자열 용 내장 데이터 유형이 있지만 이진 데이터에는 아무것도 없습니다. Blob Object는이 제한을 해결하려고 시도합니다.

어쩌면 당신은 어떻게 든 그것을 짜낼 수 있습니다.

이진 데이터를 엄격하게 텍스트 기반이고 매우 제한된 형식으로 구울 수있는 기능을 찾고 있기 때문에 Base64의 오버 헤드는 JSON과 함께 유지할 편의성에 비해 최소한이 적다고 생각합니다. 처리 능력과 처리량이 우려되는 경우 파일 형식을 재고해야 할 것입니다.

자원과 복잡성 관점을 토론에 추가하기 만하면됩니다. 새로운 리소스를 저장하고 변경하기 위해 Put/Post 및 패치를 수행하기 때문에 컨텐츠 전송은 저장된 컨텐츠를 정확하게 표현하고 GET 작업을 발행하여 수신 한 것입니다.

멀티 파트 메시지는 종종 구세주로 사용되지만 단순성 이유와보다 복잡한 작업을 위해 컨텐츠를 전체적으로 제공하는 아이디어를 선호합니다. 자체 설명이며 간단합니다.

그리고 네 JSON은 끔찍한 일이지만 결국 JSON 자체는 장점입니다. Base64에 매핑의 오버 헤드는 작은 방법입니다.

멀티 파트 메시지를 올바르게 사용하면 객체를 발송하려면 객체를 해체하거나 자동 조합의 매개 변수 이름으로 속성 경로를 사용하거나 페이로드를 표현하기 위해 다른 프로토콜/형식을 만들어야합니다.

또한 BSON 접근법을 좋아하는 것은 원하는만큼 광범위하고 쉽게 지원되는 것이 아닙니다.

기본적으로, 우리는 여기서 무언가를 놓치지 만 Base64로 바이너리 데이터를 포함시키고 실제 바이너리 전송을 수행 할 필요성을 실제로 식별하지 않는 한 바이너리 데이터가 잘 확립되어 있습니다 (이것은 거의 경우가 거의 없습니다).

데이터 유형은 실제로 우려됩니다. 편안한 리소스에서 페이로드를 보내는 데 다른 시나리오를 테스트했습니다. 인코딩을 위해 Base64 (Apache)와 압축 gzip (java.utils.zip.*)을 사용했습니다. 페이로드에는 필름, 이미지 및 오디오 파일에 대한 정보가 포함되어 있습니다. 성능을 크게 저하시키는 이미지 및 오디오 파일을 압축하고 인코딩했습니다. 압축 전에 인코딩이 잘 나타났습니다. 이미지 및 오디오 컨텐츠는 인코딩 및 압축 바이트 []로 전송되었습니다.

나타내다: http://snia.org/sites/default/files/multi-part%20mime%20extension%20v1.0g.pdf

이진 데이터의 Base64 변환없이 'CDMI 컨텐츠 유형'작업을 사용하여 CDMI 클라이언트와 서버간에 이진 데이터를 전송하는 방법을 설명합니다.

'비 CDMI 컨텐츠 유형'작업을 사용할 수있는 경우 '데이터'를 객체로/로 전송하는 것이 이상적입니다. 그런 다음 메타 데이터를 나중에 후속 'CDMI 컨텐츠 유형'작업으로 객체로/로부터 추가/검색 할 수 있습니다.

노드를 사용하는 경우 가장 효율적이고 쉬운 방법은 UTF16으로 변환하는 것입니다.

Buffer.from(data).toString('utf16le');

다음을 통해 데이터를 가져올 수 있습니다.

Buffer.from(s, 'utf16le');

나는 조금 더 파고 들었다 (구현 중에 베이스 128), 그리고 그것을 노출시킵니다 ASCII 코드가 128보다 큰 문자를 보낼 때 브라우저 (크롬)는 실제로 두 문자 (바이트) 대신 하나를 보냅니다.. 그 이유는 DEFAUL에 의한 JSON이 127 이상 ASCII 코드를 가진 문자에 대한 UTF8 문자를 사용하기 때문입니다. Chmike 대답. 이런 식으로 테스트를 수행했습니다 : Chrome URL BAR을 입력합니다. 크롬 : // net-export/ , "원시 바이트 포함"을 선택하고, 캡처를 시작하고, 게시물 요청 보내기 (하단에서 스 니펫 사용), 캡처 중지 및 원시 요청 데이터로 JSON 파일을 저장하십시오. 그런 다음 JSON 파일 내부를 살펴 봅니다.

  • 문자열을 찾아 Base64 요청을 찾을 수 있습니다 4142434445464748494a4b4c4d4e 이것은 16 진 코딩입니다 ABCDEFGHIJKLMN 그리고 우리는 그것을 볼 것입니다 "byte_count": 639 그것을 위해.
  • 문자열을 찾아서 127 위의 요청을 찾을 수 있습니다 C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B 이것은 request-hex utf8 문자 코드입니다 ¼½ÀÁÂÃÄÅÆÇÈÉÊË (그러나이 문자의 ASCII 육각 코드는 c1c2c3c4c5c6c7c8c9cacbcccdce). 그만큼 "byte_count": 703 따라서 ASCII 코드가 127 이상인 문자는 요청에서 2 바이트 씩 코드이기 때문에 Base64 요청보다 64 바이트가 길다.

실제로 우리는 코드> 127 :(. Base64 문자열의 경우 캐릭터를 보내는 데 이익이 없습니다. 우리는 그러한 부정적인 행동을 관찰하지 않습니다 (아마도 Base85의 경우 - 나는 그것을 확인하지 않을 것입니다) -이 문제에 대한 몇 가지 해결책 일 수 있습니다. 다음에 설명 된 Post Multipart/Form-Data의 이진 부분에서 데이터 보내기 Ælex 답변 (그러나 일반적 으로이 경우 우리는 기본 코딩을 전혀 사용할 필요가 없습니다 ...).

대체 접근법은 두 바이트 데이터 부분을 하나의 유효한 UTF8 문자로 매핑하는 데 의존 할 수 있습니다. Base65280 / Base65K 그러나 아마도 그것은 base64보다 덜 효과적 일 것입니다. UTF8 사양 ...

function postBase64() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("base64ch", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  req.open("POST", '/testBase64ch');
  req.send(formData);
}


function postAbove127() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("above127", "¼½ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüý");
  req.open("POST", '/testAbove127');
  req.send(formData);
}
<button onclick=postBase64()>POST base64 chars</button>
<button onclick=postAbove127()>POST chars with codes>127</button>

내 솔루션 이제 XHR2는 ArrayBuffer를 사용하고 있습니다. 바이너리 시퀀스로서의 Arraybuffer에는 다중 콘텐츠 유형이 포함 된 멀티 파트-콘텐츠, 비디오, 오디오, 그래픽, 텍스트 등이 포함되어 있습니다. 모두 한 응답으로.

최신 브라우저에서는 다른 구성 요소에 대한 Dataview, StringView 및 Blob이 있습니다. 또한보십시오: http://rolfrost.de/video.html 자세한 사항은.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top