JSON 문자열의 이진 데이터.Base64보다 뛰어난 기능
JSON 형식은 기본적으로 이진 데이터를 지원하지 않습니다.이진 데이터를 JSON에서 문자열 요소(즉, 백슬래시 이스케이프를 사용하여 큰따옴표로 묶은 0 이상의 유니코드 문자)에 넣을 수 있도록 이스케이프해야 합니다.
바이너리 데이터를 회피하는 확실한 방법은 Base64를 사용하는 것입니다.단, Base64는 처리 오버헤드가 높습니다.또한 3바이트를 4자로 확장하여 데이터 크기를 약 33% 증가시킵니다.
이에 대한 한 가지 사용 사례는 CDMI 클라우드 스토리지 API 사양의 v0.8 초안입니다.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바이트로 표시할 수 있는 Unicode 문자는 94개입니다(JSON이 UTF-8로 전송되는 경우).그런 의미에서 공간적으로 할 수 있는 최선은 4바이트를 5자로 나타내는 base85라고 생각합니다.그러나 이는 base64보다 7% 향상된 수치로 계산 비용이 더 많이 들고 구현도 base64보다 덜 일반적이기 때문에 성공적이지 않을 수 있습니다.
또한 모든 입력 바이트를 U+0000-U+00FF의 대응하는 문자에 매핑하고 그 문자를 전달하기 위해 JSON 표준이 필요로 하는 최소한의 인코딩을 실행할 수 있습니다.여기서 장점은 필요한 디코딩은 내장 함수를 넘어서는 제로이지만 공간 효율이 나쁘다는 것입니다.105% 확장(모든 입력 바이트가 동등할 가능성이 있는 경우).base85의 경우 25%, base64의 경우 33%입니다.
최종 평결: Base64의 승리라고 생각합니다.일반적이고, 쉽고, 교체를 보증할 수 있을 만큼 나쁘지는 않습니다.
저도 같은 문제에 부딪혀 해결책을 공유해야겠다고 생각했습니다.멀티 파트/폼 데이터입니다.
멀티파트 폼을 송신하면, 최초로 JSON 메타데이터의 문자열로서 송신한 후, Content-Disposition명에 의해서 인덱스 된 미가공 바이너리(이미지, wavs 등)로서 개별적으로 송신할 수 있습니다.
다음은 obj-c에서 이 작업을 수행하는 방법에 대한 튜토리얼입니다.또한 문자열 데이터를 폼 경계로 분할하여 바이너리 데이터와 분리하는 방법을 설명하는 블로그 기사입니다.
실제로 필요한 변경은 서버측뿐입니다.Meta Data를 캡처해야 합니다.Meta Data는 (Content-Disposition 경계를 사용하여) POST의 바이너리 데이터를 적절히 참조할 필요가 있습니다.
서버측에서의 추가 작업이 필요하지만, 많은 이미지나 큰 이미지를 송신하는 경우는, 이 방법을 추천합니다.필요에 따라서, 이것을 gzip 압축과 조합합니다.
IMHO는 base64 부호화 데이터를 송신하는 해킹입니다.RFC 멀티파트/폼데이터는 텍스트 또는 메타데이터와 조합하여 바이너리 데이터를 송신하는 것과 같은 문제를 위해 작성되었습니다.
BSON(Binary JSON)이 도움이 될 수 있습니다.http://en.wikipedia.org/wiki/BSON
편집: 참고:NET 라이브러리 json.net 는, C# 서버측의 사랑을 필요로 하는 경우, bson 의 판독과 쓰기를 서포트하고 있습니다.
UTF-8의 문제는 가장 공간 효율이 높은 인코딩이 아니라는 것입니다.또, 일부 랜덤 바이너리 바이트시퀀스는 무효 UTF-8 부호화입니다.따라서 랜덤 바이너리 바이트시퀀스는 UTF-8 인코딩이 무효이기 때문에 일부 UTF-8 데이터로 해석할 수 없습니다.UTF-8 인코딩에 대한 이 제약의 이점은 우리가 살펴보기 시작한 바이트의 시작과 끝의 멀티바이트 문자를 견고하고 찾을 수 있다는 것입니다.
따라서 [0] 범위의 바이트 값을 인코딩하는 경우.127] UTF-8 인코딩에서는 1바이트만 필요하며 [128] 범위의 바이트 값을 인코딩합니다.255]는 2바이트가 필요합니다!그것보다 더 나빠요.JSON에서는 제어 문자, " 및 \는 문자열에 표시할 수 없습니다.따라서 바이너리 데이터를 올바르게 인코딩하려면 변환이 필요합니다.
어디 보자.바이너리 데이터로 균등하게 분산된 랜덤바이트 값을 가정하면 평균적으로 바이트의 절반은 1바이트로 인코딩되고 나머지 절반은 2바이트로 인코딩됩니다.UTF-8로 인코딩된 바이너리 데이터는 초기 크기의 150%가 됩니다.
Base64 인코딩은 초기 크기의 133%까지만 확장됩니다.따라서 Base64 인코딩이 더 효율적입니다.
다른 Base 인코딩을 사용하는 것은 어떻습니까?UTF-8에서는 128 ASCII 값을 부호화하는 것이 가장 공간 효율적입니다.8비트에 7비트를 저장할 수 있습니다.따라서 바이너리 데이터를 7비트 청크로 잘라 UTF-8 인코딩 문자열의 각 바이트에 저장하면 인코딩된 데이터는 초기 크기의 114%까지만 증가합니다.Base64보다 낫다.안타깝게도 JSON에서는 ASCII 문자를 사용할 수 없기 때문에 이 쉬운 트릭은 사용할 수 없습니다.ASCII([0.31] 및 127)의 33개의 제어 문자 및 " 및 \는 제외해야 합니다.따라서 128-35 = 93자만 남습니다.
따라서 이론적으로 Base93 인코딩을 정의하면 인코딩 크기가 8/log2(93) = 8*log10(2)/log10(93) = 122%로 증가합니다.그러나 Base93 인코딩은 Base64 인코딩만큼 편리하지 않습니다.Base64는 입력 바이트 시퀀스를 6비트 청크로 잘라야 하며, 이는 단순한 비트 단위 연산이 잘 작동합니다.133%를 제외하면 122%를 넘지 않는다.
그래서 저는 Base64가 JSON에서 바이너리 데이터를 인코딩하는 데 가장 적합한 선택이라는 공통적인 결론을 독립적으로 내리게 되었습니다.내 대답은 그것에 대한 정당성을 제시한다.퍼포먼스 측면에서는 그다지 매력적이지 않지만, JSON을 사용하여 모든 프로그래밍 언어에서 쉽게 조작할 수 있는 사람이 읽을 수 있는 문자열 표현을 사용하는 장점도 고려합니다.
퍼포먼스가 순수 바이너리 부호화보다 중요한 경우 JSON을 대체하는 것으로 간주해야 합니다.하지만 JSON에서는 Base64가 최고라는 결론을 내렸습니다.
대역폭 문제에 대처하는 경우 먼저 클라이언트 측에서 데이터를 압축한 다음 base64-it로 압축해 보십시오.
이러한 매직의 좋은 예로는 http://jszip.stuartk.co.uk/를 들 수 있습니다.또, 이 토픽에 대한 자세한 내용은 JavaScript의 Gzip 실장을 참조해 주세요.
yEnc를 사용할 수 있습니다.
http://en.wikipedia.org/wiki/Yenc
"yEnc는 [text]에서 바이너리 파일을 전송하기 위한 바이너리-to-text 인코딩 방식입니다.8비트 확장 ASCII 인코딩 방식을 사용하여 이전의 US-ASCII 기반 인코딩 방식보다 오버헤드를 줄입니다.uencode나 Base64 등의 6비트 인코딩 방식에서는 오버헤드가 33%~40%인 데 비해 yEnc의 오버헤드는 대개 1~2%에 불과합니다.2003년까지 yEnc는 Usenet의 바이너리 파일을 위한 사실상의 표준 인코딩 시스템이 되었습니다."
단, yEnc는 8비트 부호화이므로 JSON 문자열에 저장하는 것은 원래 바이너리 데이터를 저장하는 것과 같은 문제가 있습니다.즉, 순진한 방법으로 하는 것은 base64보다 나쁜 100% 확장을 의미합니다.
base64의 확장률은 33%에 달하지만 처리 오버헤드가 이보다 훨씬 큰 것은 아닙니다.사용하는 JSON 라이브러리/툴킷에 의존합니다.부호화 및 디코딩은 간단한 간단한 조작으로 최적화된 wrt 문자 인코딩도 가능합니다(JSON은 UTF-8/16/32만 지원하므로). Base64 문자는 항상 JSON String 엔트리의 싱글바이트입니다.예를 들어 Java 플랫폼에는 작업을 효율적으로 수행할 수 있는 라이브러리가 있으므로 오버헤드는 대부분 확장된 크기에 기인합니다.
앞의 두 가지 답변에 동의합니다.
- base64는 심플하고 일반적으로 사용되는 표준이기 때문에 특별히 JSON에서 사용할 수 있는 것을 찾을 수 없을 것 같습니다(base-85는 포스트스크립트 등에 의해 사용되고 있습니다만, 생각해 보면 이점은 기껏해야 미미합니다).
- 부호화 전(및 디코딩 후) 압축은 사용하는 데이터에 따라 매우 의미가 있을 수 있습니다.
인코딩, 디코딩 및 압축이 매우 빠릅니다.
속도 비교(자바 기반이지만 의미 있음):https://github.com/eishay/jvm-serializers/wiki/
또한 바이트 배열의 base64 인코딩을 건너뛸 수 있는 JSON 확장입니다.
공간이 중요한 경우 스마일 인코딩된 문자열을 압축할 수 있습니다.
우리 하급 공룡 프로그래머들이 사용하는 다른 옵션을 추가한다면...
시대가 시작된 지 3년이 지난 구식 방법은 인텔 HEX 포맷입니다.그것은 1973년에 설립되었고 UNIX 시대는 1970년 1월 1일에 시작되었다.
- 더 효율적입니까?아니요.
- 그것은 잘 확립된 기준입니까?네.
- JSON처럼 사람이 읽을 수 있나요?대부분의 바이너리 솔루션보다 가독성이 뛰어납니다.
json은 다음과 같습니다.
{
"data": [
":10010000214601360121470136007EFE09D2190140",
":100110002146017E17C20001FF5F16002148011928",
":10012000194E79234623965778239EDA3F01B2CAA7",
":100130003F0156702B5E712B722B732146013421C7",
":00000001FF"
]
}
엄밀하게 텍스트 베이스로 매우 제한된 포맷으로 바이너리 데이터를 슈혼할 수 있는 기능을 찾고 있기 때문에 JSON에서 기대하는 편리함에 비해 Base64의 오버헤드는 최소라고 생각합니다.처리 능력과 throughput이 문제가 된다면 파일 형식을 재고해야 할 수도 있습니다.
(7년 후 편집:Google Gears가 사라졌습니다.이 답변은 무시해 주세요).
Google Gears 팀은 바이너리 데이터 유형의 부족 문제에 직면하여 다음과 같은 문제를 해결하려고 시도했습니다.
JavaScript에는 텍스트 문자열에 대한 데이터 유형이 내장되어 있지만 이진 데이터에는 내장되어 있지 않습니다.Blob 객체는 이 제한에 대처하려고 합니다.
어떻게 해서든 그걸 끼워 넣을 수 있을 거야.
상세
(base128을 실장하고 있을 때) 조금 더 파서 128보다 큰 ASCII 코드의 문자를 송신하면 브라우저(크롬)는 1개의 :(바이트)가 아닌 2개의 문자(바이트)를 송신합니다.그 이유는 defaul에 의해 JSON이 utf8 문자를 사용하기 때문에 127을 넘는 ASCII 코드를 가진 문자는 chmike 응답에 의해 언급된2 바이트로 부호화됩니다.이 방법으로 테스트를 실시했습니다.chrome url bar chrome : //net - export / 를 입력하고 "Include raw bytes" 를 선택하여 캡처를 시작하고 POST 요청을 전송합니다(하단의 스니펫을 사용하여), raw requests 데이터와 함께 json 파일 캡처를 중지하고 저장합니다.그런 다음 json 파일 내부를 확인합니다.
- 는 base64 스트링을 수 .
4142434445464748494a4b4c4d4e
입니다.ABCDEFGHIJKLMN
해서 우리가 될 것입니다."byte_count": 639
네, 네, 네. - 는 문자열 127을 수 있습니다.
C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B
은 utf8 입니다.¼½ÀÁÂÃÄÅÆÇÈÉÊË
(단, 이는 ( 「」, 「ASCII 16」)입니다c1c2c3c4c5c6c7c8c9cacbcccdce
"byte_count": 703
코드를 길어집니다
그래서 우리는 코드 >127:127:127: 이 음극에 대해 설명한 바와 같이, 이러한 부정적인 행동을 관찰할 수 있습니다.일을 하다베이스 코딩은 전혀 필요 없습니다...).
대체 접근법은 base65280 / base65k와 같은 것을 사용하여 2바이트의 데이터 부분을 1개의 유효한 utf8 문자에 매핑하는 데 의존할 수 있지만 utf8 사양으로 인해 base64보다 효과적이지 않을 수 있습니다.
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>
논의에 자원과 복잡성의 관점을 추가하기 위해서입니다.새로운 자원의 보존과 변경을 위해서 PUT/POST와 PATCH를 실시하기 때문에, 컨텐츠 전송은 보존되어 있는 컨텐츠와 GET 조작을 실행해 수신한 컨텐츠를 정확하게 나타내는 것에 주의해 주세요.
여러 부분으로 구성된 메시지는 종종 구세주로 사용되지만 단순성이나 더 복잡한 작업 때문에 내용을 전체적으로 제공하는 것을 선호합니다.그것은 자명하고 간단하다.
그리고 네, JSON은 치명적인 것이지만 결국 JSON 자체는 장황합니다.또한 BASE64에 매핑할 때 발생하는 오버헤드는 매우 작습니다.
Multi-Part 메시지를 올바르게 사용하려면 보낼 개체를 해체하거나, 속성 경로를 자동 조합의 매개 변수 이름으로 사용하거나, 페이로드를 표현하기 위해 다른 프로토콜/포맷을 만들어야 합니다.
또, BSON의 어프로치를 좋아하기 때문에, 이것은 기대만큼 폭넓고 간단하게 서포트되고 있지 않습니다.
기본적으로 여기서 놓치고 있는 것이 있습니다만, base64로서 바이너리 데이터를 짜넣는 것은 충분히 확립되어 있기 때문에, 실제로 바이너리 전송을 실시할 필요가 있는 것을 특정하지 않는 한(대부분은 그렇지 않습니다).
Node.js에서는 버퍼를 문자열로 변환하고 변경하지 않고 되돌릴 수 있습니다.
const serialized = buffer.toString("binary")
const deserialized = Buffer.from(serialized, "binary")
사이즈를 희생시켜 신뢰성을 향상시키려면"binary"
와 함께"base64"
데이터 타입은 매우 중요합니다.RESTful 리소스에서 payload를 전송하는 여러 시나리오를 테스트했습니다.인코딩에는 Base64(Apache)와 압축 GZIP(java.utils.zip.*)를 사용했습니다.페이로드에는 필름, 이미지 및 오디오 파일에 대한 정보가 포함되어 있습니다.퍼포먼스를 대폭 저하시킨 이미지와 오디오 파일을 압축해 부호화했습니다.압축 전 부호화가 정상적으로 종료되었습니다.이미지 및 오디오콘텐츠는 부호화 및 압축된 바이트[ ] 로 송신되었습니다.
참조: http://snia.org/sites/default/files/Multi-part%20MIME%20Extension%20v1.0g.pdf
Base64의 바이너리 데이터 변환 없이 CDMI 클라이언트와 서버 간에 'CDMI 콘텐츠 유형' 연산을 사용하여 바이너리 데이터를 전송하는 방법에 대해 설명합니다.
'비 CDMI 콘텐츠 유형' 작업을 사용할 수 있는 경우 개체 간에 '데이터'를 전송하는 것이 이상적입니다.그런 다음 후속 'CDMI 콘텐츠 유형' 작업으로 메타데이터를 개체와 추가하거나 개체에서 가져올 수 있습니다.
또 다른 새로운 아이디어는 uuencode를 통해 데이터를 인코딩하는 것입니다.대부분 추천되지 않지만 여전히 대안이 될 수 있습니다. (심각한 것은 아닐지 모르지만)
현재 솔루션으로는 XHR2가 ArrayBuffer를 사용하고 있습니다.이진 시퀀스로서의 ArrayBuffer에는 멀티파트 콘텐츠, 비디오, 오디오, 그래픽, 텍스트 등이 여러 콘텐츠타입으로 포함됩니다.올인원 리스폰스
최신 브라우저에서는 다양한 컴포넌트에 DataView, StringView 및 Blob을 사용할 수 있습니다.상세한 것에 대하여는, http://rolfrost.de/video.html 를 참조해 주세요.
언급URL : https://stackoverflow.com/questions/1443158/binary-data-in-json-string-something-better-than-base64
'programing' 카테고리의 다른 글
Next.js - 오류: 절대 URL만 지원됩니다. (0) | 2023.02.20 |
---|---|
React 확인란이 onChange를 전송하지 않음 (0) | 2023.02.20 |
Angular.js에서 다른 사람에게 주입할 수 있는 "물건"은 무엇입니까? (0) | 2023.02.20 |
ReactJS에서 중첩된 개체의 PropTypes를 검증하려면 어떻게 해야 합니까? (0) | 2023.02.20 |
Keyclock에서 사용자 비밀번호를 변경하기 위한 API 호출이 있습니까? (0) | 2023.02.20 |