获取 FTP 服务器上的文件大小并将其放在标签上

问题描述 投票:0回答:1

我正在尝试获取托管在

FTP
服务器上的文件的大小,并将其放入
Label
中,而“BackgroundWorker”在后台工作。

我使用“Try”来获取该值,但是该值在第一次尝试时就被捕获了。下载后,如果我按尝试再次获取它就可以了。

注意:第一次尝试时进度条也不起作用。

图片

我尝试过的:

Private Sub BWorkerD_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BWorkerD.DoWork

    Dim buffer(1023) As Byte
    Dim bytesIn As Integer
    Dim totalBytesIn As Integer
    Dim output As IO.Stream
    Dim flLength As Integer

    ''TRY TO GET FILE SIZE''

    Try
        Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePathD.Text), FtpWebRequest)
        FTPRequest.Credentials = New NetworkCredential(txtFTPUsernameD.Text, txtFTPPasswordD.Text)
        FTPRequest.Method = Net.WebRequestMethods.Ftp.GetFileSize

        flLength = CInt(FTPRequest.GetResponse.ContentLength)
        lblFileSizeD.Text = flLength & " bytes"

    Catch ex As Exception

    End Try

    Try
        Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePathD.Text), FtpWebRequest)
        FTPRequest.Credentials = New NetworkCredential(txtFTPUsernameD.Text, txtFTPPasswordD.Text)
        FTPRequest.Method = WebRequestMethods.Ftp.DownloadFile
        Dim stream As IO.Stream = FTPRequest.GetResponse.GetResponseStream
        Dim OutputFilePath As String = txtSavePathD.Text & "\" & IO.Path.GetFileName(txtFilePathD.Text)
        output = IO.File.Create(OutputFilePath)
        bytesIn = 1

        Do Until bytesIn < 1
            bytesIn = stream.Read(buffer, 0, 1024)
            If bytesIn > 0 Then
                output.Write(buffer, 0, bytesIn)
                totalBytesIn += bytesIn
                lblDownloadedBytesD.Text = totalBytesIn.ToString & " bytes"
                If flLength > 0 Then
                    Dim perc As Integer = (totalBytesIn / flLength) * 100
                    BWorkerD.ReportProgress(perc)
                End If
            End If
        Loop

        output.Close()
        stream.Close()

    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
End Sub

''UPDATE EVERY PROGRESS - DONT WORK ON FIRST TRY''

Private Sub BWorkerD_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BWorkerD.ProgressChanged

    pBarD.Value = e.ProgressPercentage
    lblPercentD.Text = e.ProgressPercentage & " %"
End Sub
vb.net winforms ftp progress-bar backgroundworker
1个回答
4
投票

主要问题(设置

Option Strict On
以查找更多):
您无法从 UI 线程之外的线程访问 UI 对象。

您收到的错误是:

跨线程操作无效:
Control

lblFileSizeD
访问自 除了创建它的线程之外的线程

然后,

lblDownloadedBytesD
出现同样的错误。

此外,您正在使用空处理程序来消耗错误消息:

Catch ex As Exception

End Try

这会使任何处理无效,因为没有。您只需让代码运行过去而不采取任何操作。处理程序的作用是处理错误,而不是让错误不受检查。

当您需要访问和更新某些 UI 组件属性时,请使用

BackGroundWorker
ReportProgress() 方法。此方法具有接受
Object
类型参数的重载。意思是,你可以给它喂任何东西。该对象将是 ReportProgress
ProgressChangedEventArgs
类中的 e.UserState 属性。

.RunWorkerAsync() 方法还接受 Object 参数。该对象将成为 BackgroundWorker.DoWork 事件的 e.Argument 属性。这为您实际传递给您的 BackGroundWorker

 的参数提供了一定的灵活性。

还有一个问题:Ftp Download程序不支持取消。运行时,用户无法停止它。

最后一个问题:如文档中所述,您永远不应该在 UI 线程(表单)的

BackGroundWorker

 事件中引用您实例化的 
DoWork
 对象。使用 
sender
 对象并将其转换为 
BackGroundWorker
 类。

在此示例中,所有 UI 引用都委托给一个 Class 对象,该对象通过

DoWork

 方法(使用 
RunWorkerAsync(Object)
 属性)传递给 
e.Argument
 事件。
Class 对象会使用进度详细信息进行更新,然后提供给
ReportProgress(Int32, Object)
 方法,该方法在原始同步上下文(UI 线程,其中调用 
RunWorkerAsync
 方法)中运行。
UI 可以安全地更新。不能发生跨线程操作。

还实现了取消方法。这允许中止下载过程并删除部分下载的文件(如果已创建)。

错误处理很少,但这是您需要与自己的工具集成的东西。

(我对 UI 控件使用了相同的名称,应该更容易测试。)

Imports System.ComponentModel Imports System.Globalization Imports System.IO Imports System.Net Imports System.Net.Security Imports System.Security.Cryptography.X509Certificates Public Class frmBGWorkerDownload Friend WithEvents BWorkerD As BackgroundWorker Public Sub New() InitializeComponent() BWorkerD = New BackgroundWorker() BWorkerD.WorkerReportsProgress = True BWorkerD.WorkerSupportsCancellation = True AddHandler BWorkerD.DoWork, AddressOf BWorkerD_DoWork AddHandler BWorkerD.ProgressChanged, AddressOf BWorkerD_ProgressChanged AddHandler BWorkerD.RunWorkerCompleted, AddressOf BWorkerD_RunWorkerCompleted BWorkerD.RunWorkerAsync(BGWorkerObj) End Sub Private Class BGWorkerObject Public Property UserName As String Public Property Password As String Public Property ResourceURI As String Public Property FilePath As String Public Property FileLength As Long Public Property DownloadedBytes As Long Public Property BytesToDownload As Long End Class Private Sub btnDownload_Click(sender As Object, e As EventArgs) Handles btnDownload.Click pBarD.Value = 0 Dim BGWorkerObj As BGWorkerObject = New BGWorkerObject With { .ResourceURI = txtFilePathD.Text, .FilePath = Path.Combine(txtSavePathD.Text, Path.GetFileName(txtFilePathD.Text)), .UserName = txtFTPUsernameD.Text, .Password = txtFTPPasswordD.Text } End Sub Private Sub BWorkerD_DoWork(sender As Object, e As DoWorkEventArgs) Dim BGW As BackgroundWorker = TryCast(sender, BackgroundWorker) Dim BGWorkerObj As BGWorkerObject = TryCast(e.Argument, BGWorkerObject) Dim FTPRequest As FtpWebRequest Dim BufferSize As Integer = 131072 ' Windows 7 / Windows 10 lacking maintenance ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 FTPRequest = DirectCast(WebRequest.Create(BGWorkerObj.ResourceURI), FtpWebRequest) FTPRequest.Credentials = New NetworkCredential(BGWorkerObj.UserName, BGWorkerObj.Password) 'FTPRequest.Method = WebRequestMethods.Ftp.GetFileSize '----------------------- UPDATE ------------------------ FTPRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails '--------------------- END UPDATE ------------------------ FTPRequest.EnableSsl = True '----------------------- UPDATE ------------------------ Using FtpResponse As WebResponse = FTPRequest.GetResponse, DirListStream As Stream = FtpResponse.GetResponseStream(), listReader As StreamReader = New StreamReader(DirListStream) While Not listReader.EndOfStream Dim DirContent As String = listReader.ReadLine() If DirContent.Contains(Path.GetFileNameWithoutExtension(BGWorkerObj.ResourceURI)) Then BGWorkerObj.FileLength = Convert.ToInt64(DirContent.Split(New String() {" "}, StringSplitOptions.RemoveEmptyEntries)(4)) BGW.ReportProgress(0, BGWorkerObj) Exit While End If End While End Using '----------------------- END UPDATE ------------------------ 'Using FtpResponse As WebResponse = FTPRequest.GetResponse ' BGWorkerObj.FileLength = Convert.ToInt64(FtpResponse.ContentLength) ' BGW.ReportProgress(0, BGWorkerObj) 'End Using If BGW.CancellationPending Then e.Cancel = True Try FTPRequest = CType(WebRequest.Create(BGWorkerObj.ResourceURI), FtpWebRequest) FTPRequest.EnableSsl = True FTPRequest.Credentials = New NetworkCredential(BGWorkerObj.UserName, BGWorkerObj.Password) FTPRequest.Method = WebRequestMethods.Ftp.DownloadFile Using Response As FtpWebResponse = DirectCast(FTPRequest.GetResponse, FtpWebResponse) If Response.StatusCode > 299 Then e.Result = 0 Throw New Exception("The Ftp Server rejected the request. StatusCode: " & Response.StatusCode.ToString(), New InvalidOperationException(Response.StatusCode.ToString())) Exit Sub End If Using stream = Response.GetResponseStream(), fileStream As FileStream = File.Create(BGWorkerObj.FilePath) Dim read As Integer Dim buffer As Byte() = New Byte(BufferSize - 1) {} Do read = stream.Read(buffer, 0, buffer.Length) fileStream.Write(buffer, 0, read) BGWorkerObj.DownloadedBytes += read BGWorkerObj.BytesToDownload = BGWorkerObj.FileLength - BGWorkerObj.DownloadedBytes If BGW.CancellationPending Then e.Cancel = True Exit Do Else BGW.ReportProgress(CInt((CSng(BGWorkerObj.DownloadedBytes) / BGWorkerObj.FileLength) * 100), BGWorkerObj) End If Loop While read > 0 End Using End Using Catch ex As Exception If e.Cancel = False Then Throw Finally If e.Cancel = True Then If File.Exists(BGWorkerObj.FilePath) Then File.Delete(BGWorkerObj.FilePath) End If End If End Try End Sub Private Sub BWorkerD_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) pBarD.Value = e.ProgressPercentage lblPercentD.Text = e.ProgressPercentage.ToString() & " %" If lblFileSizeD.Text.Length = 0 Then lblFileSizeD.Text = CType(e.UserState, BGWorkerObject).FileLength.ToString("N0", CultureInfo.CurrentUICulture.NumberFormat) End If lblDownloadedBytesD.Text = CType(e.UserState, BGWorkerObject).DownloadedBytes.ToString("N0", CultureInfo.CurrentUICulture.NumberFormat) If e.ProgressPercentage <= 15 Then lblDownloadedBytesD.ForeColor = Color.Red ElseIf e.ProgressPercentage <= 66 Then lblDownloadedBytesD.ForeColor = Color.Orange Else lblDownloadedBytesD.ForeColor = Color.LightGreen End If End Sub Private Sub BWorkerD_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Dim DownloadAborted As Boolean = False If e.Error IsNot Nothing Then DownloadAborted = True lblDownloadedBytesD.ForeColor = Color.Red lblDownloadedBytesD.Text = "Error!" ElseIf e.Cancelled Then DownloadAborted = True lblDownloadedBytesD.ForeColor = Color.Yellow lblDownloadedBytesD.Text = "Cancelled!" pBarD.Value = 0 lblPercentD.Text = "0%" Else lblDownloadedBytesD.ForeColor = Color.LightGreen lblDownloadedBytesD.Text = "Download completed" End If End Sub Private Sub btnAbortDownload_Click(sender As Object, e As EventArgs) Handles btnAbortDownload.Click BWorkerD.CancelAsync() End Sub End Class
所描述操作的视觉结果:

表单设计者的PasteBin+代码

© www.soinside.com 2019 - 2024. All rights reserved.