1、实现原理
????????前端采用 webkitdirectory 属性选择文件夹,然后遍历文件夹中的文件,循环调用后端接口一个文件一个文件的上传。某度网盘也是同样的原理。
2、前端实现
????????本文记录了Angular的写法,原生html+js的方式代码也差不多。模板页面代码如下:
<input?type="file"?(change)="selectFolder($event)"?webkitdirectory?/>
ts 代码 selectFolder 方法如下:
??selectFolder(event:?any)?{
????let?files?=?event.target.files;
????console.log(files);
????for?(let?i?=?0;?i?<?files.length;?i++)?{
??????let?formData?=?new?FormData();
??????formData.append("file",?files[i]);
??????this.http.post("http://127.0.0.1:8888/api/xxx/upload",?formData).subscribe(d?=>?{
????????console.log(d);
??????});
????}
??}
//组件构造方法中注入的HttpClient
constructor(private?http:?HttpClient)?{
??}
? ? ? ?页面运行效果:
?????????点击按钮选择文件夹:
? ? ? ? 这里如果 input 标签没有添加?webkitdirectory 属性,就不会有上传按钮,取而代之的是打开按钮,只能打开文件夹进行文件选择,而不能选中文件夹进行上传。选中文件夹a点击上传,会出现上传提示:
????????点击上传按钮完成操作。?查看打印可以发现,发送的对象里边有一个webkitRelativePath字段,包含了文件的完整路径信息:
?3、后端实现
????????后端代码需要实现接收前端请求,将流保存为本地文件。本文记录的是netcore api的实现,在Controller 中添加 Action:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
[HttpPost]
public MsgResult Upload(IFormFile file)
{
var result = new MsgResult(1, "成功");
string baseFolder = AppDomain.CurrentDomain.BaseDirectory + "/upload/"; //上传文件保存的根目录
if (!Directory.Exists(baseFolder))
{
Directory.CreateDirectory(baseFolder);
}
var subFolders = file.FileName.Split("/").SkipLast(1).ToList(); //文件多级目录文件夹名称
string folder = baseFolder;
for (int j = 0; j < subFolders.Count; j++)
{
folder = folder + subFolders[j] + "/";
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder); //若不存文件夹则创建
}
}
string path = baseFolder + file.FileName;
using (var stream = new FileStream(path, FileMode.Create))
{
file.CopyTo(stream);
}
return result;
}
????????通过代码可以发现 file.FileName 字段就包含了文件的完整路径信息,调试监视文件对象:
????????运行程序,就可以发现在程序的执行目录下保存了与前端上传的相同的目录结构及文件。?
|