C#/Asp.net 结合 Delphi 实现大文件的断点续传 [Chukeh.dll]
最近手上的一个项目需要经常的应对大于 2GB 以上文件的上传及管理,目前的.net系统虽然可以上传大于 2GB 的文件,但是由于 Http 上传不是特别稳定,所以一旦中断,或者中途无响应,那就需要从头重新传一次,这对用户确实非常不友好,所以决定在不对 .net 系统做大改动的前提下,借助 delphi 开发客户端来实现断点续传。
基本思路是,由 delphi 把要上传的文件分块,然后用 idhttp 模拟 post 请求,提交文件块,.net 以 Request.Files 方式接收数据,然后根据同时提交的 position 和 block
参数写入临时文件,上传完毕后再重名名文件,这样客户端只要记下最后的 position 参数,就可以在任意位置开始续传文件了。
您可以到这里下载示例代码 http://www.easyfrms.com/easy/chukeh/Chukeh_1_2_0.rar
[解压后的Samples\Upload Sample目录]
http://www.easyfrms.com/easy 这里有实际的应用效果
具体代码如下:
Delphi 客户端
定义全局变量
GLOBAL_POSITION: Int64; // 记录上传进度
GLOBAL_TASK: TUploadFile; // 上文文件线程对象
启动下载文件
GLOBAL_TASK:= TUploadFile.Create(Edit2.Text, Edit1.Text);
try
GLOBAL_TASK.Resume;
except
// 启动文件上传错误,无法启动线程
end;
暂停下载文件
if Assigned(GLOBAL_TASK) then begin
try
GLOBAL_TASK.Pause;
except
// 暂停文件上传错误,无法暂停线程
end;
取消下载文件
if Assigned(GLOBAL_TASK) then begin
try
GLOBAL_TASK.Cancel;
except
// 暂停文件上传错误,无法暂停线程
end;
TUploadFile 的源代码,请下载上面的示例代码 (抱歉,论坛不允许内容太长)
C#.Net 服务端
try
{
int _Block = Convert.ToInt32(this.Request.Params["Block"]);
long _Size = Convert.ToInt64(this.Request.Params["Size"]);
long _Position = Convert.ToInt64(this.Request.Params["Position"]);
string _FileName = Path.GetFileName(this.Request.Files["FileData"].FileName);
// 这里我使用了 Chukeh.Net 这个类,这个方法的实现代码见下
Chukeh.Current.SavePostedFile(Context.Server.MapPath(_FileName), true, "FileData", _Size, _Position, _Block);
Context.Response.Write("0");
}
catch
{
Context.Response.Write("1");
}
/// <summary>
/// 保存提交的文件数据到指定位置[流方式,用于实现断点续传]
/// </summary>
/// <param name="FileName">string 文件保存位置</param>
/// <param name="CreateDirectory">bool 是否创建文件夹</param>
/// <param name="PostedFile">string 提交的文件参数名称</param>
/// <param name="Size">long 文件尺寸</param>
/// <param name="Position">long 进度</param>
/// <param name="Block">int 流大小</param>
/// <returns>Data.CResult 保存结果</returns>
public static Data.CResult SavePostedFile(string FileName, bool CreateDirectory, string PostedFile, long Size, long Position, int Block)
{
if (HttpContext.Current.Request.Files[PostedFile] == null || HttpContext.Current.Request.Files[PostedFile].InputStream == null ||
HttpContext.Current.Request.Files[PostedFile].InputStream.Length <= 0)
{
return new Chukeh.Data.CResult(5, "提交了空数据,无法执行保存");
}
else
{
string _TempFileName = FileName + ".tmp";
if (Position == 0)
{
if (!Directory.Exists(Path.GetDirectoryName(_TempFileName)) && CreateDirectory)
{
Directory.CreateDirectory(Path.GetDirectoryName(_TempFileName));
}
if (Directory.Exists(Path.GetDirectoryName(_TempFileName)))
{
FileStream _FileStream = new FileStream(_TempFileName, FileMode.Append);
_FileStream.Close();
_FileStream.Dispose();
}
else
{
return new Chukeh.Data.CResult(4, "目标保存路径不存在或已删除");
}
}
if (Position > Size)
{
IO.CFile.FileDelete(_TempFileName);
return new Chukeh.Data.CResult(3, "提交的数据流超出文件范围");
}
if (File.Exists(_TempFileName))
{
byte[] _Buffer = new byte[Block];
FileStream _FileWriter = new FileStream(_TempFileName, FileMode.Open, FileAccess.ReadWrite);
if (_FileWriter.Length > Position)
{
_FileWriter.Position = Position;
}
else
{
_FileWriter.Seek(0, SeekOrigin.End);
}
HttpContext.Current.Request.Files[PostedFile].InputStream.Read(_Buffer, 0, _Buffer.Length);
_FileWriter.Write(_Buffer, 0, _Buffer.Length);
_FileWriter.Close();
_FileWriter.Dispose();
if (Position + Block >= Size)
{
File.Move(_TempFileName, FileName);
return new Chukeh.Data.CResult(0, "保存数据流成功,文件已保存完毕");
}
else
{
return new Chukeh.Data.CResult(1, "保存数据流成功,已写入文件 " + Base.ToSize(Position + Block));
}
}
else
{
return new Chukeh.Data.CResult(2, "保存数据流失败,无法写入流至文件");
}
}
} --------------------编程问答-------------------- 不知道以后会不会用到,收藏下、 --------------------编程问答-------------------- 谢谢,楼主,测试了能用
chukeh.dll 的源代码能贴出来吗 --------------------编程问答-------------------- 抱歉!不能,不过其实您也不需要啊.
下面已经贴出了你需要用到的方法的代码
补充:.NET技术 , ASP.NET