Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - Copia file
Forum - C# / VB.NET - Copia file - Pagina 3

Pagine: [ 1 2 3 4 5 ] Precedente | Prossimo
Avatar
Thejuster (Admin)
Guru^2


Messaggi: 2302
Iscritto: 04/05/2008

Segnala al moderatore
Postato alle 18:12
Giovedì, 22/06/2017
Testo quotato

Postato originariamente da lupetto77:

Ho fatto altri progressi risolvendo i tre problemi elencati sopra, in questo modo:
Codice sorgente - presumibilmente C#

  1. string[] files;
  2.         FileInfo fi;
  3.         long bytesTotali;
  4.  
  5.         private void GetFiles(string path)
  6.         {
  7.             files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
  8.  
  9.             foreach (string f in files)
  10.             {
  11.                 FileInfo fi = new FileInfo(f);
  12.                 bytesTotali += fi.Length;
  13.             }
  14.  
  15.             progressBar1.Value = 0;
  16.             progressBar1.Maximum = (int)bytesTotali;
  17.         }
  18.  
  19.         private async Task CopyFilesAsync(FileStream Source, FileStream Destination)
  20.         {
  21.             byte[] buffer = new byte[1024 * 1024];
  22.             int numRead;
  23.             while ((numRead = await Source.ReadAsync(buffer, 0, buffer.Length)) != 0)
  24.             {
  25.                 int percentuale = Convert.ToInt32(((numRead / bytesTotali) * 100));
  26.                 backgroundWorker1.ReportProgress(percentuale);
  27.                 await Destination.WriteAsync(buffer, 0, numRead);
  28.             }
  29.         }
  30.  
  31.         private void button1_Click(object sender, EventArgs e)
  32.         {
  33.             backgroundWorker1.RunWorkerAsync();
  34.         }
  35.  
  36.         private async void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
  37.         {
  38.             string UserDirectory = @"C:\Users\nomeUtente\Desktop\1";
  39.             string targetDir = @"C:\Users\nomeUtente\Desktop\2";
  40.  
  41.             GetFiles(UserDirectory);
  42.  
  43.             string newDir = "";
  44.             foreach (string file in files)
  45.             {
  46.                 fi = new FileInfo(file);
  47.                 newDir = targetDir + "\\" + fi.DirectoryName.Substring(UserDirectory.Length) + "\\";
  48.                 if (!Directory.Exists(newDir))
  49.                     Directory.CreateDirectory(newDir);
  50.  
  51.                 using (FileStream SourceReader = File.Open(file, FileMode.Open))
  52.                 {
  53.                     using (FileStream DestinationWriter = File.Create(newDir + fi.Name))
  54.                     {
  55.                         await CopyFilesAsync(SourceReader, DestinationWriter);
  56.                     }
  57.                 }
  58.             }
  59.  
  60.             MessageBox.Show("Copia effettuata con successo!");
  61.         }
  62.  
  63.         private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
  64.         {
  65.             progressBar1.Value = e.ProgressPercentage;
  66.         }



Ma è rimasto un solo problema, quello della progressBar, mi da la seguente eccezione:
Codice sorgente - presumibilmente Plain Text

  1. System.InvalidOperationException: 'Operazione cross-thread non valida: è stato eseguito l'accesso al controllo 'progressBar1' da un thread diverso da quello da cui è stata eseguita la creazione.'



Se si decommentano le seguenti righe funziona ma senza progressBar ovviamente:
Codice sorgente - presumibilmente Plain Text

  1. Nel metodo GetFiles
  2. progressBar1.Value = 0;
  3. progressBar1.Maximum = (int)bytesTotali;



Codice sorgente - presumibilmente C# / VB.NET

  1. Nella funzione CopyFilesAsync()
  2. int percentuale = Convert.ToInt32(((numRead / bytesTotali) * 100));
  3. backgroundWorker1.ReportProgress(percentuale);



Spero che qualcuno mi possa dare una mano, ci ho provato e riprovato ma niente :grr:
Continuerò a provare ma la vedo dura questa volta, spero in un aiuto da voi esperti.





Ovviamente, non puoi riportare il valore alla progressbar da un thread o task diverso da quello dove
viene inizializzato il controllo.

Ma si può semplicemente ovviare a questo problema utilizzando un delegato.


Codice sorgente - presumibilmente C# / VB.NET

  1. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
  2.         {
  3.  
  4.                 Invoke((Action)delegate
  5.                 {
  6.                     progressBar1.Value = e.ProgressPercentage;
  7.  
  8.                 });
  9.         }



Prova così


https://mire.forumfree.it/ - Mire Engine
C# UI Designer
PM Quote
Avatar
lupetto77 (Normal User)
Pro


Messaggi: 75
Iscritto: 04/12/2011

Segnala al moderatore
Postato alle 18:23
Giovedì, 22/06/2017
Ho provato come mi hai detto tu ma stessa eccezione, non vorrei che ho sbagliato i calcoli per la percentuale, se puoi controllare tu per favore.

Grazie per la risposta e l'aiuto.

Ultima modifica effettuata da lupetto77 il 22/06/2017 alle 19:16
PM Quote
Avatar
Thejuster (Admin)
Guru^2


Messaggi: 2302
Iscritto: 04/05/2008

Segnala al moderatore
Postato alle 19:33
Giovedì, 22/06/2017
Se hai di nuovo questo messaggio:


System.InvalidOperationException: 'Operazione cross-thread non valida: è stato eseguito l'accesso al controllo 'progressBar1' da un thread diverso da quello da cui è stata eseguita la creazione.'


Per prima cosa, Utilizza il debugger.
Senza di quello non si và da nessuna parte ;)


1° Inserisci un breakpoint prima del metodo invoke.
Se fino a li, non ti crasha nulla significa che c'è qualche problema in quel metodo.

2° Inserisci un breakpoint subito dopo la funzione invoke.
Se passa il metodo, significa che il problema è altrove.

quindi dovrai cercare di capire seguendo il debugger dove sta il problema.
intercettarlo è risolverlo.
perché ho provato da me, il metodo invoke serve proprio per poter manipolare controlli al di fuori
del thread principale.

Quindi se sbaglio io, credo che sbaglieranno tantissime persone.
Ma non si può dare nulla di scontato sopratutto nella programmazione.

Quindi prova a fare in questo modo.
Se nemmeno funziona, cerchiamo di capire dove sta il problema


https://mire.forumfree.it/ - Mire Engine
C# UI Designer
PM Quote
Avatar
lupetto77 (Normal User)
Pro


Messaggi: 75
Iscritto: 04/12/2011

Segnala al moderatore
Postato alle 23:14
Giovedì, 22/06/2017
Ciao Thejuster ho provato a mettere vari breakpoint
Il primo problema è capitato a questa linea:
Codice sorgente - presumibilmente Plain Text

  1. progressBar1.Maximum = (int)bytesTotali;


che mostra la stessa eccezione.
Ho provato anche li ad inserire il delegato cosi:
Codice sorgente - presumibilmente Plain Text

  1. this.Invoke((MethodInvoker)delegate
  2. {
  3.     progressBar1.Value = 0;
  4.     progressBar1.Maximum = (int)bytesTotali;
  5. });


se riprovo va avanti.

Poi arriva a questa riga di codice:
Codice sorgente - presumibilmente Plain Text

  1. backgroundWorker1.ReportProgress(percentuale);


e mostra questa eccezione:
System.InvalidOperationException: 'OperationCompleted è già stato chiamato sull'operazione. Non sono consentite ulteriori chiamate.'

anche se la uso cosi:
Codice sorgente - presumibilmente C# / VB.NET

  1. this.Invoke((MethodInvoker)delegate
  2. {
  3.    int percentuale = Convert.ToInt32(((numRead / bytesTotali) * 100));
  4.    backgroundWorker1.ReportProgress(percentuale);
  5. });


e mostra sempre questa eccezione:
System.InvalidOperationException: 'OperationCompleted è già stato chiamato sull'operazione. Non sono consentite ulteriori chiamate.'

il problema si trova sempre in queste righe:
Codice sorgente - presumibilmente C# / VB.NET

  1. progressBar1.Maximum = (int)bytesTotali;
  2. int percentuale = Convert.ToInt32(((numRead / bytesTotali) * 100))
  3.  backgroundWorker1.ReportProgress(percentuale);



però non capisco il motivo.

Ultima modifica effettuata da lupetto77 il 22/06/2017 alle 23:15
PM Quote
Avatar
Thejuster (Admin)
Guru^2


Messaggi: 2302
Iscritto: 04/05/2008

Segnala al moderatore
Postato alle 8:30
Venerdì, 23/06/2017
Il problema è sicuramente il calcolo.

Il messaggio è chiaro


Testo quotato


System.InvalidOperationException: 'OperationCompleted è già stato chiamato sull'operazione. Non sono consentite ulteriori chiamate.'




Questo messaggio viene scaturito quando si tenta di fare un Report Progress quando il suo valore massimo è gia stato raggiunto.

Oppure quando il processo è già stato terminato.


ora non mi è molto chiaro il tuo calcolo o la grandezza del file
ma potresti provare a fare


valore =  numRead * 100 / bytesTotali


Ultima modifica effettuata da Thejuster il 23/06/2017 alle 8:41


https://mire.forumfree.it/ - Mire Engine
C# UI Designer
PM Quote
Avatar
lupetto77 (Normal User)
Pro


Messaggi: 75
Iscritto: 04/12/2011

Segnala al moderatore
Postato alle 18:41
Venerdì, 23/06/2017
Valori restituiti mettendo i breakpoint.

Codice sorgente - presumibilmente C# / VB.NET

  1. long byteTotali = 5490855026; //Il valore di byteTotali



Codice sorgente - presumibilmente C# / VB.NET

  1. progressBar1.Maximum = (int)byteTotali; //Il valore convertito in int ora è: 1195887730



Codice sorgente - presumibilmente C# / VB.NET

  1. int percentuale = Convert.ToInt32(((numRead * 100) / (int)bytesTotali));


//Il valore della percentuale è: 0
//Quindi ReportProgress invia zero e crea l'eccezione

Ho provato anche cosi:
Codice sorgente - presumibilmente C# / VB.NET

  1. int percentuale = Convert.ToInt32(((numRead * 100) / progressBar1.Maximum));


...
Codice sorgente - presumibilmente C# / VB.NET

  1. int percentuale = Convert.ToInt32((numRead / (int)bytesTotali) * 100);



Mi sto rincog******do, non ci sto capendo più nulla. :grr:

Ultima modifica effettuata da lupetto77 il 23/06/2017 alle 18:43
PM Quote
Avatar
Thejuster (Admin)
Guru^2


Messaggi: 2302
Iscritto: 04/05/2008

Segnala al moderatore
Postato alle 10:37
Sabato, 24/06/2017


https://mire.forumfree.it/ - Mire Engine
C# UI Designer
PM Quote
Avatar
lupetto77 (Normal User)
Pro


Messaggi: 75
Iscritto: 04/12/2011

Segnala al moderatore
Postato alle 18:38
Sabato, 24/06/2017
Thejuster grazie davvero infinitamente per il tuo aiuto e pazienza.

Se imposto la progressBar.Maximum cosi:
Codice sorgente - presumibilmente Plain Text

  1. progressBar1.Maximum = (int)totalBytes;


o cosi:
Codice sorgente - presumibilmente Plain Text

  1. progressBar1.Maximum = 100;



e richiamandolo la funzione cosi:
Codice sorgente - presumibilmente Plain Text

  1. await CopyFiles.CopyToWithProgressAsync(SourceReader, DestinationWriter, 4096, progress => progressBar1.Value = (int)CopyFiles.total * 100 / (int)totalBytes);



Come avvio mostra subito l'eccezione:
Codice sorgente - presumibilmente Plain Text

  1. System.Reflection.TargetInvocationException: 'Eccezione generata dalla destinazione di una chiamata.'
  2.  
  3. Eccezione interna
  4. ArgumentOutOfRangeException: '-1' non è un valore valido per 'Value'. 'Value' deve essere compreso tra 'minimum' e 'maximum'.




Poi ho fatto quest'altra prova:
Se imposto cosi la progressBar:
Codice sorgente - presumibilmente Plain Text

  1. progressBar1.Maximum = (int)totalBytes;



e richiamandolo la funzione cosi:
Codice sorgente - presumibilmente Plain Text

  1. await CopyFiles.CopyToWithProgressAsync(SourceReader, DestinationWriter, 4096, progress => progressBar1.Value = (int)CopyFiles.total);



La progressBar sembra funzionare ma arrivata alla fine
Mostra l'eccezione:
Codice sorgente - presumibilmente Plain Text

  1. System.Reflection.TargetInvocationException: 'Eccezione generata dalla destinazione di una chiamata.'
  2.  
  3. Eccezione interna
  4. ArgumentOutOfRangeException: '1195757568' non è un valore valido per 'Value'. 'Value' deve essere compreso tra 'minimum' e 'maximum'.



se la progressBar la imposto cosi:
Codice sorgente - presumibilmente Plain Text

  1. progressBar1.Maximum = 100;



Come avvio mostra subito l'eccezione:
Codice sorgente - presumibilmente Plain Text

  1. System.Reflection.TargetInvocationException: 'Eccezione generata dalla destinazione di una chiamata.'
  2.  
  3. Eccezione interna
  4. ArgumentOutOfRangeException: '4096' non è un valore valido per 'Value'. 'Value' deve essere compreso tra 'minimum' e 'maximum'.



Non so se sbaglio a passare gli argomenti, ti mostro il codice:
Ho creato una classe statica CopyFiles con il seguente codice:
Codice sorgente - presumibilmente C++

  1. static public long total { get; set; }
  2.  
  3.         public static async Task CopyToWithProgressAsync(this Stream source, Stream destination, int bufferSize = 4096, Action<long> progress = null)
  4.         {
  5.             var buffer = new byte[bufferSize];
  6.             //var total = 0L;
  7.             total = 0L;
  8.             int amtRead;
  9.             do
  10.             {
  11.                 amtRead = 0;
  12.                 while (amtRead < bufferSize)
  13.                 {
  14.                     var numBytes = await source.ReadAsync(buffer, amtRead, bufferSize - amtRead);
  15.                     if (numBytes == 0)
  16.                     {
  17.                         break;
  18.                     }
  19.                     amtRead += numBytes;
  20.                 }
  21.                 total += amtRead;
  22.                 await destination.WriteAsync(buffer, 0, amtRead);
  23.                 if (progress != null)
  24.                 {
  25.                     progress(total);
  26.                 }
  27.             } while (amtRead == bufferSize);
  28.         }



Nella form principale il codice è questo:
Codice sorgente - presumibilmente C#

  1. string source;
  2. string destination;
  3. string[] files;
  4. long totalBytes;
  5. FileInfo fi;
  6.  
  7. private void GetFiles(string path)
  8.         {
  9.             files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
  10.             foreach (string file in files)
  11.             {
  12.                 fi = new FileInfo(file);
  13.                 totalBytes = fi.Length;
  14.             }
  15.  
  16.             progressBar1.Maximum = (int)totalBytes;
  17.         }
  18.  
  19. private async void btnCopy_Click(object sender, EventArgs e)
  20.         {
  21.             string newDir = "";
  22.             foreach (string file in files)
  23.             {
  24.                 fi = new FileInfo(file);
  25.                 newDir = destination + "\\" + fi.DirectoryName.Substring(source.Length) + "\\";
  26.                 if (!Directory.Exists(newDir))
  27.                     Directory.CreateDirectory(newDir);
  28.  
  29.                 using (FileStream SourceReader = File.Open(file, FileMode.Open))
  30.                 {
  31.                     using (FileStream DestinationWriter = File.Create(newDir + fi.Name))
  32.                     {
  33.                         //await CopyFiles.CopyToWithProgressAsync(SourceReader, DestinationWriter, 4096, progress => progressBar1.Value = (int)CopyFiles.total * 100 / (int)totalBytes);
  34.                         await CopyFiles.CopyToWithProgressAsync(SourceReader, DestinationWriter, 4096, progress => progressBar1.Value = (int)CopyFiles.total);
  35.                     }
  36.                 }
  37.             }
  38.  
  39.             MessageBox.Show("File copiati con successo!");
  40.         }


Ultima modifica effettuata da lupetto77 il 24/06/2017 alle 18:40
PM Quote
Pagine: [ 1 2 3 4 5 ] Precedente | Prossimo