文件hash、上传,实现文件上传重复验证
在平台开发中,我们往往对性能要求十分严苛,每一个字段、接口都有严格的要求。
系统中文件流操作十分占用资源,这里为大家介绍对文件上传进行哈希校验---同一文件只允许上传一次到服务器,其他的上传只要指向文件地址即可。
首先需要设计一张用于文件管理的业务表:
public class SysFile { public int Id { get; set; } /// <summary> /// 文件名称 /// </summary> [StringLength(100)] public string FileName { get; set; } /// <summary> /// 文件存放路径 /// </summary> [StringLength(200)] public string FilePath { get; set; } /// <summary> /// 存放目录 /// </summary> [StringLength(100)] public string FileDirectory { get; set; } /// <summary> /// 文件大小 /// </summary> public int FileSize { get; set; } /// <summary> /// 哈希值 SHa256 /// </summary> [StringLength(100)] public string Hash { get; set; } /// <summary> /// 关联表 /// </summary> public string LinkName { get; set; } /// <summary> /// 关联ID /// </summary> public int LinkID { get; set; } }
实际项目中可以根据该表写一个领域服务,方便接口调用。
由于需要验证文件是否存在,所以需要提供查询和上传接口:
public async Task<List<UploadFileDto>> Check(List<UploadFileDto> input)
{
var existFiles = await _fileRepository.GetAllListAsync(_ => input.Select(f => f.FileHash).Contains(_.Hash));
foreach (var file in input)
{
var existFile = existFiles.FirstOrDefault(_ => _.Hash == file.FileHash);
if(existFile!=null)
{
input.Remove(file);
}
}
return input;
}
public async Task<bool> Upload(IFormFileCollection files)
{
if (!files.Any())
return false;
var filePath = Path.Combine(_env.ContentRootPath, "wwwroot/Upload");
if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath);
foreach (var file in files)
{
var fileName = $"{Guid.NewGuid()}@{file.FileName}";
var tempFilePath = Path.Combine(filePath, fileName);
using (var fileStream = new FileStream(Path.Combine(filePath, fileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
return true;
}
UploadFileDto:
public class UploadFileDto
{
public string FileHash { get; set; }
public string FileName { get; set; }
}
后台需要以下步骤:
1、对前端计算的文件哈希值进行查询,返回数据库中不存在的文件信息
2、将已存在的文件进行路径指向,此时这些文件就不需要再次上传,只要在数据库中加一条路径指向就可以了
3、对服务器不存在的文件进行逐一上传
由于文件的hash算法是在前端实现,所有后台处理的方式有多种,大家可以根据自己的业务和需求进行调整。
前端(angular)的实现,前端的实现是采用开源的js包,所以任何框架均可实现
首先安装js-sha256包:npm install js-sha256
在需要上传的模块中进行引用: import { sha256 } from 'js-sha256';
这里使用的是primeng中的上传组件,在选择文件后进行哈希计算:
onSelect(event, form): void {
if (form.files.length == 1) {
this.uploadDto.pop();
}
for (const file of event.files) {
let self = this;
let fr = new FileReader();
var upload = new UploadFileDto();
upload.fileName = file.name;
fr.readAsArrayBuffer(file);
fr.onload = function (data: any) {
let fi = data.target.result;
var hash = sha256(fi);
upload.fileHash = hash;
self.uploadDto.push(upload);
}
}
}
点击上传:
myUploader(event, form): void {
if (event.files.length == 0) {
return;
}
this.uploading = true;
this._filesUploadService.check(this.uploadDto)
.subscribe(result => {
this.uploadDto = result;
});
let input = new FormData();
for (const file of event.files) {
var uploadFile = this.uploadDto.find(_ => _.fileName == file.name);
if (uploadFile) {
input.append('files', file);
}
}
this._httpClient
.post(this.uploadUrl, input)
.subscribe(result => {
if (result) {
for (const file of event.files) {
this.uploadedFiles.push(file);
}
form.clear();
this.uploading = false;
this.message.success('上传成功!');
}
else {
this.uploading = false;
this.message.error('上传失败!');
}
},
error=>{
this.message.error('上传失败!');
});
}
其他开发人员可能对angular语法有点难懂,其实核心只有三步:
1、选择文件并对文件进行计算
2、上传计算的文件信息并获取返回信息
3、对返回的文件信息进行包装,将文件流一并传入接口
总结:以上只是对文件校验上传的简单实现,如有不足之处,还请多多赐教。
转载于:https://www.cnblogs.com/william-xu/p/11091395.html

浙公网安备 33010602011771号