Загрузка файлов по FTP размером более 2 ГБ (VB.net)

Отсутствуют последние несколько байтов, и файл поврежден - щедрость

Теперь я добавил награду для решения этой проблемы. Я изменил целые типы на int64, что, кажется, решило часть проблемы, но теперь, когда он заканчивает загрузку, он иногда пропускает последние 1-5 байтов, что, в свою очередь, портит файл, поэтому его нельзя разархивировать. Есть ли другой способ закрыть поток, чтобы обеспечить полную загрузку файлов и избежать повреждения? С тех пор я пробовал этот простой код, но возникает та же проблема.

Imports System.ComponentModel
Imports System.Net

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Control.CheckForIllegalCrossThreadCalls = False
    End Sub
    Dim WithEvents WC As New WebClient
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        WC.DownloadFileAsync(New Uri("ftp://dmr-ftp-user:[email protected]/ESStatistikListeModtag/ESStatistikListeModtag-20160327-094743.zip"), "C:\XML\ESStatistikListeModtag-20160327-094743.zip.zip")
    End Sub
    Private Sub WC_DownloadProgressChanged(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs) Handles WC.DownloadProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
        If e.ProgressPercentage = 100 Then
            MsgBox("File download - 100%") 'This message box does trigger once the download is complete, but file is still corrupted.
        End If
    End Sub

    Private Sub WC_DownloadFileCompleted(sender As Object, e As AsyncCompletedEventArgs) Handles WC.DownloadFileCompleted
        MsgBox("Complete") ' This message box doesn't trigger!
    End Sub
End Class

СТАРЫЙ ВОПРОС:

Я пытаюсь загрузить zip-файл с FTP-сервера с помощью моего приложения vb.net. Мой текущий исходный код размещен ниже. Это отлично работает для небольших файлов, но когда я превышаю ограничение в 2 ГБ, я получаю следующее исключение:

"Arithmetic operation resulted in an overflow"

Это файл размером около 2,5 ГБ, который немного увеличивается с каждым слабым местом (около 20 МБ), поэтому мне нужно решение, которое может обрабатывать большие файлы, надеюсь, без ограничений. В конце концов я хотел бы также разархивировать файл с программой, поэтому, если у вас есть какие-либо идеи, как это сделать, вы также можете опубликовать это. Спасибо!

 Private Sub Download(ByVal filePath As String, ByVal fileName As String)
        FTPSettings.IP = "0.0.0.0"
        FTPSettings.UserID = "ftp-user"
        FTPSettings.Password = "ftp-pass"
        Dim reqFTP As FtpWebRequest = Nothing
        Dim ftpStream As Stream = Nothing
        Try
            Dim outputStream As New FileStream(filePath + "\" + fileName, FileMode.Create)
            reqFTP = DirectCast(FtpWebRequest.Create(New Uri("ftp://" + FTPSettings.IP + "/" + fileName)), FtpWebRequest)
            reqFTP.Method = WebRequestMethods.Ftp.DownloadFile
            reqFTP.UseBinary = True
            reqFTP.Credentials = New NetworkCredential(FTPSettings.UserID, FTPSettings.Password)
            Dim response As FtpWebResponse = DirectCast(reqFTP.GetResponse(), FtpWebResponse)
            ftpStream = response.GetResponseStream()
            Dim cl As Long = response.ContentLength
            Dim bufferSize As Integer = 2048
            Dim readCount As Int64
            Dim buffer As Byte() = New Byte(bufferSize - 1) {}
            Dim size As Int64

            readCount = ftpStream.Read(buffer, 0, bufferSize)
            While readCount > 0
                outputStream.Write(buffer, 0, readCount)
                readCount = ftpStream.Read(buffer, 0, bufferSize)

                If readCount = bufferSize Then
                    size += readCount
                    Label1.Text = size
                    Label1.Refresh()
                End If

              End While

            ftpStream.Close()
            outputStream.Close()
            response.Close()
        Catch ex As Exception
            MsgBox(ex.Message)
            If ftpStream IsNot Nothing Then
                ftpStream.Close()
                ftpStream.Dispose()
            End If
            Throw New Exception(ex.Message.ToString())
        End Try
    End Sub
    Public NotInheritable Class FTPSettings
        Private Sub New()
        End Sub
        Public Shared Property IP() As String
            Get
                Return m_IP
            End Get
            Set(ByVal value As String)
                m_IP = value
            End Set
        End Property
        Private Shared m_IP As String
        Public Shared Property UserID() As String
            Get
                Return m_UserID
            End Get
            Set(ByVal value As String)
                m_UserID = value
            End Set
        End Property
        Private Shared m_UserID As String
        Public Shared Property Password() As String
            Get
                Return m_Password
            End Get
            Set(ByVal value As String)
                m_Password = value
            End Set
        End Property
        Private Shared m_Password As String
    End Class
End Class

person TobiasKnudsen    schedule 09.04.2016    source источник
comment
Вы не сказали нам, где это происходит, поэтому я предполагаю, что это size += readCount изменить размер на Int64, а также включить Option Strict.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 09.04.2016
comment
Спасибо, я только что успешно скачал весь файл! Спасибо!   -  person TobiasKnudsen    schedule 09.04.2016
comment
На самом деле zip-файл поврежден. У меня больше нет проблемы с ограничением в 2 ГБ, но я получаю новое исключение, когда файл вот-вот будет готов: базовое соединение было закрыто: при получении произошла непредвиденная ошибка.   -  person TobiasKnudsen    schedule 09.04.2016
comment
Вот бесплатная zip-библиотека .NET с открытым исходным кодом, которую вы можете использовать для архивации/распаковки файлов dotnetzip.codeplex.com   -  person Chase Rocker    schedule 09.04.2016
comment
Особенно при применении награды вы должны обновить вопрос с проблемой и где. Предыдущие комментарии указывают на то, что исходная проблема (в сообщении) решена, и теперь вы пытаетесь решить новую проблему. Если кто-то опубликует ответ change size to an Int64, вы застрянете с этим ответом и потеряете репутацию.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 25.06.2016
comment
@Plutonix, спасибо! Я обновил проблему выше!   -  person TobiasKnudsen    schedule 25.06.2016
comment
Во-первых, избавьтесь от Control.CheckForIllegalCrossThreadCalls = False и правильно маршалируйте любой доступ пользовательского интерфейса к потоку пользовательского интерфейса. Вы заявляете, что файл поврежден, но уверены ли вы, что используемая вами утилита ZIP может обрабатывать ZIP-файл такого размера? см.: ZIP-файл — Ограничения.   -  person TnTinMn    schedule 25.06.2016
comment
Дублировать нельзя. Оба события срабатывают нормально, результирующий файл можно открыть и распаковать нормально. Спорадические ошибки обычно сложнее всего диагностировать, но, поскольку DL этого монстра занимает почти час, я не буду пытаться снова. Используйте Console.WriteLine()/Debug.Print для отладки кода. MsgBox является модальным и может вызывать проблемы с асинхронным методом.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 25.06.2016
comment
@TnTinMn я использую WinRAR, чтобы открыть файл. Когда я загружаю файл с помощью стандартного браузера или ftp-клиента, такого как totalcommander, я получаю файл и могу его нормально извлечь.   -  person TobiasKnudsen    schedule 26.06.2016
comment
@Plutonix да, вот почему мне потребовалось так много времени, чтобы решить эту проблему. Каждый раз, когда я что-то меняю, мне приходится ждать еще 20-30 минут, пока файл загрузится. Кажется, это работает для небольших zip-файлов, но может быть это как-то связано с ограничением в 2 ГБ?   -  person TobiasKnudsen    schedule 26.06.2016
comment
Это двойное .zip "C:\XML\ESStatistikListeModtag-20160327-094743.zip.zip" сделано намеренно?   -  person A Friend    schedule 27.06.2016
comment
Использование такого блока Try...Catch вызывает только головную боль. Он предназначен не для блоков кода, а для отдельных строк, когда вы знаете (или, по крайней мере, подозреваете), что может пойти не так и как с этим бороться. Теперь всякий раз, когда возникает исключение, вы теряетесь. Освободите блок Try...Catch и запустите свой код с помощью отладчика, чтобы увидеть (первую) точку отказа.   -  person Bozhidar Stoyneff    schedule 28.06.2016
comment
... С другой стороны, блоки Using предназначены для одноразовых объектов независимо от того, появляются ли они в блоках Try.Catch. Просто объявите свои одноразовые объекты в операторе Using (один или несколько). Объекты, объявленные таким образом, гарантированно будут удалены в конце используемого блока, несмотря ни на что.   -  person Bozhidar Stoyneff    schedule 28.06.2016
comment
Две вещи, которые вы можете попробовать, могут помочь. FtpWebRequest имеет свойство KeepAlive, для которого можно установить значение false, чтобы убедиться, что соединение закрыто. Затем с вызовом Flush для ftpStream и outputStream перед вызовом Close.   -  person Ryan Roos    schedule 28.06.2016


Ответы (1)


У меня были подобные проблемы с WebClient раньше, особенно при использовании его с оператором WithEvents. Посмотрите, решит ли проблему переписывание вашего кода следующим образом:

Imports System.ComponentModel
Imports System.Net

Public Class Form1
    Private wc As New WebClient()

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        wc = New WebClient()

        AddHandler wc.DownloadProgressChanged, Sub(s As Object, ByVal e As DownloadProgressChangedEventArgs)
                                                Me.Invoke(New MethodInvoker(Sub() ProgressBar1.Value = e.ProgressPercentage))
                                            End Sub

        AddHandler wc.DownloadFileCompleted, Sub(s As Object, e As ComponentModel.AsyncCompletedEventArgs)
                                                MsgBox("Complete")
                                            End Sub
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        wc.DownloadFileAsync(New Uri("ftp://dmr-ftp-user:[email protected]/ESStatistikListeModtag/ESStatistikListeModtag-20160327-094743.zip"), "C:\XML\ESStatistikListeModtag-20160327-094743.zip.zip")
    End Sub
End Class
person xfx    schedule 30.06.2016