#眉標=Silverlight、Web Services、JavaScript #副標=Silverlight開發技術(15) #大標=利用Silverlight處理大檔案上傳與進度顯示 #作者=文/圖 董大偉 ============= 程式1 ''' ''' 每一個檔案上傳單位資訊 ''' ''' Public Class UploadFileResult Public TotalBytes As Long '檔案總大小 Public NextStartPosition As Long '下一次開始位置(傳給Client端的Silverlight應用程式用以決定讀取檔案的哪一段) Public SessionID As Long '唯一的SessionID,用以辨識呼叫端,確保Stateful的方法 Public NeedContinue As Boolean '是否還要繼續?(傳給Client端的Silverlight應用程式用以決定是否需要繼續,如果檔案已經傳遞完畢則為false) Public OriginalFileName As String '原始檔案名稱 Public ServerPathToSave As String '要儲存到伺服器的哪一個位置(預設為 "~/_UploadFileTempFolder") Public SavedFilePath As String '檔案在伺服器端的實際儲存位置 Public isErrorOccur As Boolean '是否發生錯誤 Public ErrorMessage As String '錯誤訊息 Public isWarningOccur As Boolean '是否發生警告 Public WarningMessage As String '警告訊息 Public SavedUrl As String '檔案實際儲存位置URL End Class ================ ============= 程式2 ''' ''' 檔案上傳服務 ''' ''' 唯一的SessionID值,由用戶端產生,表示一個獨立的檔案 ''' 檔案名稱 ''' 總Bytes數 ''' 開始位置 ''' 每次上傳大小 ''' 是否為最後一批Bytes ''' 要儲存在伺服器端的哪一個路徑 ''' ''' _ Public Function UploadFile(ByVal FileSessionId As Long, ByVal fileName As String, ByVal TotalBytes As Long, ByVal StartPosition As Long, ByVal Btyes() As Byte, ByVal lastBytes As Boolean, ByVal ServerPathToSave As String) As UploadFileResult '建立回傳物件 Dim ret As New UploadFileResult Try (...略…) '將資訊寫入EventLog(底下這行程式為測試用) (...略…) '先確認用戶端傳來的SessionID是否存在 If Session("_UploadFile" & FileSessionId) Is Nothing Then '若SessionID不存在,表示啟動新的上傳 '在記憶體中建立檔案暫存物件 Dim FileData(TotalBytes) As Byte '把上傳的Bytes填入 System.Array.Copy(Btyes, 0, FileData, 0, Btyes.Length) '把上傳的資料保留在Session中 Session("_UploadFile" & FileSessionId) = FileData '記錄檔案名稱與相關資訊 ret.OriginalFileName = fileName ret.ServerPathToSave = ServerPathToSave Else '若SessionID存在,表示是繼續先前未完成的上傳 '先從Session中取回先前上傳的內容 Dim FileData() As Byte = Session("_UploadFile" & FileSessionId) '把上傳的Bytes填入 System.Array.Copy(Btyes, 0, FileData, StartPosition, Btyes.Length) '把上傳的資料保留在Session中 Session("_UploadFile" & FileSessionId) = FileData '記錄檔案名稱與相關資訊 ret.OriginalFileName = fileName ret.ServerPathToSave = ServerPathToSave End If '如果是最後一批Bytes If lastBytes = True Then '取得資料 Dim FileData() As Byte = Session("_UploadFile" & FileSessionId) '決定檔案儲存路徑 If ServerPathToSave = "" Then '開發人員沒指定路徑, 可採用相對路徑 ServerPathToSave = Server.MapPath("_UploadFileTempFolder\") '相對路徑可以確定SavedRul ret.SavedUrl = "/_UploadFileTempFolder/" & fileName Else '如果開發人員有指定路徑 If Right(ServerPathToSave, 1) <> "\" Then ServerPathToSave = ServerPathToSave + "\" '絕對路徑無法確定SavedRul ret.SavedUrl = "" End If '如果資料夾不存在, 則嘗試開啟 If Not IO.Directory.Exists(ServerPathToSave) Then IO.Directory.CreateDirectory(ServerPathToSave) End If '把檔案寫入 IO.File.WriteAllBytes(ServerPathToSave & fileName, FileData) ret.SavedFilePath = ServerPathToSave & fileName '檔案儲存後,把記憶體清空 Session("_UploadFile" & FileSessionId) = Nothing End If '建立回傳資料 ret.TotalBytes = TotalBytes ret.NextStartPosition = StartPosition + Btyes.Length ret.SessionID = FileSessionId ret.NeedContinue = Not lastBytes Return ret Catch ex As Exception '發生任何錯誤則回傳錯誤訊息 ret.isErrorOccur = True ret.ErrorMessage = ex.Message Return ret End Try End Function ================ ============= 程式3 _ Public Function UploadFile(ByVal FileSessionId As Long, ByVal fileName As String, ByVal TotalBytes As Long, ByVal StartPosition As Long, ByVal Btyes() As Byte, ByVal lastBytes As Boolean, ByVal ServerPathToSave As String) As UploadFileResult ================ ============= 程式4 Sub UploadFile(ByVal ServerPathToSave As String) ' 建立openFileDialog1 Dim openFileDialog1 As System.Windows.Controls.OpenFileDialog = New System.Windows.Controls.OpenFileDialog ' 設定開啟選項 openFileDialog1.FilterIndex = 1 openFileDialog1.Multiselect = True ' 顯示DialogBox If (openFileDialog1.ShowDialog = True) Then Dim CancelUplaod As Boolean '點選檔案後的事件 RaiseEvent OnFileSelected(openFileDialog1.File.FullName, openFileDialog1.File.Length, CancelUplaod) '開發人員取消 If CancelUplaod = True Then Exit Sub End If '建立stream reader Dim fileStream As System.IO.Stream = openFileDialog1.File.OpenRead Dim i As Integer = 0 '重新定義陣列大小 If size > fileStream.Length Then size = fileStream.Length Else size = 1024 * 50 End If ReDim block(fileStream.Length) '讀取檔案區塊 ret = fileStream.Read(block, 0, fileStream.Length) Dim dat(size) As Byte '將要上傳的部分填入陣列 System.Array.Copy(block, 0, dat, 0, dat.Length) '隨機建立ID(可改用GUID) FileID = Microsoft.VisualBasic.Rnd(Now.Ticks) * 1000 + Now.Millisecond '呼叫遠端的服務上傳檔案 upload.UploadFileAsync(FileID, openFileDialog1.File.Name, block.Length, 0, dat, False, ServerPathToSave) fileStream.Close() End If End Sub ================ ============= 程式5 '非同步Web Services呼叫事件 Private Sub upload_UploadFileCompleted(ByVal sender As Object, ByVal e As FileUploadSvc.UploadFileCompletedEventArgs) Handles upload.UploadFileCompleted Dim dat() As Byte '如果發生警告 If e.Result.isWarningOccur = True Then RaiseEvent OnWarning(e.Result.WarningMessage) End If '如果發生錯誤 If e.Result.isErrorOccur = True Then MessageBox.Show(e.Result.ErrorMessage) Exit Sub End If '如果使用者取消 If CancelFlag = True Then MessageBox.Show("Cancel Upload") Exit Sub End If '顯示進度 RaiseEvent UploadProgress(e.Result.NextStartPosition, block.Length, e.Result.NextStartPosition / block.Length) '如果不需要繼續(已經是最後一批) If e.Result.NeedContinue = False Then RaiseEvent UploadCompleted(block.Length, e.Result.SavedFilePath, e.Result.SavedUrl) Exit Sub End If '繼續 If e.Result.NextStartPosition + size < block.Length Then '一個block ReDim dat(size) System.Array.Copy(block, e.Result.NextStartPosition, dat, 0, dat.Length) '上傳(注意參數LastBytes為False) upload.UploadFileAsync(e.Result.SessionID, e.Result.OriginalFileName, block.Length, e.Result.NextStartPosition, dat, False, e.Result.ServerPathToSave) Else '最後一批 ReDim dat(block.Length - e.Result.NextStartPosition - 1) System.Array.Copy(block, e.Result.NextStartPosition, dat, 0, dat.Length) '上傳後結束(注意參數LastBytes為True) upload.UploadFileAsync(e.Result.SessionID, e.Result.OriginalFileName, block.Length, e.Result.NextStartPosition, dat, True, e.Result.ServerPathToSave) End If End Sub ================ ============= 程式6 Dim WithEvents FileUploader As FileUploader '按下檔案上傳鈕 Private Sub Button_Load_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) '建立FileUploader物件 FileUploader = New FileUploader '執行上傳動作 FileUploader.UploadFile() End Sub ================ ============= 程式7 '當檔案被選取後... Private Sub FileUploader_OnFileSelected(ByVal fileName As String, ByVal FileSize As Long, ByRef CancelUpload As Boolean) Handles FileUploader.OnFileSelected '判斷檔案大小(現置大小) If FileSize > 1024 * 1024 * 15 Then '如果太大則取消 CancelUpload = True MessageBox.Show("請選擇較小的檔案. [" & fileName & "]檔案太大") End If End Sub '如果發生警告 Private Sub FileUploader_OnWarning(ByVal Message As String) Handles FileUploader.OnWarning Me.textBlock1.Text += "..." & Message End Sub '如果檔案上傳完畢 Private Sub FileUploader_UploadCompleted(ByVal totalBytes As Long, ByVal SavedFileFullPath As String, ByVal SavedUrl As String) Handles FileUploader.UploadCompleted MessageBox.Show(IO.Path.GetFileName(SavedFileFullPath) & "...done") Windows.Browser.HtmlPage.Window.Eval("addString(' " & IO.Path.GetFileName(SavedFileFullPath) & "
');") End Sub '如果檔案上傳進度改變 Private Sub FileUploader_UploadProgress(ByVal position As Double, ByVal totalBytes As Long, ByVal percentage As Single) Handles FileUploader.UploadProgress '顯示進度 Me.textBlock1.Text = position & "/" & totalBytes & " ... " & Format(percentage * 100, "0.00") & "% ID:" & FileUploader.FileID Me.Progress1.Value = percentage * 100 End Sub '取消正在進行中的上傳動作 Private Sub Button_Cancel_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) FileUploader.CancelFlag = True End Sub ================ ===<反灰>============= ================