일반적으로 파일 업로드 시 업로드할 파일은 클라이언트를 통해 서버에 업로드되는데, 이때 업로드된 파일은 모두 서버 메모리에 들어있습니다. 매우 빡빡하며 일반적으로 비동기 업로드에 플래시나 HTML5를 사용합니다. 파일이 상대적으로 크면 클라이언트가 파일이 100% 업로드되었다고 표시하더라도 여전히 오래 기다려야 하며 현재 페이지의 요청은 다음과 같습니다. 서버도 차단됩니다.
일반적인 상황에서는 장기간의 전송이 완료된 후 서버에 직접 저장되는 경우가 많습니다.
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; //保存文件 context.Request.Files[0].SaveAs(context.Server.MapPath("~/1/" + context.Request.Files[0].FileName)); context.Response.Write("Hello World"); }
최근 프로젝트에서는 Baidu의 오픈소스 업로드 구성 요소인 webuploader가 사용되었습니다. 공식적으로 webuploader는 다중 부분 업로드를 지원합니다.
var uploader = WebUploader.create({ auto: true, swf:'/webuploader/Uploader.swf', // 文件接收服务端。 server: '/Uploader.ashx', // 内部根据当前运行是创建,可能是input元素,也可能是flash. pick: '#filePicker', chunked: true,//开启分片上传 threads: 1,//上传并发数 //由于Http的无状态特征,在往服务器发送数据过程传递一个进入当前页面是生成的GUID作为标示 formData: {guid:"<%=Guid.NewGuid().ToString()%>"} });
Webuploader의 멀티파트 업로드는 파일을 여러 부분으로 나눈 후, 업로드한 파일이 다음과 같으면 정의한 파일 수신자에게 데이터를 게시하는 것입니다. 분할된 것보다 큰 조각의 크기가 조각화되고 두 개의 양식 요소 청크와 청크가 게시물 데이터에 추가됩니다. 전자는 업로드된 조각에서 현재 조각의 순서를 나타내며(0부터 시작) 후자는 총 조각 수를 나타냅니다.
파일을 선택한 후 7개의 샤드로 나누어서 Uploader.ashx에 데이터를 올리는 과정을 총 7번 수행했습니다.
각 요청의 양식 요소 청크 및 청크와 동일한 파일의 조각임을 나타내는 GUID
서버 측에서 데이터를 수신한 후 이러한 매개변수에 따라 처리할 수 있습니다.
1. GUID에 따라 임시 파일을 생성합니다
2. 수신된 조각 데이터를 GUID에 해당하는 파일에 추가합니다.
3. 업로드한 파일명에 맞춰 임시파일 이름을 변경합니다
4. 샤딩하지 않고 직접 저장하면
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; //如果进行了分片 if (context.Request.Form.AllKeys.Any(m => m == "chunk")) { //取得chunk和chunks int chunk =Convert.ToInt32(context.Request.Form["chunk"]); int chunks = Convert.ToInt32(context.Request.Form["chunks"]); //根据GUID创建用该GUID命名的临时文件 string path = context.Server.MapPath("~/1/" + context.Request["guid"]); FileStream addFile = new FileStream(path, FileMode.Append, FileAccess.Write); BinaryWriter AddWriter = new BinaryWriter(addFile); //获得上传的分片数据流 HttpPostedFile file = context.Request.Files[0]; Stream stream = file.InputStream; BinaryReader TempReader = new BinaryReader(stream); //将上传的分片追加到临时文件末尾 AddWriter.Write(TempReader.ReadBytes((int)stream.Length)); //关闭BinaryReader文件阅读器 TempReader.Close(); stream.Close(); AddWriter.Close(); addFile.Close(); TempReader.Dispose(); stream.Dispose(); AddWriter.Dispose(); addFile.Dispose(); //如果是最后一个分片,则重命名临时文件为上传的文件名 if (chunk == (chunks - 1)) { FileInfo fileinfo = new FileInfo(path); fileinfo.MoveTo(context.Server.MapPath("~/1/" + context.Request.Files[0].FileName)); } } else//没有分片直接保存 { context.Request.Files[0].SaveAs(context.Server.MapPath("~/1/" + context.Request.Files[0].FileName )); } context.Response.Write("ok"); }
이 있습니다 여전히 일부 문제가 해결되지 않았지만 당분간 요구 사항은 충족됩니다.
1. 동시 업로드가 1개 이상인 경우 분할 업로드 서버가 처리를 완료하지 못하고 두 번째 분할은 동시에 도착하면 파일이 사용 중이라는 오류가 발생합니다.
2. 잠금으로 첫 번째 문제가 해결되면 잠금은 효율성에 확실히 영향을 미칩니다(동시에 하나의 프로세스만 파일을 저장하는 코드에 액세스할 수 있습니다).
3. 파일 순서에 문제가 있습니다. 두 번째 조각이 먼저 도착한 다음 첫 번째 조각이 도착할 수 있습니다. 그러면 임시 파일에 스트림을 한 번에 추가할 수 없습니다. 임시 파일입니다. 멀티파트 업로드가 완료되면 하나의 파일로 합쳐집니다.
단지 데모일 뿐입니다. 누군가가 기존 문제를 해결하는 데 도움을 줄 수 있기를 바랍니다.