如何通过.NET Core Web API无压缩上传含子文件夹且保留结构的完整目录
实现方案
可以无需压缩直接上传完整文件夹并保留原有目录结构,核心依赖浏览器的webkitdirectory上传能力,前后端配合即可实现。
1. 前端配置
首先前端上传控件需要开启文件夹上传属性,提交时携带每个文件的相对路径:
<!-- 上传控件开启文件夹选择 --> <input type="file" id="folderUpload" webkitdirectory multiple />
提交的JS逻辑示例:
const uploadInput = document.getElementById('folderUpload'); const formData = new FormData(); // 遍历选中的所有文件,传入相对路径作为第三个参数 for (const file of uploadInput.files) { formData.append('files', file, file.webkitRelativePath); } // 提交FormData到后端接口 fetch('/api/你的控制器名/import', { method: 'POST', body: formData })
2. 后端代码改造
你现有代码的核心问题是没有处理文件的相对路径,也没有按路径创建对应层级目录,改造后代码如下:
private async Task<bool> Import() { bool isSaveSuccess = false; // 统一设置根存储目录 var rootSaveDir = Path.Combine(Directory.GetCurrentDirectory(), "Upload", "files1"); if (!Directory.Exists(rootSaveDir)) { Directory.CreateDirectory(rootSaveDir); } var files = Request.Form.Files; foreach (var file in files) { try { // file.FileName就是前端传入的相对路径,格式如"二级文件夹/三级文件夹/测试文件.txt" var relativePath = file.FileName; // 安全校验:禁止路径穿越,避免恶意上传到根目录外 if (relativePath.Contains("..") || Path.IsPathRooted(relativePath)) { continue; } // 如果需要避免文件重名,可以打开以下注释加时间戳重命名 /* var fileName = Path.GetFileName(relativePath); var newFileName = $"{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.Ticks}{Path.GetExtension(fileName)}"; relativePath = Path.Combine(Path.GetDirectoryName(relativePath), newFileName); */ // 拼接完整存储路径,创建对应层级目录 var fullSavePath = Path.Combine(rootSaveDir, relativePath); var fileDir = Path.GetDirectoryName(fullSavePath); if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); } // 保存文件 using (var stream = new FileStream(fullSavePath, FileMode.Create)) { await file.CopyToAsync(stream); } isSaveSuccess = true; } catch (Exception ex) { _logger.LogError("文件保存失败:{Msg}", ex.Message); } } return isSaveSuccess; }
3. 注意事项
- 请调整Kestrel/IIS的上传大小限制,避免大文件/多文件批量上传时触发请求大小拦截
webkitdirectory为所有主流浏览器支持的特性,若需兼容非常老旧的浏览器,仍建议使用压缩包上传后解压的方案- 生产环境建议对可上传的文件类型做白名单校验,避免恶意脚本上传
内容的提问来源于stack exchange,提问作者Lax
相关产品推荐
相关产品推荐

