2017-02-01 1 views
0

그래서 저는 지금 당분간이 문제를 해결하려고 노력해 왔습니다. 저는 아마추어 프로그래머입니다. 그래서 나는 항상 내가 뭘 잘못하고 있는지 알지 못합니다. 어쨌든WebClient 비동기 다운로더가 제대로 작동하지 않습니다.

, 내 최근 프로젝트의 전제 :

내 친구와 나는 정기적으로 마인 크래프트를 플레이,하지만 그들은 정말 밝은 아니에요, 우리가 개조를 얻고 그들에게 링크와 이것 저것을 보낼 항상 주위 아니에요 . 그래서 mods를 자동으로 풀다가 서버와 동기화되어 동시에 서버 데이터를 얻도록 프로그램 할 것이라고 생각했습니다.

저는 무료 FTP 호스트를 사용하고 있습니다.하지만 그 이유가 분명해질 것이라고 생각하지 않습니다.

기본적으로 전체 데이터 블록의 진행률을 표시하기 위해 진도 표시 줄과 이상적으로 레이블을 사용하고 싶습니다. 모든 개조는 함께 ... 1GB 이하 여야합니다.

  • 그것은 무작위로 선택됩니다이 주장하기 전에

  • 그것은 전체가 파일을 다운로드 할 수 있습니다 다운로드해야하는 파일을 다운로드하지 : 그러나, 나는 비동기 옵션에 대한 몇 가지 문제로 실행하는 것 완료 될

  • msgbox가 모든 항목의 다운로드를 완료했다는 메시지를 표시 할 때 프로그 레스 바가 50 % 찼을 수 있습니다. 진행 막대가 나는 BGworker의 싱크로를 실행할 때 진행,의 WebClient 동기 사용에 존재하지 않는의보고 이벤트로 인해 작동하지 않는 동안

그러나, 제대로 때마다 다운로드합니다. 그러나, 나는 기본적으로, 그래서 중요한의 종류 ....

인 진행률을보고 놓치게 :

  • 이 구현하는 더 나은 방법이 있나요?

준비가되기 전에 작업하기 위해 필요한 마지막 청크입니다. 그래서 실제로 시도하고 싶습니다. 어떤 도움을 주셔서 감사합니다!

편집 : 코드 업데이트 : 모든

Public Function GetDownloadSize(ByVal URL As String) As Long 
    Dim request As Net.FtpWebRequest = DirectCast(Net.WebRequest.Create(URL), Net.FtpWebRequest) 
    request.Method = Net.WebRequestMethods.Ftp.GetFileSize 
    request.Credentials = New Net.NetworkCredential(dl_user, dl_pass) 
    Dim response As Net.FtpWebResponse = DirectCast(request.GetResponse(), Net.FtpWebResponse) 
    Dim fileSize As Long = response.ContentLength 
    Return fileSize 
End Function 

Private Sub btn_sync_Click(sender As Object, e As EventArgs) Handles btn_sync.Click 
    Dim cont As DialogResult = MsgBox("Continue? " + (total_dl_size/1000).ToString("N0") + " KB remain to be downloaded.", MsgBoxStyle.YesNo, "CAUTION!") 
    If cont = DialogResult.No Then 
     tb_warnings.AppendText("-ERR: User declined to synchronize files. Restart the application to sync.") 
     tb_warnings.AppendText(ControlChars.NewLine) 
     Label3.BackColor = Color.Firebrick 
     Return 
    End If 
    btn_sync.Enabled = False 
    btn_scan.Enabled = false 
    tb_warnings.AppendText("-Deleting outmoded/unused mods. Protected mods will be kept.") 
    For Each i As fdata_obj In deleted_files 
     My.Computer.FileSystem.DeleteFile(mc_dir + "\mods\" + i.name) 
    Next 
    tb_warnings.AppendText(ControlChars.NewLine) 
    tb_warnings.AppendText("-Deleting mod subdirectories to ensure no conflicts.") 
    tb_warnings.AppendText(ControlChars.NewLine) 

    For Each d In My.Computer.FileSystem.GetDirectories(mc_dir + "\mods") 
     My.Computer.FileSystem.DeleteDirectory(d, FileIO.DeleteDirectoryOption.DeleteAllContents) 
    Next 

    initialize_download() 


End Sub 

Private Sub initialize_download() 

      Dim wc As New System.Net.WebClient() ' SORRY, ASSUME THIS IS A PUBLIC VAR SO IT CAN BE REFERENCED ACROSS ITS OTHER METHODS 
    AddHandler wc.DownloadProgressChanged, AddressOf OnDownloadProgressChanged 
    AddHandler wc, AddressOf OnFileDownloadCompleted 

    Dim usr As String = "randouser" 
    Dim pass As String = "randopass" 
    For Each s In (From dl As fdata_obj In new_files Select dl_server + "/mods/" + mods_dir + "/" + dl.name).ToList 
     downloads.Enqueue(s) 
    Next 
    wc.Credentials = New Net.NetworkCredential(usr, pass) 

     Dim urix As String = downloads.Dequeue 
     Try 
      wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix)) 
     Catch ex As Exception 
      MsgBox(ex.Message) 
      If tb_warnings.InvokeRequired = True Then 
       tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix) 
      Else 
       tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix)) 
       tb_warnings.AppendText(ControlChars.NewLine) 

      End If 
    end try 
End Sub 
Private Sub OnDownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs) 
    MsgBox("This is happening!") 
    total_dl = total_dl + e.BytesReceived 
    Dim percentage As Integer = (CType((total_dl/total_dl_size), Integer) * 100) 
    if percentage > 100 then 
     percentage = 100 
    endif 
    prog_update(percentage) 

End Sub 

delegate sub progress_update(byval prog as integer) 
' POTENTIAL ISSUES HERE??????? 
private sub prog_update(byval prog as integer) 
    if progressbar1.invokerequired then 
     progressbar1.invoke(new prog_update(addressof progress),prog) 
    else 
     progressbar1.value = prog 


Private Sub OnFileDownloadCompleted(ByVal sender As Net.WebClient, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) 

    If e.Cancelled Then 
     MsgBox(e.Cancelled) 
    ElseIf Not e.Error Is Nothing Then 
     MsgBox(e.Error.Message) 
    Else 
    if downloads.count > 0 then 
       Dim urix As String = downloads.Dequeue 
     Try 
      wc.DownloadFileasync(New Uri(urix), mc_dir + "\mods\" + IO.Path.GetFileName(urix)) 
     Catch ex As Exception 
      MsgBox(ex.Message) 
      If tb_warnings.InvokeRequired = True Then 
       tb_warnings.Invoke(New tb_updater(AddressOf tb_update), "-ERR: Could not download file: " + urix, urix) 
      Else 
       tb_warnings.AppendText("-ERR: Could not download file: " + IO.Path.GetFileName(urix)) 
       tb_warnings.AppendText(ControlChars.NewLine) 

      End If 
     End Try 
    End If 

End Sub 
+0

지난 번 확인한 'WebClient'는 정상적으로 작동했습니다. 귀하의 코드를 보여주십시오. –

+1

@VisualVincent # 1 : 멋진 사용자 이름, # 2 : 코드를 표시 할 수정 된 게시물.그 위임 함수 invoke 호출은 IDE의 이점을 가진이 코드를 다시 작성하고 형식을 매우 기억하지 않기 때문에 약간 꺼져있을 수 있습니다. 콜 템플릿이 원래 코드에서 맞는지 안심하십시오. –

+0

** 1 : ** 고마워;) ** 2 : ** 좋아, 컴퓨터를 시작한 다음 코드를 사용해 보도록하겠습니다. –

답변

1

첫째, 당신의 진행 표시 줄이 작동하지 않는 주된 이유는이 때문에입니다 : 코드는 첫 번째 total_dl/total_dl_size을 평가합니다

Dim percentage As Integer = (CType((total_dl/total_dl_size), Integer) * 100) 

, 결과가 0.34이면 결과를 0으로 변환 할 정수로 변환합니다 (정수는 소수가 없기 때문에 0.34는 0으로 반올림됩니다). 마지막으로 0을 100으로 곱합니다 (여전히 0이됩니다).
당신이해야만하는 것은 결과가 0-1 : (total_dl * 100)/total_dl_size 대신에 0-100이되도록 배당금을 100으로 먼저 곱하는 것입니다.스레드 안전 (호출) 난 항상 내가 만든이 extension method 사용에 관해서는

: Lambda expressions과 함께

Imports System.Runtime.CompilerServices 

Public Module Extensions 
    <Extension()> _ 
    Public Sub InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object()) 
     If Parameters Is Nothing OrElse _ 
      Parameters.Length = 0 Then Parameters = Nothing 'If Parameters is null or has a length of zero then no parameters should be passed. 
     If Control.InvokeRequired = True Then 
      Control.Invoke(Method, Parameters) 
     Else 
      Method.DynamicInvoke(Parameters) 
     End If 
    End Sub 
End Module 

(양호하게는 다른 파일에 넣어)

즉, (비주얼 스튜디오에 도입 2010), 크게 당신을위한 호출을 단순화합니다. 이 때문에 대신 사방 If InvokeRequired 패턴을 넣어이다 :

If Me.InvokeRequired Then 
    Me.Invoke(New Action(AddressOf SomeMethod), params) 
Else 
    SomeMethod() 
End If 

은 만 입력해야합니다

Me.InvokeIfRequired(AddressOf SomeMethod, params) 

및 확장 방법은 당신을위한 나머지를 할 것.

그리고 당신은 람다 표현식을 사용하는 경우 동적 방법을 만들 수 있습니다

Me.InvokeIfRequired(Sub() 
         Label1.Text = "Hello world!" 
         ProgressBar1.Value += 1 
        End Sub) 

지금, 당신의 코드.

나는 더 쉽게 처리 할 수 ​​있도록 코드를 좀 더 구분했습니다. 처음에는 DownloadFileCompleted 이벤트 핸들러에 다운로드 코드를 복사하여 붙여 넣는 대신 DownloadFile()이라는 좀 더 일반적인 메서드를 만들었습니다.

''' <summary> 
''' Downloads a file from the specified URL with the specified credentials. 
''' </summary> 
''' <param name="URL">The URL of the file.</param> 
''' <param name="Username">The username which to login with.</param> 
''' <param name="Password">The password which to login with.</param> 
''' <remarks></remarks> 
Private Sub DownloadFile(ByVal URL As String, ByVal Username As String, ByVal Password As String) 
    If wc.IsBusy = True Then Throw New Exception("A download is already ongoing!") 

    wc.Credentials = New NetworkCredential(dl_user, dl_pass) 
    total_dl_size = GetDownloadSize(URL, Username, Password) 

    Try 
     Dim FileName As String = Path.GetFileName(URL) 
     AppendWarning("Downloading " & FileName & "...") 
     wc.DownloadFileAsync(New Uri(URL), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), FileName)) 
    Catch ex As Exception 
     AppendWarning("-ERR: Could not download file: " & Path.GetFileName(URL)) 
    End Try 
End Sub 

는 나는 또한 경고 및 오류 메시지를 출력하기위한 일반적인 방법을했다시피 :

''' <summary> 
''' (Thread-safe) Appends a warning or status message to the "tb_warnings" text box. 
''' </summary> 
''' <param name="Text">The text to append.</param> 
''' <remarks></remarks> 
Private Sub AppendWarning(ByVal Text As String) 
    Me.InvokeIfRequired(Sub() tb_warnings.AppendText(Text & Environment.NewLine)) 
End Sub 

여기에 전체 코드의를, 나를 위해 제대로 작동 :

Private dl_user As String = "someusername" 
Private dl_pass As String = "somepassword" 

Private dl_urls As String() = {"URL1", "URL2"} 'Temporary. Use your own code. 
Private total_dl_size As Long = 0 
Private total_dl As Long = 0 

Dim WithEvents wc As New System.Net.WebClient() 
Dim downloads As New Queue(Of String) 

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 
    'Populate the download queue. 
    downloads.Enqueue(dl_urls(0)) 'Temporary. Use your own code here. 
    downloads.Enqueue(dl_urls(1)) 
End Sub 

'The download button. 
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 
    'Do your pre-download stuff here. 

    DownloadFile(downloads.Dequeue(), dl_user, dl_pass) 'Download the first file. 
End Sub 

''' <summary> 
''' Downloads a file from the specified URL with the specified credentials. 
''' </summary> 
''' <param name="URL">The URL of the file.</param> 
''' <param name="Username">The username which to login with.</param> 
''' <param name="Password">The password which to login with.</param> 
''' <remarks></remarks> 
Private Sub DownloadFile(ByVal URL As String, ByVal Username As String, ByVal Password As String) 
    If wc.IsBusy = True Then Throw New Exception("A download is already ongoing!") 

    wc.Credentials = New NetworkCredential(dl_user, dl_pass) 'Set the credentials. 
    total_dl_size = GetDownloadSize(URL, Username, Password) 'Get the size of the current file. 

    Try 
     Dim FileName As String = Path.GetFileName(URL) 'Get the current file's name. 
     AppendWarning("Downloading " & FileName & "...") 'Download notice. 
     wc.DownloadFileAsync(New Uri(URL), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), FileName)) 'Download the file to the desktop (use your own path here). 
    Catch ex As Exception 
     AppendWarning("-ERR: Could not download file: " & Path.GetFileName(URL)) 
    End Try 
End Sub 

''' <summary> 
''' (Thread-safe) Appends a warning or status message to the "tb_warnings" text box. 
''' </summary> 
''' <param name="Text">The text to append.</param> 
''' <remarks></remarks> 
Private Sub AppendWarning(ByVal Text As String) 
    Me.InvokeIfRequired(Sub() tb_warnings.AppendText(Text & Environment.NewLine)) 
End Sub 

Private Sub wc_DownloadProgressChanged(sender As Object, e As System.Net.DownloadProgressChangedEventArgs) Handles wc.DownloadProgressChanged 
    Me.InvokeIfRequired(Sub() 
          Dim Progress As Integer = CType(Math.Round((e.BytesReceived * 100)/total_dl_size), Integer) 
          If Progress > 100 Then Progress = 100 
          If Progress < 0 Then Progress = 0 
          ProgressBar1.Value = Progress 
         End Sub) 
End Sub 

Private Sub wc_DownloadFileCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs) Handles wc.DownloadFileCompleted 
    If e.Cancelled Then 
     MessageBox.Show(e.Cancelled) 

    ElseIf Not e.Error Is Nothing Then 
     MessageBox.Show(e.Error.Message) 

    Else 
     If downloads.Count > 0 Then 
      DownloadFile(downloads.Dequeue(), dl_user, dl_pass) 'Download the next file. 
     Else 
      AppendWarning("Download complete!") 
     End If 

    End If 
End Sub 

일부를 유의 사항 :

  • MsgBox() function은 순전히 이전 버전과의 호환성을 위해 존재합니다. 대신 .NET 표준 인 MessageBox.Show() method을 사용해야합니다.

  • 문자열 연결은 더하기 (+) 대신 앰퍼샌드 (&)를 사용해야합니다. See why.

  • 연결 경로는 항상 올바른 경로를 만들 수 있도록 Path.Combine()을 사용해야합니다. 무언가를 입력하면 예외가 발생합니다.

    사용법 :이 도움이

    Path.Combine(Path1, Path2, Path3, ...) 
    Path.Combine("C:\", "Foo") 'Results in: C:\Foo 
    Path.Combine("C:\", "Foo", "Bar", "Hello World.txt") 'Results in: C:\Foo\Bar\Hello World.txt 
    

희망!

+0

우수! 나는 집에 도착했을 때 이것을 구현하려고 노력할 것이다. 도와 줘서 고마워! 다운로드 부분을 제대로 작동시키는 것이 퍼즐의 마지막 부분이었습니다. 글쎄, 난 아직도 구성 파일을 생성하는 프로그램을 만들 필요가 있지만 그것은 사소한 일이다. 감사! –

+0

@smitty_werbermanjensen : 문제 없습니다. 그것이 효과가 있기를 바랍니다. –

+0

@smitty_werbermanjensen : 모든 코드를 포함하지 않았다는 것을 명심하십시오. 일부 부품을 다시 추가해야합니다. 주로'Form_Load' 이벤트에 채워지는 큐와'Button_Click' 이벤트에서 수행되어야하는 사전 다운로드 작업입니다. –

관련 문제