Tôi đang làm việc trong C # và thực hiện một số giao tiếp giữa 2 ứng dụng tôi đang viết. Tôi đã thích API Web và JSON. Bây giờ tôi đang ở thời điểm mà tôi đang viết một thói quen để gửi một bản ghi giữa hai máy chủ bao gồm một số dữ liệu văn bản và một tệp.
Theo internet, tôi phải sử dụng một yêu cầu nhiều dữ liệu / biểu mẫu dữ liệu như được hiển thị ở đây:
Câu hỏi SO "Biểu mẫu nhiều từ khách hàng C #"
Về cơ bản, bạn viết một yêu cầu theo cách thủ công theo một định dạng như vậy:
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--
Sao chép từ RFC 1867 - Tải lên tệp dựa trên mẫu trong HTML
Định dạng này khá khó chịu với một người đã quen với dữ liệu JSON đẹp. Vì vậy, rõ ràng giải pháp là tạo một yêu cầu JSON và Base64 mã hóa tệp và kết thúc bằng một yêu cầu như thế này:
{
"field1":"Joe Blow",
"fileImage":"JVBERi0xLjUKJe..."
}
Và chúng ta có thể sử dụng tuần tự hóa và giải tuần tự hóa JSON ở bất cứ đâu chúng ta muốn. Trên hết, mã để gửi dữ liệu này khá đơn giản. Bạn chỉ cần tạo lớp của mình để tuần tự hóa JSON và sau đó đặt các thuộc tính. Thuộc tính chuỗi tệp được đặt trong một vài dòng tầm thường:
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);
}
Không còn phân định ngớ ngẩn và tiêu đề cho mỗi mục. Bây giờ câu hỏi còn lại là hiệu suất. Vì vậy, tôi định hình rằng. Tôi có một bộ 50 tệp mẫu mà tôi sẽ cần gửi qua dây có phạm vi từ 50KB đến 1,5 MB hoặc hơn. Đầu tiên tôi đã viết một số dòng chỉ đơn giản là truyền phát tệp trong một mảng byte để so sánh nó với logic truyền phát trong tệp và sau đó chuyển đổi nó thành luồng Base64. Dưới đây là 2 đoạn mã mà tôi đã mô tả:
Truyền trực tiếp đến nhiều phần dữ liệu / biểu mẫu
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
Truyền phát và mã hóa vào hồ sơ tạo yêu cầu 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
Kết quả là việc đọc đơn giản luôn mất 0ms, nhưng mã hóa Base64 mất tới 5ms. Dưới đây là thời gian dài nhất:
File Size | Output Stream Size | Time
1352KB 1802KB 5ms
1031KB 1374KB 7ms
463KB 617KB 1ms
Tuy nhiên, trong sản xuất, bạn sẽ không bao giờ chỉ viết một cách mù quáng nhiều dữ liệu / biểu mẫu mà không kiểm tra trước dấu phân cách của bạn phải không? Vì vậy, tôi đã sửa đổi mã dữ liệu biểu mẫu để nó kiểm tra các byte phân cách trong chính tệp để đảm bảo mọi thứ sẽ được phân tích cú pháp ok. Tôi đã không viết một thuật toán quét tối ưu hóa, vì vậy tôi chỉ làm cho dấu phân cách nhỏ để nó không lãng phí nhiều thời gian.
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;
Bây giờ kết quả đang cho tôi thấy rằng phương pháp dữ liệu biểu mẫu sẽ thực sự chậm hơn đáng kể. Dưới đây là kết quả với thời gian> 0ms cho một trong hai phương pháp:
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
Dường như một thuật toán tối ưu hóa sẽ làm tốt hơn nhiều khi nhìn thấy vì dấu phân cách của tôi chỉ dài 5 ký tự. Dù sao cũng không phải là 3x tốt hơn, đó là lợi thế về hiệu suất của việc thực hiện mã hóa Base64 thay vì kiểm tra các byte tệp để phân cách.
Rõ ràng mã hóa Base64 sẽ tăng kích thước như tôi hiển thị trong bảng đầu tiên, nhưng nó thực sự không tệ ngay cả với UTF-8 có khả năng Unicode và sẽ nén tốt nếu muốn. Nhưng lợi ích thực sự là mã của tôi rất đẹp, sạch sẽ và dễ hiểu và nó không làm tổn thương nhãn cầu của tôi khi nhìn vào tải trọng yêu cầu JSON.
Vậy tại sao mọi người không chỉ đơn giản là mã hóa các tệp Base64 trong JSON thay vì sử dụng nhiều dữ liệu / biểu mẫu? Có các Tiêu chuẩn, nhưng chúng thay đổi tương đối thường xuyên. Tiêu chuẩn thực sự chỉ là đề xuất dù sao phải không?