获取 FTP 服务器上的文件大小并将其放在标签上 [英] Get File Size on FTP Server and put it on a Label

查看:31
本文介绍了获取 FTP 服务器上的文件大小并将其放在标签上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试获取托管在 FTP 服务器上的文件的大小,并将其放入 Label 中,而 `BackgroundWorker 在后台工作.

我正在使用尝试"来获取该值,但是该值在第一次尝试时被捕获.下载后,如果我按再次尝试获取它,则它可以工作.

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

图片

我尝试过的:

Private Sub BWorkerD_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) 处理 BWorkerD.DoWorkDim 缓冲区(1023)作为字节Dim bytesIn 作为整数Dim totalBytesIn As Integer将输出调暗为 IO.Stream将 flLength 调暗为整数''尝试获取文件大小''尝试Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePathD.Text), FtpWebRequest)FTPRequest.Credentials = New NetworkCredential(txtFTPUsernameD.Text, txtFTPPasswordD.Text)FTPRequest.Method = Net.WebRequestMethods.Ftp.GetFileSizeflLength = CInt(FTPRequest.GetResponse.ContentLength)lblFileSizeD.Text = flLength &字节"Catch ex 作为例外结束尝试尝试Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePathD.Text), FtpWebRequest)FTPRequest.Credentials = New NetworkCredential(txtFTPUsernameD.Text, txtFTPPasswordD.Text)FTPRequest.Method = WebRequestMethods.Ftp.DownloadFileDim 流作为 IO.Stream = FTPRequest.GetResponse.GetResponseStreamDim OutputFilePath As String = txtSavePathD.Text &" &IO.Path.GetFileName(txtFilePathD.Text)输出 = IO.File.Create(OutputFilePath)字节输入 = 1直到 bytesIn <1bytesIn = stream.Read(buffer, 0, 1024)如果 bytesIn >0 那么output.Write(buffer, 0, bytesIn)总字节数 += 字节数lblDownloadedBytesD.Text = totalBytesIn.ToString &字节"如果 flLength >0 那么Dim perc As Integer = (totalBytesIn/flLength) * 100BWorkerD.ReportProgress(perc)万一万一环形输出.关闭()流.关闭()Catch ex 作为例外MessageBox.Show(ex.Message)结束尝试结束子''更新每个进度 - 不要在第一次尝试时工作''Private Sub BWorkerD_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) 处理 BWorkerD.ProgressChangedpBarD.Value = e.ProgressPercentagelblPercentD.Text = e.ProgressPercentage &%"结束子

解决方案

主要问题(设置Option Strict On以查找更多):
您无法从不同于 UI 线程的线程访问 UI 对象.
您收到的错误是:

<块引用>

跨线程操作无效:
控制lblFileSizeD访问自
创建它的线程以外的线程

然后,lblDownloadedBytesD 出现同样的错误.

此外,您正在使用带有

的空处理程序吃掉您的错误消息

Catch ex As Exception结束尝试

这使任何处理无效,因为没有.您只是让代码通过它而不采取任何行动.处理程序的作用是处理错误,而不是让它们不受检查.

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

表单设计器的 PasteBin + 代码.

I'm trying to get the size of a file that is hosted on a FTP Server and put it in a Label while the `BackgroundWorker works in the background.

I'm using "Try" to get the value, however the value is caught on the first attempt. After downloading, if I press to try to get it again then it works.

Note: The progress bar also does not work on the first try.

Image

What I have tried:

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

解决方案

The main problems (set Option Strict On to find more):
You can't access the UI objects from a thread different than the UI Thread.
The error you receive is:

Cross-thread operation not valid:
Control lblFileSizeD accessed from
a thread other than the thread it was created on

Then, the same error for lblDownloadedBytesD.

Also, you are eating up your Error messages using an empty handler with

Catch ex As Exception

End Try

This nullifies any handling, because theres's none. You are simply letting the code run past it without taking any action. The handlers are there to, well, handle the errors, not to let them go unchecked.

When you need to access and update some UI component property, use the BackGroundWorker ReportProgress() method. This method has an overload that accepts a parameter of type Object. Meaning, you can feed it anything. This Object will be the e.UserState property in the ReportProgress ProgressChangedEventArgs class.

The .RunWorkerAsync() method also accepts an Object parameter. This Object will become the e.Argument property of the BackgroundWorker.DoWork Event. This gives some flexibility in relation to the parameters you can actually pass to your BackGroundWorker.

One more problem: the Ftp Download procedure does not support cancellation. When run, a user can't stop it.

Last problem: as reported in the documentation, you should never reference the BackGroundWorker object you instantiated in your UI thread (the Form) in its DoWork event. Use the sender object and cast it to the BackGroundWorker class.

In this example, all the UI references are delegated to a Class object that is passed to the DoWork event through the RunWorkerAsync(Object) method (using the e.Argument property).
The Class object is updated with progress details and then fed to the ReportProgress(Int32, Object) method, which runs in the original Synchronization Context (the UI thread, where the RunWorkerAsync method is called).
The UI can be updated safely. No cross-thread operations can occur.

A cancellation method is also implemented. This allows to abort the download procedure and to delete a partial downloaded file, if one is created.

The error handling is minimal, but this is something you need to integrate with your own tools.

(I've used the same names for the UI Controls, it should be easier to test.)

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
    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
        }
        AddHandler BWorkerD.DoWork, AddressOf BWorkerD_DoWork
        AddHandler BWorkerD.ProgressChanged, AddressOf BWorkerD_ProgressChanged
        AddHandler BWorkerD.RunWorkerCompleted, AddressOf BWorkerD_RunWorkerCompleted
        BWorkerD.RunWorkerAsync(BGWorkerObj)

    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

        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
        ServicePointManager.ServerCertificateValidationCallback =
            Function(snd As Object, Cert As X509Certificate, Chain As X509Chain, Err As SslPolicyErrors)
                Return True
            End Function

        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

        RemoveHandler BWorkerD.DoWork, AddressOf BWorkerD_DoWork
        RemoveHandler BWorkerD.ProgressChanged, AddressOf BWorkerD_ProgressChanged
        RemoveHandler BWorkerD.RunWorkerCompleted, AddressOf BWorkerD_RunWorkerCompleted
    End Sub

    Private Sub btnAbortDownload_Click(sender As Object, e As EventArgs) Handles btnAbortDownload.Click
        BWorkerD.CancelAsync()
    End Sub
End Class

A visual result of the operation described:


A PasteBin of the Form's Designer + Code.

这篇关于获取 FTP 服务器上的文件大小并将其放在标签上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆