asp教程.net实现 文件断点续传的功能
1.文件断点续传的功能由接收方管理。
2.在每次文件接收中断的时候,会创建一个等待续传的项目对象,使用resumedfileitem类来封装相关的信息。
///
/// 有可能被续传的项目。
///
public class resumedfileitem
{
#region senderid
private string senderid;
///
/// 发送者的id。
///
public string senderid
{
get { return senderid; }
set { senderid = value; }
}
#endregion#region originfilepath
private string originfilepath;
///
/// 发送方发送的文件的全路径。
///
public string originfilepath
{
get { return originfilepath; }
set { originfilepath = value; }
}
#endregion#region originfilesize
private long originfilesize = 0;
///
/// 发送方发送的文件的大小。
///
public long originfilesize
{
get { return originfilesize; }
set { originfilesize = value; }
}
#endregion#region originfilelastupdatetime
private datetime originfilelastupdatetime;
///
/// 发送方发送的文件的最后修改日期。
///
public datetime originfilelastupdatetime
{
get { return originfilelastupdatetime; }
set { originfilelastupdatetime = value; }
}
#endregion#region localtempfilesavepath
private string localtempfilesavepath;
///
/// 接收的临时文件的存储路径
///
public string localtempfilesavepath
{
get { return localtempfilesavepath; }
set { localtempfilesavepath = value; }
}
#endregion#region localfilesavepath
private string localfilesavepath;
///
/// 接收的文件存储路径
///
public string localfilesavepath
{
get { return localfilesavepath; }
set { localfilesavepath = value; }
}
#endregion#region receivedcount
private long receivedcount = 0;
///
/// 已经接收了多少字节数。
///
public long receivedcount
{
get { return receivedcount; }
set { receivedcount = value; }
}
#endregion#region disrupttedtime
private datetime disrupttedtime = datetime.now;
///
/// 接收中断的时间。
///
public datetime disrupttedtime
{
get { return disrupttedtime; }
set { disrupttedtime = value; }
}
#endregion
}
要记录的这些信息从哪里获取了?首先,是发送方在发送文件的时候,会将文件的相关信息告知接收方,如 被发送文件的全路径、被发送文件的大小、被发送的文件的最后修改日期等等;其次,当接收方接收文件时,就知道了临时文件的存储路径、正式文件的存储路径;再次,当文件传输中断的时刻,可以知道当前的文件已经被传递了多少字节。有了这些信息,断点续传才成为可能。
3.使用iresumedfilemanager将所有的续传项目管理起来。
public interface iresumedfilemanager
{
///
/// 当一个续传项超过多长时间没被使用,则将其移除,同时删除对应的临时文件。单位:秒。默认值:600。
///
int ttl4resumedfileitem { get; set; }///
/// 是否启用文件的断点续传功能。默认值 true。
///
bool enabled { get; set; }iagilelogger esflogger { set; }
void initialize();
void add(resumedfileitem resumedfileitem);
///
/// 当接收一个文件之前,先看能否找到续传的匹配项(同时判断临时文件是否存在)。如果没有匹配,则返回null。
///
resumedfileitem mapping4receive(transmittingfileinfo fileinfo);//
/// 移除续传项。
///
/// 要移除的续传项
/// 是否同时删除临时文件
void remove(resumedfileitem resumedfileitem, bool deletetempfile);
}
resumedfilemanager提供了定时删除过期的续传项目的功能,比如,一个续传项目在文件中断传输以后的10分钟内都没被激活,则视其为过期项目,将会被resumedfilemanager从内存中删除。这样就避免累积很多无效的续传项目对象,而浪费内存。
resumedfilemanager的remove方法用于从内存中移除某个续传项目,其第二个参数表示是否删除临时文件,当某个续传项目因过期而被删除时,这时必须将临时文件也删除掉,以释放硬盘空间 -- 特别是对于作为文件服务器的服务端,这点更是重要的,否则,众多永远也不会被用到的临时文件将会浪费大量的硬盘空间。如果是因为找到匹配项而从管理器中移除续传项时,则不能删除临时文件,因为接下来临时文件会被继续使用。
4.当接收方在接收一个文件之前,首先调用iresumedfilemanager的mapping4receive方法寻找续传匹配项。当同时满足三个条件时(即originfilepath、originfilesize、originfilelastupdatetime),匹配才算成功。
if (item.originfilepath == fileinfo.originfilepath && item.originfilesize == fileinfo.filesize && item.originfilelastupdatetime == fileinfo.originfilelastupdatetime)
{
return item;
}
如此,可以保证续传的文件与上次传输中断的文件是同一个文件。
5.当找到匹配项时,可以询问用户是否接受续传,esplus通过回调ifilebusinesshandler.readytoacceptfileasyn方法得到回复。
string readytoacceptfileasyn(string senderid, string filename, long filelength, string comment, string fileid, resumedfileitem resumedfileitem);
如果返回值为null,表示拒绝接收;如果返回的存储路径与上次的存储路径相同,则表示同意续传;如果返回新的路径,则表示要求发送方重新发送整个文件。框架根据该方法的返回值而决定是否在后台启动续传。
6.如果同意续传,则接收方会告知发送方已接收的字节数,发送方可以从文件的对应偏移处开始发送后续数据。
rejectoracceptfilecontract协议说明了这一点。
public class rejectoracceptfilecontract
{
#region fileid
private string fileid;
public string fileid
{
get { return fileid; }
set { fileid = value; }
}
#endregion#region agree
private bool agree;
public bool agree
{
get { return agree; }
set { agree = value; }
}
#endregion#region receivedcount4resumefile
private long receivedcount4resumefile = 0;
///
/// 如果值非0,则表示续传,指示已经传递了多少字节。
///
public long receivedcount4resumefile
{
get { return receivedcount4resumefile; }
set { receivedcount4resumefile = value; }
}
#endregion
}
7.如果续传开始,则接收方首先需要打开原始的临时文件,并寻址到正确的偏移处。
this.fstream = new filestream(this.tempfilepath, filemode.open);
this.fstream.seek(item.receivedcount, seekorigin.begin);
8.接下来就和以前一样进行正常的文件传输了。这样的设计,可以支持同一文件的无限次断点续传,也就是说,你在传送一个巨大文件的时候,哪怕中途断网很多次,也没关系,你不需要额外地重复传递哪怕一个字节。