ฉันทำงานใน C # และสื่อสารระหว่าง 2 แอพที่ฉันกำลังเขียน ฉันชอบ Web API และ JSON ตอนนี้ฉันมาถึงจุดที่ฉันกำลังเขียนกิจวัตรประจำวันเพื่อส่งบันทึกระหว่างเซิร์ฟเวอร์ทั้งสองที่มีข้อมูลตัวอักษรและไฟล์อยู่บ้าง
ตามอินเทอร์เน็ตฉันควรใช้คำขอ multipart / form-data ตามที่แสดงที่นี่:
ดังนั้นคำถาม "Multipart form จาก C # client"
โดยทั่วไปคุณเขียนคำขอด้วยตนเองที่ตามรูปแบบดังนี้:
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 - การอัพโหลดไฟล์แบบฟอร์มเป็น HTML
รูปแบบนี้ค่อนข้างน่าวิตกสำหรับคนที่คุ้นเคยกับข้อมูล JSON ที่ดี ดังนั้นวิธีแก้ไขคือการสร้างคำขอ JSON และ Base64 เข้ารหัสไฟล์และจบลงด้วยคำขอเช่นนี้:
{
"field1":"Joe Blow",
"fileImage":"JVBERi0xLjUKJe..."
}
และเราสามารถใช้ประโยชน์จากซีเรียลไลเซชัน JSON และดีซีเรียลไลเซชั่นได้ทุกที่ ยิ่งไปกว่านั้นรหัสในการส่งข้อมูลนี้ค่อนข้างง่าย คุณเพียงแค่สร้างคลาสของคุณสำหรับการทำให้เป็นอันดับ JSON แล้วตั้งค่าคุณสมบัติ คุณสมบัติสตริงไฟล์ถูกตั้งค่าในสองสามบรรทัด:
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);
}
ไม่มีตัวคั่นและส่วนหัวที่โง่มากสำหรับแต่ละรายการ ตอนนี้คำถามที่เหลือคือประสิทธิภาพ ดังนั้นฉันจึงประวัติว่า ฉันมีไฟล์ตัวอย่าง 50 ชุดที่ฉันต้องการส่งข้ามสายที่มีตั้งแต่ 50KB ถึง 1.5MB หรือมากกว่านั้น ก่อนอื่นฉันเขียนบางบรรทัดเพื่อสตรีมในไฟล์ไปยังอาร์เรย์ไบต์เพื่อเปรียบเทียบกับตรรกะที่สตรีมในไฟล์แล้วแปลงเป็นสตรีม Base64 ด้านล่างนี้เป็นโค้ด 2 ชิ้นที่ฉันทำโปรไฟล์:
สตรีมไปยังโปรไฟล์หลายส่วน / แบบฟอร์มข้อมูลโดยตรง
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
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
ผลลัพธ์คือการอ่านที่เรียบง่ายใช้เวลาเสมอ 0 มิลลิวินาที แต่การเข้ารหัส Base64 ใช้เวลาสูงสุด 5 มิลลิวินาที ด้านล่างเป็นเวลาที่ยาวที่สุด:
File Size | Output Stream Size | Time
1352KB 1802KB 5ms
1031KB 1374KB 7ms
463KB 617KB 1ms
อย่างไรก็ตามในการผลิตคุณจะไม่เขียนสุ่มหลายส่วน / ข้อมูลแบบสุ่มโดยไม่ตรวจสอบตัวคั่นของคุณก่อนใช่มั้ย ดังนั้นฉันจึงแก้ไขโค้ดข้อมูลฟอร์มเพื่อตรวจสอบไบต์ตัวคั่นในไฟล์ของตัวเองเพื่อให้แน่ใจว่าทุกอย่างจะถูกแยกวิเคราะห์ได้ ฉันไม่ได้เขียนอัลกอริธึมการสแกนที่ได้รับการปรับปรุงดังนั้นฉันจึงทำให้ตัวคั่นมีขนาดเล็กเพื่อไม่ให้เสียเวลา
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;
ตอนนี้ผลแสดงให้ฉันเห็นว่าวิธีการแบบฟอร์มข้อมูลจะช้าลงอย่างมีนัยสำคัญ ด้านล่างเป็นผลลัพธ์ที่มีเวลา> 0ms สำหรับวิธีใดวิธีหนึ่ง:
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
ดูเหมือนว่าอัลกอริทึมที่ได้รับการเพิ่มประสิทธิภาพจะทำได้ดีกว่ามากหากคุณเห็นว่าตัวคั่นของฉันมีความยาวเพียง 5 ตัวอักษร ไม่ใช่เรื่องที่ดีกว่านี้อีก 3x ซึ่งเป็นข้อได้เปรียบด้านประสิทธิภาพของการเข้ารหัส Base64 แทนการตรวจสอบไบต์ไฟล์สำหรับตัวคั่น
เห็นได้ชัดว่าการเข้ารหัส Base64 จะขยายขนาดตามที่ฉันแสดงในตารางแรก แต่จริงๆแล้วมันไม่ได้แย่ขนาดนั้นถึงแม้จะใช้ Unicode ที่มีความสามารถ UTF-8 และจะบีบอัดได้ดีหากต้องการ แต่ประโยชน์ที่แท้จริงคือรหัสของฉันนั้นดีและสะอาดและเข้าใจได้ง่ายและไม่ทำให้ลูกตาของฉันเจ็บเมื่อต้องดู JSON ขอน้ำหนักบรรทุกที่มาก
เหตุใดในโลกนี้ทุกคนจะไม่เพียงแค่เข้ารหัสไฟล์ Base64 ใน JSON แทนที่จะใช้หลายส่วน / ฟอร์มข้อมูล มีมาตรฐาน แต่สิ่งเหล่านี้เปลี่ยนแปลงค่อนข้างบ่อย มาตรฐานเป็นเพียงข้อเสนอแนะจริง ๆ ใช่มั้ย