在ASP.NET中跟踪和恢复大文件下载
Else
' 单个部分消息拥有的文件内容类型
objResponse.ContentType = objFile.ContentType
End If
下载所需要的一切都准备好了,可以开始下载文件了。你将使用FileStream对象从文件中读取字节块。把FileInformation实例objFile的State属性设置为fsDownloadInProgress。只要客户端保持连接,服务器就从文件中读取字节块并发送给客户端。对于多部分下载,这段代码会发送特定的头信息。如果客户端中断连接,服务器就把文件状态设置为fsDownloadBroken。如果服务器完成了被请求范围的发送过程,它会把状态设置为fsDownloadFinished(见下载代码)。
FileInformation辅助类
在ZIPHandler部分中你会发现,FileInformation是一个辅助类,它封装了下载状态信息(例如下载中、中断等等)。
为了建立FileInformation的实例,你需要把被请求文件的路径传递给该类的构造函数:
Public Sub New(ByVal sPath As String)
m_objFile = New System.IO.FileInfo(sPath)
End Sub
FileInformation使用System.IO.FileInfo对象来获取文件的信息,这些信息是作为该对象的属性暴露的(例如文件是否存在、文件全名、大小等等)。这个类还暴露了一个DownloadState枚举,它描述了下载请求的多种状态:
Enum DownloadState
' Clear:没有下载过程,文件可能在维护
fsClear = 1
' Locked:动态建立的文件不能被更改
fsLocked = 2
' In Progress:文件被锁定了,下载过程正在进行
fsDownloadInProgress = 6
' Broken:文件被锁定了,下载过程正在进行,但是被取消了
fsDownloadBroken = 10
' Finished:文件被锁定了,下载过程完成了
fsDownloadFinished = 18
End Enum
FileInformation还提供了EntityTag属性值。示例代码中的这个值是硬编码的,这是由于示例代码只使用了一个下载文件,并且该文件不会被改变,但是对于实际应用程序来说,你会提供多个文件,甚至于动态地建立文件,你的代码必须为每个文件提供一个唯一的EntityTag值。此外,每次改变或修改该文件的时候,这个值也必须改变。这使客户端软件能够验证它们已经下载的字节块是否仍然是最新的。下面是示例代码中返回硬编码EntityTag值的部分:
Public ReadOnly Property EntityTag() As String
' EntityTag用于对客户端的初始(200)响应,以及来自客户端的恢复请求
Get
' 为文件建立唯一的字符串。
' 注意,只要文件没有发生改变,该唯一码就必须保留。
' 但是,如果文件的确改变了或者被修改了,这个码必须改变。
Return "MyExampleFileID"
End Get
End Property
一个简单的和大致足够安全的EntityTag可能由文件名和文件最后被修改的日期组成。无论使用什么方法,你都必须确保这个值是真的是唯一的,不会与其它文件的EntityTag混淆。我希望在自己的应用程序中按照客户、顾客和邮编索引来动态地替被建立的文件命名,并把用作EntityTag的GUID存储在数据库中。
ZipFileHandler类读取和设置公共的State属性。在完成下载以后,它把State设置为fsDownloadFinished。这个时候你就可以删除临时文件了。这儿一般需要调用Save方法来维持状态。
Public Property State() As DownloadState
Get
Return m_nState
End Get
Set(ByVal nState As DownloadState)
m_nState = nState
' 可选操作:这个时候你可以自动地删除文件。
' 如果状态被设置为Finished ,你就再也不需要这个文件了。
' If nState =DownloadState.fsDownloadFinished Then
' Clear()
' Else
' Save()
' End If
Save()
End Set
End Property
在文件状态发生改变的任何时候ZipFileHandler都应该调用Save方法,保存文件的状态,这样在以后才能显示给用户。你还可以用它来保存你自己建立的EntityTag。请不要把文件的状态和EntityTag值保存在Application、Session或Cache中--你必须跨越所有的这些这些对象的生命周期来保存信息。
Private Sub Save()
' 把该文件下载的状态保存到数据库或XML文件中。
' 当然,如果你并没有动态地建立文件,就不需要保存这个状态。
End Sub
前面提到,示例代码只处理一个已有的文件(download.zip),但是你可以进一步增强这个程序,根据需要建立被请求的文件。
测试示例代码的时候,你的本地系统或LAN可能太快了,以至于无法中断下载过程,因此我推荐你使用慢速LAN连接(在IIS中减少站点的带宽是一种模拟的方法)或者把服务器放到互联网上。
在客户端上下载文件仍然很艰难。ISP操作的不对的或配置错误的Web缓冲服务器都可能使大文件下载过程失败,包括下载状况恶化或早期对话终结。如果文件大小超过了255MB,你就应该鼓励顾客使用第三方下载管理软件,尽管某些最新的浏览器内建了基本的下载管理器。
如果你希望进一步扩展示例代码,查阅一下HTTP规范是有益的。你可以为下载建立MD5校验值,使用Content-MD5头信息添加它们,提供一种验证下载文件完整性的途径。示例代码除了GET和HEAD之外没有涉及到其它的HTTP方法。
做人要厚道,请注明转自chinazhan中国站长(www.ChinaZhan.com)。
' 单个部分消息拥有的文件内容类型
objResponse.ContentType = objFile.ContentType
End If
下载所需要的一切都准备好了,可以开始下载文件了。你将使用FileStream对象从文件中读取字节块。把FileInformation实例objFile的State属性设置为fsDownloadInProgress。只要客户端保持连接,服务器就从文件中读取字节块并发送给客户端。对于多部分下载,这段代码会发送特定的头信息。如果客户端中断连接,服务器就把文件状态设置为fsDownloadBroken。如果服务器完成了被请求范围的发送过程,它会把状态设置为fsDownloadFinished(见下载代码)。
FileInformation辅助类
在ZIPHandler部分中你会发现,FileInformation是一个辅助类,它封装了下载状态信息(例如下载中、中断等等)。
为了建立FileInformation的实例,你需要把被请求文件的路径传递给该类的构造函数:
Public Sub New(ByVal sPath As String)
m_objFile = New System.IO.FileInfo(sPath)
End Sub
FileInformation使用System.IO.FileInfo对象来获取文件的信息,这些信息是作为该对象的属性暴露的(例如文件是否存在、文件全名、大小等等)。这个类还暴露了一个DownloadState枚举,它描述了下载请求的多种状态:
Enum DownloadState
' Clear:没有下载过程,文件可能在维护
fsClear = 1
' Locked:动态建立的文件不能被更改
fsLocked = 2
' In Progress:文件被锁定了,下载过程正在进行
fsDownloadInProgress = 6
' Broken:文件被锁定了,下载过程正在进行,但是被取消了
fsDownloadBroken = 10
' Finished:文件被锁定了,下载过程完成了
fsDownloadFinished = 18
End Enum
FileInformation还提供了EntityTag属性值。示例代码中的这个值是硬编码的,这是由于示例代码只使用了一个下载文件,并且该文件不会被改变,但是对于实际应用程序来说,你会提供多个文件,甚至于动态地建立文件,你的代码必须为每个文件提供一个唯一的EntityTag值。此外,每次改变或修改该文件的时候,这个值也必须改变。这使客户端软件能够验证它们已经下载的字节块是否仍然是最新的。下面是示例代码中返回硬编码EntityTag值的部分:
Public ReadOnly Property EntityTag() As String
' EntityTag用于对客户端的初始(200)响应,以及来自客户端的恢复请求
Get
' 为文件建立唯一的字符串。
' 注意,只要文件没有发生改变,该唯一码就必须保留。
' 但是,如果文件的确改变了或者被修改了,这个码必须改变。
Return "MyExampleFileID"
End Get
End Property
一个简单的和大致足够安全的EntityTag可能由文件名和文件最后被修改的日期组成。无论使用什么方法,你都必须确保这个值是真的是唯一的,不会与其它文件的EntityTag混淆。我希望在自己的应用程序中按照客户、顾客和邮编索引来动态地替被建立的文件命名,并把用作EntityTag的GUID存储在数据库中。
ZipFileHandler类读取和设置公共的State属性。在完成下载以后,它把State设置为fsDownloadFinished。这个时候你就可以删除临时文件了。这儿一般需要调用Save方法来维持状态。
Public Property State() As DownloadState
Get
Return m_nState
End Get
Set(ByVal nState As DownloadState)
m_nState = nState
' 可选操作:这个时候你可以自动地删除文件。
' 如果状态被设置为Finished ,你就再也不需要这个文件了。
' If nState =DownloadState.fsDownloadFinished Then
' Clear()
' Else
' Save()
' End If
Save()
End Set
End Property
在文件状态发生改变的任何时候ZipFileHandler都应该调用Save方法,保存文件的状态,这样在以后才能显示给用户。你还可以用它来保存你自己建立的EntityTag。请不要把文件的状态和EntityTag值保存在Application、Session或Cache中--你必须跨越所有的这些这些对象的生命周期来保存信息。
Private Sub Save()
' 把该文件下载的状态保存到数据库或XML文件中。
' 当然,如果你并没有动态地建立文件,就不需要保存这个状态。
End Sub
前面提到,示例代码只处理一个已有的文件(download.zip),但是你可以进一步增强这个程序,根据需要建立被请求的文件。
测试示例代码的时候,你的本地系统或LAN可能太快了,以至于无法中断下载过程,因此我推荐你使用慢速LAN连接(在IIS中减少站点的带宽是一种模拟的方法)或者把服务器放到互联网上。
在客户端上下载文件仍然很艰难。ISP操作的不对的或配置错误的Web缓冲服务器都可能使大文件下载过程失败,包括下载状况恶化或早期对话终结。如果文件大小超过了255MB,你就应该鼓励顾客使用第三方下载管理软件,尽管某些最新的浏览器内建了基本的下载管理器。
如果你希望进一步扩展示例代码,查阅一下HTTP规范是有益的。你可以为下载建立MD5校验值,使用Content-MD5头信息添加它们,提供一种验证下载文件完整性的途径。示例代码除了GET和HEAD之外没有涉及到其它的HTTP方法。
做人要厚道,请注明转自chinazhan中国站长(www.ChinaZhan.com)。
