军工项目中,C#在.NET MVC里如何实现文件夹的断点续传上传(示例代码)?
·
一个被20G文件折磨的.NET程序员的求生指南
“甲方爸爸说要兼容IE8?还要20G文件上传?预算100块?” —— 当我看到需求文档时,手里的泡面突然就不香了…🍜
技术方案:在刀尖上跳舞
前端部分:与IE8老爷爷斗智斗勇
// 文件分片上传核心代码(纯手工打造,兼容IE8版)
function uploadFile(file) {
// IE8特供版检测
if (navigator.userAgent.indexOf('MSIE 8.0') > -1) {
alert('尊敬的用户,检测到您正在使用IE8,我们将为您启用特殊兼容模式...');
// 其实就是降级方案...
return ie8SpecialUpload(file);
}
const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB一片
let chunks = Math.ceil(file.size / CHUNK_SIZE);
let uploaded = 0;
// 加密相关(SM4/AES)
let crypto = new SuperCrypto('SM4'); // 这个类当然是我编的...
for (let i = 0; i < chunks; i++) {
let start = i * CHUNK_SIZE;
let end = Math.min(start + CHUNK_SIZE, file.size);
let chunk = file.slice(start, end);
// 加密分片
let encryptedChunk = crypto.encrypt(chunk);
let formData = new FormData();
formData.append('file', encryptedChunk);
formData.append('chunkIndex', i);
formData.append('totalChunks', chunks);
formData.append('fileName', file.name);
formData.append('fileSize', file.size);
// 这里应该是AJAX调用,但为了兼容IE8...
let xhr = new XMLHttpRequest();
xhr.open('POST', '/api/upload', true);
xhr.onload = function() {
uploaded++;
updateProgress(uploaded / chunks * 100);
saveProgressToLocalStorage(file.name, uploaded);
};
xhr.send(formData);
}
}
// IE8特供版上传(Flash后备方案)
function ie8SpecialUpload(file) {
// 这里应该有Flash上传代码...
alert('请安装Flash Player 10.1或更高版本');
return false;
}
后端部分:C# WebForm的救赎
// UploadHandler.ashx 文件上传处理
public class UploadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
try
{
// 获取上传的文件分片
HttpPostedFile file = context.Request.Files["file"];
int chunkIndex = int.Parse(context.Request["chunkIndex"]);
int totalChunks = int.Parse(context.Request["totalChunks"]);
string fileName = context.Request["fileName"];
long fileSize = long.Parse(context.Request["fileSize"]);
// 解密处理
byte[] fileData = new byte[file.InputStream.Length];
file.InputStream.Read(fileData, 0, fileData.Length);
byte[] decryptedData = CryptoHelper.SM4Decrypt(fileData, "密钥");
// 临时保存分片
string tempPath = Path.Combine("E:\\UploadTemp", fileName);
if (!Directory.Exists(tempPath))
Directory.CreateDirectory(tempPath);
string chunkPath = Path.Combine(tempPath, chunkIndex.ToString());
File.WriteAllBytes(chunkPath, decryptedData);
// 检查是否所有分片都已上传
if (Directory.GetFiles(tempPath).Length == totalChunks)
{
// 合并文件
MergeFile(tempPath, "E:\\Uploads\\" + fileName);
Directory.Delete(tempPath, true);
// 记录到数据库
SaveToDb(fileName, fileSize, "E:\\Uploads\\" + fileName);
}
context.Response.Write("{\"status\":\"ok\"}");
}
catch (Exception ex)
{
context.Response.Write("{\"status\":\"error\",\"message\":\"" + ex.Message + "\"}");
}
}
private void MergeFile(string tempPath, string targetPath)
{
// 这里应该有合并文件的代码...
}
private void SaveToDb(string fileName, long fileSize, string filePath)
{
// 这里应该有数据库操作代码...
}
}
开发血泪史
-
IE8兼容性:我尝试了各种黑魔法,最后发现唯一的解决方案是…建议用户换电脑(当然这话不能跟甲方说)
-
20G文件上传:我的开发机只有256G SSD,测试时差点把自己电脑搞崩溃
-
加密传输:SM4在JavaScript端的实现让我掉了不少头发
文件夹上传的终极解决方案
// 文件夹上传保留层级结构
function uploadFolder(event) {
let files = event.target.files;
let folderStructure = {};
// 构建文件夹结构
for (let i = 0; i < files.length; i++) {
let file = files[i];
if (file.webkitRelativePath) {
let paths = file.webkitRelativePath.split('/');
let currentLevel = folderStructure;
for (let j = 0; j < paths.length - 1; j++) {
if (!currentLevel[paths[j]]) {
currentLevel[paths[j]] = {};
}
currentLevel = currentLevel[paths[j]];
}
currentLevel[paths[paths.length - 1]] = file;
}
}
// 递归上传
uploadFolderItem(folderStructure, '');
}
function uploadFolderItem(item, currentPath) {
for (let key in item) {
if (item[key] instanceof File) {
// 上传文件
uploadFile(item[key], currentPath);
} else {
// 创建文件夹
createFolderOnServer(currentPath + key + '/');
// 递归上传子项
uploadFolderItem(item[key], currentPath + key + '/');
}
}
}
数据库设计(SQL Server版)
-- 文件记录表
CREATE TABLE FileRecords (
Id UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
FileName NVARCHAR(255) NOT NULL,
FileSize BIGINT NOT NULL,
FilePath NVARCHAR(MAX) NOT NULL,
UploadTime DATETIME DEFAULT GETDATE(),
IsEncrypted BIT DEFAULT 1,
EncryptionType NVARCHAR(50) DEFAULT 'SM4'
);
-- 上传进度表(用于断点续传)
CREATE TABLE UploadProgress (
SessionId NVARCHAR(255) PRIMARY KEY,
FileName NVARCHAR(255) NOT NULL,
FileMd5 NVARCHAR(255) NOT NULL,
TotalChunks INT NOT NULL,
UploadedChunks INT NOT NULL,
LastUpdateTime DATETIME DEFAULT GETDATE()
);
给甲方爸爸的温馨Tips
-
关于IE8:真的不考虑升级一下吗?现在连微软都不支持IE8了…
-
关于20G文件:建议上传前先压缩,毕竟您家宽带上传20G可能需要一整天
-
关于100块预算:这个价格我们只能提供"心灵支持"服务了…
PS:那个QQ群真的存在,但红包可能已经被抢光了。至于"一个项目提成1万"…醒醒,该搬砖了!👷
设置框架
安装.NET Framework 4.7.2
https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472
框架选择4.7.2
添加3rd引用

编译项目

NOSQL
NOSQL无需任何配置可直接访问页面进行测试
SQL
使用IIS
大文件上传测试推荐使用IIS以获取更高性能。
使用IIS Express
小文件上传测试可以使用IIS Express
创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试

相关参考:
文件保存位置,
下载完整示例
更多推荐
所有评论(0)