C#实现Google Drive文件上传前MD5查重:哈希生成位置咨询
我现在有一段将文件上传至Google Drive的代码,需求是用户点击上传按钮时,检查文件的MD5哈希并与Google Drive中其他文件的MD5哈希对比,若存在重复则弹出提示告知文件重复,需重新上传。以下是我的相关代码:
视图代码(GetGoogleDrive.cshtml)
@using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { <p> <label for="file">Upload file:</label> <input type="file" name="file" id="file" /> <input type="submit" value="Upload" id="fileUpload" /> <script> $('#fileUpload').click(function (e) { if ($('#file').val() === "") { Swal.fire({ title: 'Nothing', text: 'No file selected', type: 'error', confirmButtonText: 'Again!!', timer: 4000 }) } else { Swal.fire({ title: 'Wait awhile...', text: 'File will be uploaded shortly', type: 'success', confirmButtonText: 'Okay, cool', timer: 4000 }) } }); </script>
上传文件控制器代码
[HttpPost] public ActionResult UploadFile(HttpPostedFileBase file) { GoogleDriveFilesRepository.FileUpload(file); return RedirectToAction("GetGoogleDriveFiles"); }
Google Drive文件模型类代码
public static void FileUpload(HttpPostedFileBase file) { if (file != null && file.ContentLength > 0) { DriveService service = GetService(); string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"), Path.GetFileName(file.FileName)); file.SaveAs(path); HashGenerator(path); compareHash(HashGenerator(path)); var FileMetaData = new Google.Apis.Drive.v3.Data.File(); FileMetaData.Name = Path.GetFileName(file.FileName); FileMetaData.MimeType = MimeMapping.GetMimeMapping(path); FilesResource.CreateMediaUpload request; using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open)) { request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType); request.Fields = "id"; request.Upload(); } } }
结合你的需求和现有代码,我更推荐在C#后端生成并对比MD5哈希,原因如下:
1. 安全性与可信度
前端JS生成的哈希可以被轻易篡改——用户只要懂点基础技术,就能通过浏览器控制台修改哈希值绕过重复检查。而后端生成的哈希完全在服务器端处理,无法被客户端干预,能确保对比结果的真实性,避免恶意上传重复文件。
2. 与Google Drive交互的便利性
你的compareHash逻辑需要和Google Drive的文件哈希做对比,而Google Drive API的交互(获取已上传文件的哈希)本身就是在后端通过DriveService实现的。在后端直接生成本地文件的MD5,再和从Drive API获取的哈希对比,代码逻辑更连贯,不需要额外的跨域请求传递哈希值,减少了前后端交互的复杂度。
3. 处理大文件的性能
如果用户上传大文件,前端JS读取整个文件计算MD5会占用大量浏览器资源,可能导致页面卡顿甚至崩溃。后端服务器通常有更强的性能,处理大文件的哈希计算更稳定,还可以通过异步处理避免阻塞请求。
调整代码的具体建议
第一步:完善后端的哈希生成与对比逻辑
补全你现有的HashGenerator和compareHash方法:
// 生成文件MD5哈希的方法 public static string HashGenerator(string filePath) { using (var md5 = MD5.Create()) { using (var stream = File.OpenRead(filePath)) { byte[] hashBytes = md5.ComputeHash(stream); // 转换为十六进制字符串格式 return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant(); } } } // 对比哈希:从Google Drive查询所有文件的MD5,检查是否重复 public static bool compareHash(string localHash) { DriveService service = GetService(); // 查询文件时只获取id和md5Checksum字段,减少数据传输 var request = service.Files.List(); request.Fields = "files(id, md5Checksum)"; var result = request.Execute(); foreach (var file in result.Files) { if (!string.IsNullOrEmpty(file.Md5Checksum) && file.Md5Checksum.Equals(localHash, StringComparison.OrdinalIgnoreCase)) { // 找到重复文件 return true; } } return false; }
第二步:修改上传逻辑,添加重复检查
在FileUpload方法中,先检查哈希是否重复,若重复则终止上传并清理临时文件:
public static void FileUpload(HttpPostedFileBase file) { if (file != null && file.ContentLength > 0) { DriveService service = GetService(); string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"), Path.GetFileName(file.FileName)); file.SaveAs(path); string localHash = HashGenerator(path); if (compareHash(localHash)) { // 删除临时保存的文件 File.Delete(path); throw new Exception("文件已存在于Google Drive中,请重新选择文件上传"); } var FileMetaData = new Google.Apis.Drive.v3.Data.File(); FileMetaData.Name = Path.GetFileName(file.FileName); FileMetaData.MimeType = MimeMapping.GetMimeMapping(path); FilesResource.CreateMediaUpload request; using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open)) { request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType); request.Fields = "id"; request.Upload(); } // 上传完成后删除临时文件 File.Delete(path); } }
第三步:在控制器中捕获异常,返回提示给前端
修改UploadFile控制器方法,处理异常并将错误信息传递到前端:
[HttpPost] public ActionResult UploadFile(HttpPostedFileBase file) { try { GoogleDriveFilesRepository.FileUpload(file); return RedirectToAction("GetGoogleDriveFiles"); } catch (Exception ex) { ViewBag.ErrorMessage = ex.Message; return View("GetGoogleDrive"); // 返回上传页面并携带错误信息 } }
第四步:前端显示错误提示
在GetGoogleDrive.cshtml中添加错误信息的弹出逻辑:
@if (!string.IsNullOrEmpty(ViewBag.ErrorMessage)) { <script> Swal.fire({ title: '上传失败', text: '@ViewBag.ErrorMessage', type: 'error', confirmButtonText: '重新上传' }); </script> }
当然,如果你的业务场景中都是小文件,也可以考虑前端先计算哈希,再请求后端检查是否存在——这样能提前拦截重复文件,减少不必要的文件上传流量。但这种方式必须注意:后端仍然需要再次验证哈希,防止前端篡改。综合来看,后端处理是更稳妥的方案。
内容的提问来源于stack exchange,提问作者Viv

