출처 : Baoyu BLOG
1. 클라이언트 HTML을 예로 들어 컴포넌트 없는 업로드의 원리를 조금씩 설명하겠습니다. 업로드된 첨부 파일을 찾아보기 위해 <input type="file"> 요소를 전달하지만 양식의 enctype 속성을 "multipart/form-data"로 설정해야 합니다.
<form method="post" action="upload.asp" enctype="multipart/form-data">
<라벨>
<입력 유형="파일" 이름="파일1" />
</label>
<br />
<input type="text" name="파일 이름" value="기본 파일 이름"/>
<br />
<입력 유형="제출" 값="제출"/>
<입력 유형="재설정" 값="재설정"/>
</form>
백그라운드 ASP 프로그램에서는 양식에 의해 제출된 ASCII 데이터를 얻는 것이 매우 쉬웠습니다. 그러나 업로드된 파일을 가져와야 하는 경우 Request 개체의 BinaryRead 메서드를 사용하여 읽어야 합니다. BinaryRead 메서드는 현재 입력 스트림에서 지정된 바이트 수의 이진 읽기를 수행합니다. 한 가지 주의할 점은 BinaryRead 메서드가 사용되면 Request.Form 또는 Request.QueryString 컬렉션을 더 이상 사용할 수 없다는 것입니다. Request 개체의 TotalBytes 속성과 결합하면 양식으로 제출된 모든 데이터를 바이너리로 변환할 수 있지만 이러한 데이터는 모두 인코딩됩니다. 먼저 이러한 데이터가 어떻게 인코딩되는지 살펴보겠습니다. 코드를 분할하면 BinaryRead가 읽은 바이너리를 텍스트로 변환하여 백그라운드에서 upload.asp로 출력합니다. 이 예에서는 큰 파일을 업로드하지 마십시오. 그렇지 않으면 브라우저가 충돌할 수 있습니다.
<%
Dim biData, PostData
크기 = Request.TotalBytes
biData = Request.BinaryRead(크기)
PostData = BinaryToString(biData,크기)
Response.Write "<pre>" & PostData & "</pre>" 'pre를 사용하고 형식을 그대로 출력합니다.
'RecordSet의 도움으로 바이너리 스트림을 텍스트로 변환합니다.
함수 BinaryToString(biData,Size)
상수 adLongVarChar = 201
RS 설정 = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, 크기
RS.오픈
RS.새로 추가
RS("mBinary").AppendChunk(biData)
RS.업데이트
BinaryToString = RS("mBinary").값
RS.닫기
기능 종료
%>
단순화를 위해 가장 간단한 텍스트 파일(G:homepage.txt, 콘텐츠 "Baoyu: http://www.webuc.net ")을 업로드하여 테스트합니다. 텍스트 상자 파일 이름을 제출하고 출력을 확인하세요.
--------------------------------7d429871607fe
콘텐츠 처리: 양식-데이터; 파일 이름="G:homepage.txt"
콘텐츠 유형: 텍스트/일반
바오위: http://www.webuc.net
-------------7d429871607fe
내용 처리: 양식-데이터 이름="파일 이름"
기본 파일 이름
----------------7d429871607fe--
형식의 항목에 대해 "----- -------------7d429871607fe" 이러한 경계는 조각을 조각으로 분리하는 데 사용되며 각 조각의 시작 부분에 몇 가지 설명 정보가 있습니다. 예: Content- Disposition: form-data; name="filename", 설명 정보에서 name="filename"을 통해 양식 항목의 이름을 알 수 있습니다. filename="G:homepage.txt"와 같은 내용이 있으면 업로드된 파일이라는 뜻입니다. 업로드된 파일이라면 설명 정보에 Content-Type: text/plain 한 줄이 더 추가되어 설명됩니다. 파일의 콘텐츠 유형입니다. 설명 정보와 본문 정보는 줄 바꿈으로 구분됩니다.
뭐, 기본적으로는 명확합니다. 이 규칙에 따르면, 우리는 데이터를 분리하고 분리된 데이터를 처리하는 방법을 알고 있습니다. 그러나 우리는 경계값(위의 "-------")이라는 문제를 거의 간과했습니다. 예) ----------7d429871607fe")는 어떻게 알았나요? 이 경계 값은 업로드할 때마다 다릅니다. 다행히 ASP의 Request.ServerVariables("HTTP_CONTENT_TYPE")를 통해 얻을 수 있습니다. 예를 들어 위 예에서 HTTP_CONTENT_TYPE의 내용은 "multipart/form-data; 경계=-- -------------7d429871607fe", 이를 통해 enctype="multipart/form- data "(사용하지 않는 경우 아래에서 실행할 필요가 없습니다.) 경계값도 얻을 수 있습니다. ----- 7d429871607fe. (참고: 여기서 얻은 경계값은 위의 경계값보다 시작 부분에 "--"가 적습니다. 추가하는 것이 가장 좋습니다.)
데이터를 분석하는 과정에 대해서는 자세히 설명하지 않겠습니다. 우리가 원하는 데이터를 분리하기 위해 InStr 및 Mid와 같은 기능을 사용하는 것 이상입니다.
2. 청크로 업로드할 때, 녹화 진행 상황은 실시간으로 진행률 표시줄을 반영해야 합니다. 현재 서버가 얼마나 많은 데이터를 실시간으로 얻었는지 아는 것이 핵심입니다. 업로드 과정을 다시 생각해보면, Request.BinaryRead(Request.TotalBytes)를 통해 구현합니다. Request 과정에서는 현재 서버가 얼마나 많은 데이터를 얻었는지 알 수 없습니다. 따라서 획득한 데이터를 여러 조각으로 나누어 업로드된 블록 수를 기준으로 현재 업로드된 데이터의 크기를 계산할 수 있는 방법만 사용할 수 있습니다! 즉, 1K가 1블록이면 1MB를 업로드하는 입력 스트림을 1024블록으로 나누어 얻습니다. 예를 들어 100블록을 얻었다면 100K가 업로드되었음을 의미합니다. 제가 차단을 제안했을 때 많은 사람들은 BinaryRead 메서드가 지정된 크기를 읽을 수 있을 뿐만 아니라 지속적으로 읽을 수 있다는 점을 무시했기 때문에 이를 믿을 수 없다고 생각했습니다.
지금의 예제를 기반으로 블록 읽기의 무결성을 확인하는 예제를 작성하십시오(이 예제는 대용량 파일을 업로드하지 않습니다. 그렇지 않으면 브라우저가 충돌할 수 있습니다):
<%
Dim biData, PostData, TotalBytes, ChunkBytes
ChunkBytes = 1 * 1024 ' 청크 크기는 1K입니다.
TotalBytes = Request.TotalBytes '전체 크기
PostData = "" ' 텍스트 유형으로 변환된 데이터
ReadedBytes = 0 '0으로 초기화되었습니다.
'청크 단위로 읽기
ReadedBytes < TotalBytes인 동안 수행
biData = Request.BinaryRead(ChunkBytes) '현재 청크
PostData = PostData & BinaryToString(biData,ChunkBytes) '현재 청크를 텍스트로 변환하고 접합합니다.
ReadedBytes = ReadedBytes + ChunkBytes '레코드 읽기 크기
ReadedBytes > TotalBytes이면 ReadedBytes = TotalBytes입니다.
고리
Response.Write "<pre>" & PostData & "</pre>" ' pre를 사용하고 형식을 있는 그대로 출력합니다.
' 이진 스트림을 텍스트로 변환
함수 BinaryToString(biData,Size)
상수 adLongVarChar = 201
RS 설정 = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, 크기
RS.오픈
RS.새로 추가
RS("mBinary").AppendChunk(biData)
RS.업데이트
BinaryToString = RS("mBinary").값
RS.닫기
기능 종료
%>
지금 바로 텍스트 파일을 업로드해 보세요. 출력 결과는 블록에서 읽은 내용이 완료되었음을 증명하고 While 루프에서는 루프할 때마다 현재 상태를 애플리케이션에 기록할 수 있으며 그런 다음 Access를 전달할 수 있습니다. 업로드 진행률 표시줄을 동적으로 가져오는 애플리케이션입니다.
또한: 위의 예에서는 바이너리 데이터를 연결하려는 경우 ADODB.Stream 개체의 Write 메서드를 사용할 수 있습니다. 샘플 코드는 다음과 같습니다.
Set bSourceData = createobject("ADODB.Stream" )
bSourceData.Open
bSourceData.Type = 1 '바이너리
ReadedBytes < TotalBytes인 동안 수행
biData = Request.BinaryRead(ChunkBytes)
bSourceData.Write biData ' 쓰기 메소드를 직접 사용하여 현재 파일 스트림을 bSourceData에 씁니다.
ReadedBytes = ReadedBytes + ChunkBytes
ReadedBytes > TotalBytes이면 ReadedBytes = TotalBytes입니다.
Application("ReadedBytes") = 읽은바이트
고리
3. 업로드된 파일을 저장합니다. Request.BinaryRead를 통해 제출된 데이터를 얻습니다. 업로드된 파일을 분리한 후 데이터 유형에 따라 저장 방법이 다릅니다.
바이너리 데이터의 경우 SaveToFile 메소드를 통해 직접 바이너리 스트림을 저장할 수 있습니다. ADODB.Stream 객체가 됩니다.
텍스트 데이터의 경우 TextStream 개체의 Write 메서드를 통해 텍스트 데이터를 파일로 저장할 수 있습니다.
텍스트 데이터와 바이너리 데이터는 서로 쉽게 변환될 수 있으며, 작은 파일을 업로드하는 경우에는 기본적으로 둘 사이에 차이가 없습니다. 그러나 두 가지 방법은 저장 시 약간의 차이가 있습니다. ADODB.Stream 개체의 경우 모든 데이터를 로드해야 파일로 저장할 수 있으므로 이 방법을 사용하여 대용량 파일을 업로드하면 많은 메모리를 차지하게 됩니다. TextStream 개체의 경우 파일이 생성된 후 한 번에 일부를 쓸 수도 있고 여러 번 쓸 수도 있습니다. 위에서 분석한 블록을 통해 업로드된 데이터의 각 부분을 파일에 쓸 수 있습니다. 한 번 실험을 해보니 200MB가 넘는 파일을 같은 기기에 업로드했는데, 첫 번째 방법을 사용하면 메모리가 계속 늘어나서 결국 컴퓨터의 가상 메모리가 부족하다는 메시지가 직접적으로 나타났습니다. 진행 표시줄에는 파일이 업로드되었다고 표시되어 있지만 결국 파일이 저장되지 않았습니다. 후자의 방법을 사용하면 기본적으로 업로드 과정에서 메모리에 변화가 없습니다.
4. 해결되지 않은 문제 Asp.Net 업로드 구성 요소가 Sever.SetTimeOut과 독립적일 수 있다고 설명하는 Bestcomy의 블로그를 보았는데 Asp에서는 대용량 파일을 업로드할 때 Server.SetTimeOut만 사용할 수 있었습니다. 매우 큰 값으로 설정됩니다. 더 나은 해결책이 있는지 모르겠습니다.
파일을 저장할 때 TextStream 개체의 Write 메서드를 사용하면 사용자가 업로드할 때 파일 전송을 중단하더라도 업로드된 파일의 일부가 그대로 유지되어 업로드가 재개될 수 있다면 좋을 것입니다. 중요한 문제는 Request.BinaryRead 메서드가 블록 단위로 읽을 수 있지만 특정 읽기 섹션을 건너뛸 수 없다는 것입니다.
5. 결론 기본적으로는 원리는 명확하게 설명되어 있지만 실제 코드는 이보다 훨씬 복잡합니다. 가장 문제가 되는 부분은 획득한 데이터를 분석하는 것입니다. 설명 정보에 속하는지 분석해 보세요. 양식 항목이 여전히 업로드된 파일인지, 파일이 업로드되었는지...
위의 설명을 바탕으로 자신만의 강력한 컴포넌트 없는 업로드 컴포넌트를 개발할 수도 있다고 믿습니다. 코드에만 관심이 있고 스스로 작성하는 방법을 모르는 사람들이 더 많아진 것 같아요. 어쩌면 시간이 없을 수도 있고, 레벨이 부족할 수도 있고, 그냥 습관이 된 것 같아요... CSDN에서 너무 많은 기술을 보았습니다. 8부분으로 구성된 에세이(설명 단락, 그리고 모든 코드)입니다. 사람에게 낚시를 가르치는 것은 낚시를 가르치는 것만큼 좋지 않습니다. 내가 코드를 알려준다면 다음에 비슷한 문제가 발생하면 왜 그런지 생각하지 않고 그냥 사용하게 될 것입니다. 이 기사가 더 많은 사람들이 무언가를 배우는 데 도움이 되기를 바랍니다. 가장 중요한 것은 무언가를 "계몽"하는 것입니다!