나는 C #에서 일하고 있고 내가 쓰고있는 두 응용 프로그램 사이에서 약간의 의사 소통을하고 있습니다. 웹 API와 JSON이 마음에 들었습니다. 이제 텍스트 데이터와 파일이 포함 된 두 서버 사이에 레코드를 보내기 위해 루틴을 작성하는 시점에 있습니다.
인터넷에 따르면 다음과 같이 multipart / form-data 요청을 사용해야합니다.
기본적으로 다음과 같은 형식을 따르는 요청을 수동으로 작성합니다.
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);
}
각 항목에 대해 더 이상 바보 구분 기호와 헤더가 없습니다. 이제 남은 질문은 성능입니다. 그래서 나는 그것을 프로파일했다. 50KB에서 1.5MB 정도의 전선을 통해 전송 해야하는 50 개의 샘플 파일 세트가 있습니다. 먼저 파일에서 바이트 배열로 스트리밍하여 파일에서 스트리밍되는 논리와 비교하여 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
그 결과 단순 읽기는 항상 0ms가 걸리지 만 Base64 인코딩은 최대 5ms가 걸렸습니다. 가장 긴 시간은 다음과 같습니다.
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 자에 불과하기 때문에 최적화 된 알고리즘이 훨씬 더 나은 것처럼 보이지는 않습니다. 어쨌든 3 배 더 좋지는 않습니다. 이는 파일 바이트를 구분 기호로 검사하는 대신 Base64 인코딩을 수행하는 성능 이점입니다.
분명히 Base64 인코딩은 첫 번째 테이블에 표시된 것처럼 크기를 늘리지 만 유니 코드 가능 UTF-8에서도 그렇게 나쁘지는 않으며 원하는 경우 잘 압축됩니다. 그러나 실제 이점은 내 코드가 훌륭하고 깨끗하며 쉽게 이해할 수 있으며 JSON 요청 페이로드를 많이 보더라도 시력을 손상시키지 않는다는 것입니다.
그렇다면 왜 지구상에서 multipart / form-data를 사용하는 대신 단순히 Base64로 JSON으로 파일을 인코딩하지 않는 사람이 있습니까? 표준이 있지만 이러한 표준은 상대적으로 자주 변경됩니다. 어쨌든 표준은 실제로 제안 일 뿐입니 까?