C # ile çalışıyorum ve yazdığım 2 uygulama arasında iletişim kuruyorum. Web API ve JSON'u beğenmeye geldim. Şimdi, bazı metin verilerini ve bir dosyayı içeren iki sunucu arasında bir kayıt göndermek için bir rutin yazdığım noktadayım.
İnternete göre burada gösterildiği gibi çok parçalı / form-veri talebi kullanmam gerekiyor:
SO Question "C # istemcisinden çok parçalı formlar"
Temel olarak, aşağıdaki gibi bir biçimi izleyen bir isteği manuel olarak yazarsınız:
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
RFC 1867'den kopyalandı - HTML'de Form Tabanlı Dosya Yükleme
Bu biçim, JSON verilerini güzelleştirmek için kullanılan birine oldukça üzücü. Açıkçası çözüm bir JSON isteği oluşturmak ve Base64 dosyayı kodlamak ve bunun gibi bir istekle sonuçlanmaktır:
{
"field1":"Joe Blow",
"fileImage":"JVBERi0xLjUKJe..."
}
Ve istediğimiz her yerde JSON serileştirme ve serileştirmeyi kullanabiliriz. Bunun da ötesinde, bu verileri gönderme kodu oldukça basittir. Sadece JSON serileştirme için sınıfınızı oluşturun ve sonra özellikleri ayarlayın. File string özelliği birkaç önemsiz satırda ayarlanır:
using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] file_bytes = new byte[fs.Length];
fs.Read(file_bytes, 0, file_bytes.Length);
MyJsonObj.fileImage = Convert.ToBase64String(file_bytes);
}
Artık her öğe için aptal sınırlayıcı ve başlık yok. Şimdi geriye kalan soru performans. Ben de bunu profilledim. Ben 50KB ile 1.5MB ya da öylesine arasında değişen tel üzerinden göndermek gerekir 50 örnek dosyaları bir dizi var. Öncelikle, dosyadaki akışları mantıkla karşılaştırmak ve daha sonra Base64 akışına dönüştürmek için dosyada bir bayt dizisine akış yapmak için bazı satırlar yazdım. Aşağıda profilli olduğum 2 kod parçası bulunmaktadır:
Profile Çok Parçalı / Form Verilerine Doğrudan Akış
var timer = new Stopwatch();
timer.Start();
using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] test_data = new byte[fs.Length];
fs.Read(test_data, 0, test_data.Length);
}
timer.Stop();
long test = timer.ElapsedMilliseconds;
//Write time elapsed and file size to CSV file
JSON isteği oluşturan profile akış ve kodlama
var timer = new Stopwatch();
timer.Start();
using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] file_bytes = new byte[fs.Length];
fs.Read(file_bytes, 0, file_bytes.Length);
ret_file = Convert.ToBase64String(file_bytes);
}
timer.Stop();
long test = timer.ElapsedMilliseconds;
//Write time elapsed, file size, and length of UTF8 encoded ret_file string to CSV file
Sonuçlar, basit okumanın her zaman 0 ms sürdüğü, ancak Base64 kodlamasının 5 ms sürdüğü idi. En uzun zamanlar aşağıdadır:
File Size | Output Stream Size | Time
1352KB 1802KB 5ms
1031KB 1374KB 7ms
463KB 617KB 1ms
Bununla birlikte, üretimde, önce sınırlayıcınızı kontrol etmeden asla çok yönlü / form verilerini körü körüne yazmazsınız değil mi? Böylece form-veri kodunu değiştirdim, böylece her şeyin yolunda ayrıştırıldığından emin olmak için dosyanın kendisindeki sınırlayıcı baytları kontrol etti. Optimize edilmiş bir tarama algoritması yazmadım, bu yüzden sınırlayıcıyı küçük yaptım, böylece çok fazla zaman kaybetmeyecekti.
var timer = new Stopwatch();
timer.Start();
using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] test_data = new byte[fs.Length];
fs.Read(test_data, 0, test_data.Length);
string delim = "--DXX";
byte[] delim_checker = Encoding.UTF8.GetBytes(delim);
for (int i = 0; i <= test_data.Length - delim_checker.Length; i++)
{
bool match = true;
for (int j = i; j < i + delim_checker.Length; j++)
{
if (test_data[j] != delim_checker[j - i])
{
match = false;
break;
}
}
if (match)
{
break;
}
}
}
timer.Stop();
long test = timer.ElapsedMilliseconds;
Şimdi sonuçlar bana form-veri yönteminin önemli ölçüde daha yavaş olacağını gösteriyor. Aşağıda, her iki yöntem için de 0ms'den büyük sonuçlar verilmiştir:
File Size | FormData Time | Json/Base64 Time
181Kb 1ms 0ms
1352Kb 13ms 4ms
463Kb 4ms 5ms
133Kb 1ms 0ms
133Kb 1ms 0ms
129Kb 1ms 0ms
284Kb 2ms 1ms
1031Kb 9ms 3ms
Optimize edilmiş bir algoritmanın, sınırlayıcımın sadece 5 karakter uzunluğunda olduğunu görerek çok daha iyi olacağı görülmüyor. Yine de 3 kat daha iyi değil, bu da dosya baytlarını bir sınırlayıcı için kontrol etmek yerine Base64 kodlaması yapmanın performans avantajı.
Tabii ki Base64 kodlaması, ilk tabloda gösterdiğim gibi boyutu şişirecek, ancak Unicode özellikli UTF-8 ile bile o kadar da kötü değil ve istenirse iyi sıkıştırır. Ama asıl fayda benim kod güzel ve temiz ve kolay anlaşılır ve JSON istek yükü o kadar bakmak için benim gözbebekleri zarar vermez.
Öyleyse neden dünyadaki Base64, çoklu bölüm / form verileri kullanmak yerine JSON'daki dosyaları kodlamıyor? Standartlar var, ancak bunlar nispeten sık değişiyor. Standartlar gerçekten sadece öneri değil mi?