.net framework分片上传,最佳实践

核心代码:

   /// 
        /// 上传分片文件
        /// 
        /// 
        [HttpPost, Route("uploader/chunk")]
        public async Task UploadChunk()
        {
            try
            {
                var provider = new MultipartFormDataStreamProvider(Path.GetTempPath());
                await Request.Content.ReadAsMultipartAsync(provider);
                var chunk = new ChunkEntity()
                {
                    ChunkNumber = int.Parse(provider.FormData.GetValues("chunkNumber").FirstOrDefault()),
                    ChunkSize = long.Parse(provider.FormData.GetValues("chunkSize").FirstOrDefault()),
                    CurrentChunkSize = long.Parse(provider.FormData.GetValues("currentChunkSize").FirstOrDefault()),
                    TotalSize = long.Parse(provider.FormData.GetValues("totalSize").FirstOrDefault()),
                    Identifier = provider.FormData.GetValues("identifier").FirstOrDefault(),
                    Filename = provider.FormData.GetValues("filename").FirstOrDefault(),
                    RelativePath = provider.FormData.GetValues("relativePath").FirstOrDefault(),
                    TotalChunks = int.Parse(provider.FormData.GetValues("totalChunks").FirstOrDefault()),
                };
                var file = provider.FileData.FirstOrDefault();
                Console.WriteLine($"file originName: {file.LocalFileName}, chunkNumber: { chunk.ChunkNumber}");
                string root = @"E:\代码练习\dotNetPractiseCollect\chunk-files\files-storege";// your local path
                if (!Directory.Exists(root)) Directory.CreateDirectory(root);
                var filePath = file.LocalFileName;
                var rawFileBytes = File.ReadAllBytes(filePath);
                // 将文件移动到指定文件夹
                var targetFilePath = GenerateUploadPath(root, chunk);
                File.WriteAllBytes(targetFilePath, rawFileBytes);
                //保存分片记录
                using (var db = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = "Server=localhost;Port=3306;Database=test;Uid=root;Pwd=123456;",
                    DbType = DbType.MySql, // 数据库类型
                    IsAutoCloseConnection = true, // 自动释放连接,避免内存泄漏
                }))
                {
                    Guid guid = Guid.NewGuid();
                    chunk.Id = BitConverter.ToInt64(guid.ToByteArray(), 0);
                    db.Insertable(chunk).ExecuteCommand();
                }
                return Request.CreateResponse(HttpStatusCode.OK, "文件上传成功");
            }
            catch (Exception e)
            {

                Console.WriteLine(e.Message);
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "服务器内部异常");
            }
        }

        /// 
        /// 检查分片文件
        /// 
        /// 
        /// 
        [HttpGet, Route("uploader/chunk")]
        public HttpResponseMessage CheckChunk([FromUri] ChunkEntity chunk)
        {
            try
            {
                if (checkChunk(chunk.Identifier, chunk.ChunkNumber) == false)
                {
                    return Request.CreateResponse(HttpStatusCode.NotModified);
                }
                return Request.CreateResponse(HttpStatusCode.OK, chunk);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "服务器内部异常");
            }

        }

        /// 
        /// 合并分片文件
        /// 
        /// 
        /// 
        [HttpPost]
        [Route("uploader/mergeFile")]
        public async Task MergeFileAsync([FromBody] MergeFileDto fileInfo)
        {
            try
            {
                string filename = fileInfo.Filename;
                string uploadFolder = @"E:\代码练习\dotNetPractiseCollect\chunk-files\files-storege";// your local path
                var file = uploadFolder + "/" + fileInfo.Identifier + "/" + filename;
                var folder = uploadFolder + "/" + fileInfo.Identifier;
                var isMergeOk = await MergeChunkFilesAsync(file, folder, filename);
                using (var db = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = "Server=localhost;Port=3306;Database=test;Uid=root;Pwd=123456;",
                    DbType = DbType.MySql, // 数据库类型
                    IsAutoCloseConnection = true, // 自动释放连接,避免内存泄漏
                }))
                {
                    db.Deleteable().Where(x => x.Identifier == fileInfo.Identifier).ExecuteCommand();

                }
                if (isMergeOk == false)
                {
                    Console.WriteLine("合成的文件:" + filename);
                    return Request.CreateResponse(HttpStatusCode.BadRequest, "合并失败");
                }

                return Request.CreateResponse(HttpStatusCode.BadRequest, "合并失败");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "服务器内部异常");
            }

        }
        /// 
        /// 查询分片是否存在
        /// 
        /// 
        /// 
        /// true:分片存在,false:分片不存在
        private bool checkChunk(string identifier, int chunkNumber)
        {
            try
            {
                using (var db = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = "Server=localhost;Port=3306;Database=test;Uid=root;Pwd=123456;",
                    DbType = DbType.MySql, // 数据库类型
                    IsAutoCloseConnection = true, // 自动释放连接,避免内存泄漏
                }))
                {
                    var flag = db.Queryable().Where(x => x.Identifier == identifier && x.ChunkNumber == chunkNumber).Count() > 0;
                    return flag;
                }

             
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
        }

        /// 
        /// 生成上传文件路径
        /// 
        /// 
        /// 
        /// 
        private string GenerateUploadPath(string uploadFolder, ChunkEntity chunk)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(uploadFolder).Append("/").Append(chunk.Identifier);
            //判断uploadFolder/identifier 路径是否存在,不存在则创建
            if (!Directory.Exists(sb.ToString()))
            {
                Console.WriteLine("文件路径不存在: {0}", sb.ToString());
                try
                {
                    Directory.CreateDirectory(sb.ToString());
                }
                catch (IOException e)
                {
                    Console.WriteLine(e);
                }
            }
            var path = sb.Append("/").Append(chunk.Filename).Append("-").Append(chunk.ChunkNumber).ToString();
            return path;
        }


        /// 
        /// 分片文件合并
        /// 
        /// 目标文件名
        /// 源文件所在目录
        /// 需要排除的文件名
        /// 返回是否成功合并
        private async Task MergeChunkFilesAsync(string targetFile, string folder, string filename)
        {

            DirectoryInfo directory = new DirectoryInfo(folder);
            var files = directory.GetFiles();
            // 根据文件名中的“-”进行排序,按照降序排列
            var paths = new List();
            foreach (var item in files)
            {
                var ext = Path.GetExtension(item.FullName);
                if (ext.Contains("-"))
                {
                    paths.Add(item.FullName);
                }
            }
            paths = paths.OrderBy(path => int.Parse(path.Split('-').Last())).ToList();
            if (System.IO.File.Exists(targetFile))
            {
                System.IO.File.Delete(targetFile);
            }
            using (var fileStream = new FileStream(targetFile, FileMode.Create))
            {
                // 依次将非排除文件的内容追加到目标文件中,并删除源文件
                foreach (var path in paths)
                {

                    var saveFile = files.Where(x => x.FullName == path).FirstOrDefault();
                    using (FileStream fileChunk = new FileStream(saveFile.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        await fileChunk.CopyToAsync(fileStream);
                    }
                    //合并后删除该块
                    File.Delete(saveFile.FullName);
                }
            }
            return true;
        }

完整前后端代码如下,请慢慢享用。

dotNetPractiseCollect/chunk-files at master · LeoMingGit/dotNetPractiseCollect · GitHub

你可能感兴趣的:(.net)