The format JSON native tidak mendukung data biner. Data biner harus melarikan diri sehingga dapat ditempatkan ke elemen string (yaitu nol atau lebih karakter Unicode dalam tanda kutip ganda menggunakan backslash escapes) di JSON.
Metode yang jelas untuk melarikan diri data biner adalah menggunakan Base64. Namun, Base64 memiliki overhead pemrosesan yang tinggi. Juga memperluas 3 byte menjadi 4 karakter yang mengarah pada peningkatan ukuran data sekitar 33%.
Satu kasus penggunaan untuk ini adalah draft v0.8 dari spesifikasi API penyimpanan awan CDMI . Anda membuat objek data melalui REST-Webservice menggunakan JSON, misalnya
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=",
}
Adakah cara dan metode standar yang lebih baik untuk menyandikan data biner ke dalam string JSON?
JSON.parse
. Dll ......Jawaban:
Ada 94 karakter Unicode yang dapat direpresentasikan sebagai satu byte sesuai dengan spesifikasi JSON (jika JSON Anda ditransmisikan sebagai UTF-8). Dengan mengingat hal itu, saya pikir yang terbaik yang bisa Anda lakukan di luar angkasa adalah base85 yang mewakili empat byte sebagai lima karakter. Namun, ini hanya peningkatan 7% dari base64, ini lebih mahal untuk dihitung, dan implementasi lebih jarang dari pada base64 sehingga mungkin bukan kemenangan.
Anda juga bisa memetakan setiap byte input ke karakter yang sesuai di U + 0000-U + 00FF, lalu melakukan pengkodean minimum yang diperlukan oleh standar JSON untuk meneruskan karakter tersebut; keuntungan di sini adalah bahwa decoding yang diperlukan adalah nihil di luar fungsi builtin, tetapi efisiensi ruang buruk - ekspansi 105% (jika semua byte input kemungkinan sama) vs 25% untuk base85 atau 33% untuk base64.
Putusan akhir: base64 menang, menurut saya, dengan alasan bahwa itu umum, mudah, dan tidak cukup buruk untuk menjamin penggantian.
Lihat juga: Base91 dan Base122
sumber
base64.b85encode()
danb85decode()
sekarang. Pengkodean sederhana + pengukuran waktu dekode menunjukkan bahwa b85 lebih dari 13 kali lebih lambat daripada b64. Jadi kami memiliki 7% ukuran menang, tetapi 1300% kehilangan kinerja.DEL
sebagai karakter kontrol.Saya mengalami masalah yang sama, dan berpikir saya akan membagikan solusi: multipart / form-data.
Dengan mengirimkan formulir multi bagian, Anda mengirim pertama sebagai string meta-data JSON Anda , dan kemudian secara terpisah mengirim sebagai biner mentah (gambar, wav, dll) yang diindeks oleh nama Content-Disposition .
Berikut ini adalah tutorial yang bagus tentang bagaimana melakukan ini di obj-c, dan di sini ada artikel blog yang menjelaskan bagaimana cara mempartisi data string dengan batas bentuk, dan memisahkannya dari data biner.
Satu-satunya perubahan yang benar-benar perlu Anda lakukan adalah di sisi server; Anda harus menangkap meta-data Anda yang seharusnya merujuk data biner POST dengan tepat (dengan menggunakan batas Disposisi Konten).
Memang itu membutuhkan kerja tambahan di sisi server, tetapi jika Anda mengirim banyak gambar atau gambar besar, ini sepadan. Kombinasikan ini dengan kompresi gzip jika Anda mau.
IMHO mengirim data yang disandikan base64 adalah hack; multipart / formulir-data RFC dibuat untuk masalah seperti ini: mengirim data biner dalam kombinasi dengan teks atau meta-data.
sumber
Masalah dengan UTF-8 bukanlah encoding yang paling efisien ruang. Juga, beberapa urutan byte biner acak adalah pengkodean UTF-8 yang tidak valid. Jadi Anda tidak bisa hanya menginterpretasikan urutan byte biner acak sebagai beberapa data UTF-8 karena itu akan menjadi pengkodean UTF-8 yang tidak valid. Manfaat dari batasan ini pada pengkodean UTF-8 adalah membuatnya kuat dan memungkinkan untuk menemukan karakter multi byte mulai dan mengakhiri byte apa pun yang mulai kita lihat.
Sebagai akibatnya, jika pengkodean nilai byte dalam rentang [0..127] hanya membutuhkan satu byte dalam pengkodean UTF-8, pengkodean nilai byte dalam rentang [128..255] akan membutuhkan 2 byte! Lebih buruk dari itu. Di JSON, kontrol karakter, "dan \ tidak diizinkan untuk muncul dalam sebuah string. Jadi data biner akan memerlukan beberapa transformasi untuk dikodekan dengan benar.
Biarkan melihat. Jika kita mengasumsikan nilai byte acak yang terdistribusi secara seragam dalam data biner kita, maka, rata-rata, setengah dari byte akan dikodekan dalam satu byte dan setengah lainnya dalam dua byte. Data biner yang dikodekan UTF-8 akan memiliki 150% dari ukuran awal.
Pengkodean Base64 hanya tumbuh hingga 133% dari ukuran awal. Jadi pengkodean Base64 lebih efisien.
Bagaimana dengan menggunakan pengkodean Base lain? Dalam UTF-8, penyandian nilai 128 ASCII adalah yang paling efisien dalam ruang. Dalam 8 bit Anda dapat menyimpan 7 bit. Jadi jika kita memotong data biner dalam potongan 7 bit untuk menyimpannya dalam setiap byte dari string yang dikodekan UTF-8, data yang dikodekan hanya akan tumbuh hingga 114% dari ukuran awal. Lebih baik dari Base64. Sayangnya kami tidak dapat menggunakan trik mudah ini karena JSON tidak mengizinkan beberapa karakter ASCII. 33 karakter kontrol ASCII ([0..31] dan 127) dan tanda "dan \ harus dikecualikan. Ini membuat kita hanya 128-35 = 93 karakter.
Jadi secara teori kita dapat mendefinisikan encoding Base93 yang akan menumbuhkan ukuran yang dikodekan menjadi 8 / log2 (93) = 8 * log10 (2) / log10 (93) = 122%. Tetapi pengkodean Base93 tidak akan senyaman pengkodean Base64. Base64 mengharuskan untuk memotong urutan byte input dalam potongan 6bit yang operasi bitwise sederhana bekerja dengan baik. Selain 133% tidak lebih dari 122%.
Inilah sebabnya saya sampai pada kesimpulan umum bahwa Base64 memang pilihan terbaik untuk menyandikan data biner di JSON. Jawaban saya menyajikan pembenaran untuk itu. Saya setuju itu tidak terlalu menarik dari sudut pandang kinerja, tetapi mempertimbangkan juga manfaat menggunakan JSON dengan representasi string yang dapat dibaca manusia mudah dimanipulasi dalam semua bahasa pemrograman.
Jika kinerja sangat penting daripada pengkodean biner murni harus dianggap sebagai penggantian JSON. Tetapi dengan JSON kesimpulan saya adalah bahwa Base64 adalah yang terbaik.
sumber
BSON (Binary JSON) dapat bekerja untuk Anda. http://en.wikipedia.org/wiki/BSON
Sunting: FYI. NET library json.net mendukung membaca dan menulis bson jika Anda mencari beberapa sisi cinta C # server.
sumber
Jika Anda berurusan dengan masalah bandwidth, coba kompres data di sisi klien terlebih dahulu, lalu base64-it.
Contoh bagus dari sihir semacam itu ada di http://jszip.stuartk.co.uk/ dan diskusi lebih lanjut untuk topik ini adalah pada implementasi JavaScript dari Gzip
sumber
Content-Encoding
), karena base64 dapat dikompres dengan cukup baik.yEnc mungkin bekerja untuk Anda:
http://en.wikipedia.org/wiki/Yenc
Namun, yEnc adalah penyandian 8-bit, jadi menyimpannya dalam string JSON memiliki masalah yang sama dengan menyimpan data biner asli - melakukannya dengan cara naif berarti tentang ekspansi 100%, yang lebih buruk daripada base64.
sumber
Meskipun benar bahwa base64 memiliki ~ 33% tingkat ekspansi, itu tidak selalu benar bahwa memproses overhead secara signifikan lebih dari ini: itu benar-benar tergantung pada perpustakaan / toolkit JSON yang Anda gunakan. Pengkodean dan penguraian adalah operasi langsung yang sederhana, dan mereka bahkan dapat dioptimalkan pengkodean karakter wrt (karena JSON hanya mendukung UTF-8/16/32) - karakter base64 selalu byte tunggal untuk entri String JSON. Misalnya pada platform Java ada perpustakaan yang dapat melakukan pekerjaan dengan lebih efisien, sehingga overhead sebagian besar disebabkan oleh ukuran yang diperluas.
Saya setuju dengan dua jawaban sebelumnya:
sumber
Format senyum
Sangat cepat untuk menyandikan, mendekode, dan kompak
Perbandingan kecepatan (berbasis java tapi tetap berarti): https://github.com/eishay/jvm-serializers/wiki/
Juga merupakan ekstensi ke JSON yang memungkinkan Anda untuk melewatkan encoding base64 untuk array byte
Senyum yang dikodekan dengan senyuman dapat di-gzip saat ruang kritis
sumber
( Edit 7 tahun kemudian: Google Gears hilang. Abaikan jawaban ini.)
Tim Google Gears mengalami masalah kekurangan tipe data biner dan telah berupaya mengatasinya:
Mungkin Anda bisa menenunnya entah bagaimana.
sumber
Karena Anda mencari kemampuan untuk memilih data biner ke dalam format yang sangat berbasis teks dan sangat terbatas, saya pikir biaya overhead Base64 minimal dibandingkan dengan kenyamanan yang Anda harapkan untuk dipertahankan dengan JSON. Jika kekuatan pemrosesan dan throughput menjadi perhatian, maka Anda mungkin perlu mempertimbangkan kembali format file Anda.
sumber
Hanya untuk menambah sudut pandang sumber daya dan kompleksitas pada diskusi. Karena melakukan PUT / POST dan PATCH untuk menyimpan sumber daya baru dan mengubahnya, orang harus ingat bahwa transfer konten adalah representasi yang tepat dari konten yang disimpan dan yang diterima dengan mengeluarkan operasi GET.
Pesan multi-bagian sering digunakan sebagai penyelamat tetapi untuk alasan kesederhanaan dan untuk tugas-tugas yang lebih kompleks, saya lebih suka ide memberikan konten secara keseluruhan. Ini menjelaskan diri sendiri dan sederhana.
Dan ya JSON adalah sesuatu yang melumpuhkan tetapi pada akhirnya JSON itu sendiri adalah verbose. Dan overhead pemetaan ke BASE64 adalah cara untuk menjadi kecil.
Menggunakan pesan Multi-Bagian dengan benar kita harus membongkar objek untuk dikirim, menggunakan jalur properti sebagai nama parameter untuk kombinasi otomatis atau perlu membuat protokol / format lain untuk hanya mengekspresikan muatan.
Juga menyukai pendekatan BSON, ini tidak didukung secara luas dan mudah seperti yang diinginkan.
Pada dasarnya, kami hanya melewatkan sesuatu di sini tetapi menanamkan data biner karena base64 sudah mapan dan cara untuk pergi kecuali Anda benar-benar telah mengidentifikasi kebutuhan untuk melakukan transfer biner nyata (yang jarang terjadi).
sumber
Saya menggali sedikit lebih banyak (selama implementasi base128 ), dan mengekspos bahwa ketika kita mengirim karakter yang kode ascii lebih besar dari 128 maka browser (chrome) sebenarnya mengirim DUA karakter (byte) alih-alih satu :( . Alasannya adalah bahwa JSON oleh defaul gunakan utf8 karakter yang karakternya dengan kode ascii di atas 127 dikodekan oleh dua byte yang disebut oleh jawaban chmike . Saya membuat tes dengan cara ini: ketik chrome url bar chrome: // net-export / , pilih "Include raw byte ", mulailah menangkap, mengirim permintaan POST (menggunakan snipet di bagian bawah), berhenti mengambil dan menyimpan file json dengan data permintaan mentah. Lalu kita melihat ke dalam file json itu:
4142434445464748494a4b4c4d4e
merupakan hex codingABCDEFGHIJKLMN
dan kami akan melihatnya"byte_count": 639
untuk itu.C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B
ini adalah kode karakter hex-utf8 permintaan¼½ÀÁÂÃÄÅÆÇÈÉÊË
(namun kode hex ascii dari karakter ini adalahc1c2c3c4c5c6c7c8c9cacbcccdce
). The"byte_count": 703
sehingga 64bytes lebih lama dari base64 meminta karena karakter dengan kode ascii di atas 127 adalah kode dengan 2 byte dalam permintaan :(Jadi sebenarnya kita tidak mendapat untung dengan mengirim karakter dengan kode> 127 :(. Untuk string base64 kita tidak mengamati perilaku negatif seperti itu (mungkin untuk base85 juga - saya tidak memeriksanya) - namun mungkin ada beberapa solusi untuk masalah ini adalah mengirim data dalam bagian biner dari POST multipart / formulir-data yang dijelaskan dalam Ælex answer (namun biasanya dalam hal ini kita tidak perlu menggunakan kode dasar sama sekali ...).
Pendekatan alternatif dapat mengandalkan pemetaan dua byte data bagian menjadi satu karakter utf8 yang valid dengan kode menggunakan sesuatu seperti base65280 / base65k tapi mungkin itu akan kurang efektif daripada base64 karena spesifikasi utf8 ...
Tampilkan cuplikan kode
sumber
Tipe data sangat memprihatinkan. Saya telah menguji berbagai skenario pengiriman muatan dari sumber yang tenang. Untuk pengkodean saya telah menggunakan Base64 (Apache) dan untuk kompresi GZIP (java.utils.zip. *). Muatannya berisi informasi tentang film, gambar, dan file audio. Saya telah mengompresi dan menyandikan file gambar dan audio yang secara drastis menurunkan kinerja. Pengkodean sebelum kompresi berjalan dengan baik. Konten gambar dan audio dikirim sebagai byte yang dikodekan dan dikompresi [].
sumber
Lihat: http://snia.org/sites/default/files/Multi-part%20MIME%20Extension%20v1.0g.pdf
Ini menjelaskan cara untuk mentransfer data biner antara klien CDMI dan server menggunakan operasi 'tipe konten CDMI' tanpa memerlukan konversi base64 dari data biner.
Jika Anda dapat menggunakan operasi 'Jenis konten Non-CDMI', sangat ideal untuk mentransfer 'data' ke / dari objek. Metadata kemudian dapat ditambahkan / diambil ke / dari objek sebagai operasi 'tipe konten CDMI' berikutnya.
sumber
Solusi saya sekarang, XHR2 menggunakan ArrayBuffer. ArrayBuffer sebagai urutan biner berisi konten multi-bagian, video, audio, grafik, teks dan sebagainya dengan beberapa tipe konten. Semua dalam Satu Respons.
Di browser modern, memiliki DataView, StringView dan Blob untuk Komponen yang berbeda. Lihat juga: http://rolfrost.de/video.html untuk lebih jelasnya.
sumber
[16, 2, 38, 89]
yang sangat tidak efisien.