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

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

问题描述

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

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.

图片

我尝试过的事情:

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

推荐答案

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

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:

跨线程操作无效:
从中访问控件lblFileSizeD
与其在其上创建的线程不同的线程

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

然后,与lblDownloadedBytesD相同的错误.

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.

当您需要访问和更新某些UI组件属性时,请使用BackGroundWorker "属性. microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.ComponentModel.ProgressChangedEventArgs); k(TargetFrameworkMoniker-.NETFramework%26f%3D255%26MSPPError%3D-2147217396& view = netframework-4.7.2"rel =" nofollow noreferrer> ProgressChangedEventArgs 类.

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.

e.Argument 属性/en-us/dotnet/api/system.componentmodel.backgroundworker.dowork?f1url=https%3A%2F%2Fmsdn.microsoft .com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.ComponentModel.BackgroundWorker.DoWork); k(TargetFrameworkMoniker-.NETFramework& view = netframework-4.7.2"rel =" nofollow noreferrer> BackgroundWorker.DoWork 事件.相对于您可以实际传递给BackGroundWorker的参数,这提供了一些灵活性.

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.

另一个问题:Ftp下载过程不支持取消.运行时,用户无法停止它.

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

最后一个问题:如文档中所报告,您永远不要在DoWork事件中引用在UI线程(窗体)中实例化的BackGroundWorker对象.使用sender对象并将其强制转换为BackGroundWorker类.

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.

在此示例中,所有UI引用都委派给一个Class对象,该对象通过RunWorkerAsync(Object)方法(使用e.Argument属性)传递给DoWork事件.
将使用进度详细信息更新Class对象,然后将其馈送到ReportProgress(Int32, Object)方法,该方法在原始的同步上下文(UI线程,调用RunWorkerAsync方法的位置)中运行.
用户界面可以安全更新.不能进行跨线程操作.

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.

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

(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:


表单设计者+代码的粘贴框.

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

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