Forum - C# / VB.NET
- Copia file - Pagina 4
lupetto77 (Normal User)
Pro
Messaggi: 75
Iscritto: 04/12/2011
Ciao Thejuster ho provato a richiamare la funzione anche cosi:
Codice sorgente - presumibilmente Plain Text
await CopyFiles.CopyToWithProgressAsync(SourceReader, DestinationWriter, 4096, progress => progressBar1.Value = (int)progress);
e anche cosi:
Codice sorgente - presumibilmente Plain Text
await SourceReader.CopyToWithProgressAsync(DestinationWriter, 4096, amtCopied => progressBar1.Value = (int)amtCopied);
Ma sempre questa eccezione:
Codice sorgente - presumibilmente Plain Text
System.Reflection.TargetInvocationException: 'Eccezione generata dalla destinazione di una chiamata.'
Eccezione interna
ArgumentOutOfRangeException: '1195757568' non è un valore valido per 'Value'. 'Value' deve essere compreso tra 'minimum' e 'maximum'.
Thejuster (Admin )
Guru^2
Messaggi: 2310
Iscritto: 04/05/2008
L'errore parla chiaro
ArgumentOutOfRangeException
Out of range, c'è sempre un problema relativo al calcolo della prograssbar.
il valore supera quello impostato in massimo.
devi controllare bene il calcolo
lupetto77 (Normal User)
Pro
Messaggi: 75
Iscritto: 04/12/2011
Ciao Thejuster scusami se non ti ho risposto subito, ma stavo facendo delle prove per risolvere il problema.
Ti posto il codice che sembrava funzionare:
Codice sorgente - presumibilmente C#
private async void btnCopy_Click( object sender, EventArgs e)
{
//backgroundWorker1.RunWorkerAsync();
string newDir = "" ;
foreach ( string file in files)
{
newDir = txtDestination.Text + "\\ " + fi.DirectoryName .Substring ( txtSource.Text .Length ) + "\\ " ;
if ( ! Directory.Exists ( newDir) )
Directory.CreateDirectory ( newDir) ;
using ( Stream SourceReader = File.Open ( file, FileMode.Open ) )
{
using ( Stream DestinationWriter = File.Create ( newDir + fi.Name ) )
{
await SourceReader.CopyToWithProgressAsync ( DestinationWriter, 4096, amtCopied => progressBar1.Value = ( int ) Math.Round ( ( ( double ) amtCopied / ( double ) totalBytes * ( double ) 100) ) ) ;
}
}
}
MessageBox.Show ( "File copiati con successo!" ) ;
}
Codice nella classe:
Codice sorgente - presumibilmente C++
static class CopyFiles
{
public static async Task CopyToWithProgressAsync( this Stream source, Stream destination, int bufferSize = 4096, Action< long > progress = null)
{
var buffer = new byte[ bufferSize] ;
var total = 0L ;
int amtRead;
do
{
amtRead = 0 ;
while ( amtRead < bufferSize)
{
var numBytes = await source.ReadAsync ( buffer, amtRead, bufferSize - amtRead) ;
if ( numBytes == 0)
{
break ;
}
amtRead + = numBytes;
}
total + = amtRead;
await destination.WriteAsync ( buffer, 0, amtRead) ;
if ( progress ! = null)
{
progress( total) ;
}
} while ( amtRead == bufferSize) ;
}
}
Il conteggio sembrava essere risolto con l'uso di Math.Round nel modo che ho usato sopra, ho provato anche con Math.Truncate la copia dei file viene effettuata con successo e la progressBar avanza.
Ho provato con una cartella che usavo di prova ed era finita correttamente anche la progressBar, ma era solo un illusione, infatti passando un'altra cartella si vede che ad ogni file la progressBar ricomincia sempre da 0.
Non so più cosa devo fare ti prego aiutami
Ultima modifica effettuata da lupetto77 il 27/06/2017 alle 23:15
Thejuster (Admin )
Guru^2
Messaggi: 2310
Iscritto: 04/05/2008
Ok dai e ora dunque di svelare l'arcano.
siccome non ci sei riuscito ma ho visto che la volontà ci stava
( Altrimenti sti cavoli che ti scrivevo la soluzione ed il codice )
Ti spiego dove sbagliavi e come fare.
Anche perché normalmente sul forum aiutiamo veramente a chi ci mostra che
sta brancolando nel buio o è in difficoltà.
Il tuo metodo poteva andare bene ma preferisco un approccio diverso
senza utilizzare Thread paralleli o altre cose del genere.
La logica del discorso è questa.
1° Ottengo tutti i bytes da copiare di tutti i file facendo un ciclo ricorsivo
ed incrementando una variabile pubblica
2° Inizio un ciclo di copia
Siccome ti avevo ripetuto tipo 100 volte che il tuo calcolo era sbagliato.
ti spiego il perché.
Perché la copia viene effettuata in Kilobyte e non in byte.
un byte è 255 un kilobyte 1024
quindi si fà
copiato / 1024 (Kilobyte)
e giustamente ( OutOfRange ) ci sta ed ha pure ragione...
Dunque come fare?
Codice sorgente - presumibilmente C#
//Variabili pubbliche
int maxbytes = 0 ;
int copiati = 0 ;
int totali = 0 ;
string source;
string dest;
//Avvio del processo
private void button3_Click( object sender, EventArgs e)
{
DirectoryInfo diSource
= new DirectoryInfo
( source
) ; DirectoryInfo diTarget
= new DirectoryInfo
( dest
) ;
//Creo un ciclo veloce per recuperare
//prima tutti i bytes totali di tutti i file contenuti
//nelle cartelle e sottocartelle, la funzione è un ciclo
//che man mano incrementa la variabiale maxbytes.
GetSize( diSource, diTarget) ;
maxbytes = maxbytes / 1024 ;
progressBar1.Maximum = maxbytes;
Copia( label4, progressBar1, diSource, diTarget) ;
MessageBox.Show ( "Completato..." ) ;
}
/// <summary>
/// Funzione Copia Tutto
/// </summary>
/// <param name="lable1">Label su cui applicare le modifiche</param>
/// <param name="progressBar1">Progressbar su cui applicare le modifiche</param>
/// <param name="source">Cartella sorgente</param>
/// <param name="target">Cartella di destinazione</param>
public void Copia( Label lable1, ProgressBar progressBar1, DirectoryInfo source, DirectoryInfo target)
{
if ( Directory.Exists ( target.FullName ) == false )
{
Directory.CreateDirectory ( target.FullName ) ;
}
foreach ( FileInfo fi in source.GetFiles ( ) )
{
fi.CopyTo ( Path.Combine ( target.ToString ( ) , fi.Name ) , true ) ;
totali += ( int ) fi.Length ;
copiati += ( int ) fi.Length ;
copiati /= 1024 ;
progressBar1.Step = copiati;
progressBar1.PerformStep ( ) ;
lable1.Text = ( totali / 1024 ) .ToString ( ) + "KB di " + maxbytes.ToString ( ) + "KB copiati" ;
lable1.Refresh ( ) ;
}
foreach ( DirectoryInfo diSourceSubDir in source.GetDirectories ( ) )
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory ( diSourceSubDir.Name ) ;
Copia( lable1, progressBar1, diSourceSubDir, nextTargetSubDir) ;
}
}
/// <summary>
/// Funzione iniziale utilizzata per il recupero e successivamente
/// per la grandezza dei files
/// </summary>
/// <param name="source">cartella di sorgente</param>
/// <param name="target">cartella di destinazione</param>
public void GetSize( DirectoryInfo source, DirectoryInfo target)
{
foreach ( FileInfo fi in source.GetFiles ( ) )
{
maxbytes += ( int ) fi.Length ;
}
foreach ( DirectoryInfo diSourceSubDir in source.GetDirectories ( ) )
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory ( diSourceSubDir.Name ) ;
GetSize( diSourceSubDir, nextTargetSubDir) ;
}
}
poi volendo puoi mettere tutto in un thread separato
ma assicurati di utilizzare invoke((Action)delegate { .... } per le operazioni sia alla label
che alla progressBar.
Detto questo sei apposto così
Buona fortuna per il tuo progetto
Ultima modifica effettuata da Thejuster il 29/06/2017 alle 16:12
lupetto77 (Normal User)
Pro
Messaggi: 75
Iscritto: 04/12/2011
Ciao Thejuster e grazie infinitamente per l'aiuto.
Stavo provando da un po il codice, siccome copia tutti i file ma non si avvia la progressBar e la finestra rimane bloccata, solo dopo la fine della copia mostra la progressBar piena con la MessageBox i completamento.
Stavo facendo delle prove e sono queste:
Una domanda prima, perche' usi la label4 nel button3?
Non so cos'è la label4, ma immagino che si poteva passare la labe1 giusto?
Premetto che ho provato con il backgroundWorker pensando che era più facile, ma non ci sono riuscito.
Allora ho provato a creare una classe sempre basandomi su il tuo codice:
Codice sorgente - presumibilmente C++
static class CopyFilesAsync
{
public static int maxbytes { get; set; } = 0 ;
public static int copiati { get; set; } = 0 ;
public static int totali { get; set; } = 0 ;
/// <summary>
/// Funzione Copia Tutto
/// </summary>
/// <param name="lable1">Label su cui applicare le modifiche</param>
/// <param name="progressBar1">Progressbar su cui applicare le modifiche</param>
/// <param name="source">Cartella sorgente</param>
/// <param name="target">Cartella di destinazione</param>
public static async Task Copia( Label label1, ProgressBar progressBar1, DirectoryInfo source, DirectoryInfo target, Action< int > progress = null, Action< string> label = null)
{
//Controllo se esiste la directory di destinazione altrimenti la creo
if ( Directory.Exists ( target.FullName ) == false )
{
Directory.CreateDirectory ( target.FullName ) ;
}
foreach ( FileInfo fi in source.GetFiles ( ) )
{
fi.CopyTo ( Path.Combine ( target.ToString ( ) , fi.Name ) , true ) ;
totali + = ( int ) fi.Length ;
copiati + = ( int ) fi.Length ;
copiati / = 1024 ;
//progressBar1.Step = copiati;
//progressBar1.PerformStep();
//label1.Text = (totali / 1024).ToString() + "KB di " + maxbytes.ToString() + "KB copiati";
//label1.Refresh();
if ( progress ! = null)
{
progress( copiati) ;
}
if ( label ! = null)
{
label( ( totali / 1024 ) .ToString ( ) + "KB di " + maxbytes.ToString ( ) + "KB copiati" ) ;
}
}
foreach ( DirectoryInfo diSourceSubDir in source.GetDirectories ( ) )
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory ( diSourceSubDir.Name ) ;
await Copia( label1, progressBar1, diSourceSubDir, nextTargetSubDir, progress, label) ;
}
}
}
Nel form principale:
Codice sorgente - presumibilmente C#
//Variabili pubbliche
string source;
string dest;
/// <summary>
/// Funzione iniziale utilizzata per il recupero e successivamente
/// per la grandezza dei files
/// </summary>
/// <param name="source">cartella di sorgente</param>
/// <param name="target">cartella di destinazione</param>
public void GetSize( DirectoryInfo source, DirectoryInfo target)
{
foreach ( FileInfo fi in source.GetFiles ( ) )
{
CopyFilesAsync.maxbytes += ( int ) fi.Length ;
}
foreach ( DirectoryInfo diSourceSubDir in source.GetDirectories ( ) )
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory ( diSourceSubDir.Name ) ;
GetSize( diSourceSubDir, nextTargetSubDir) ;
}
}
private void btnSource_Click( object sender, EventArgs e)
{
FolderBrowserDialog fbd
= new FolderBrowserDialog
( ) ; if ( fbd.ShowDialog ( ) == DialogResult.OK )
{
source = fbd.SelectedPath ;
txtSource.Text = source;
}
}
private void btnDestination_Click( object sender, EventArgs e)
{
FolderBrowserDialog fbd
= new FolderBrowserDialog
( ) ; if ( fbd.ShowDialog ( ) == DialogResult.OK )
{
dest = fbd.SelectedPath ;
txtDestination.Text = dest;
}
}
//Avvio del processo
private async void btnCopia_Click( object sender, EventArgs e)
{
DirectoryInfo diSource
= new DirectoryInfo
( source
) ; DirectoryInfo diTarget
= new DirectoryInfo
( dest
) ;
//Creo un ciclo veloce per recuperare
//prima tutti i bytes totali di tutti i file contenuti
//nelle cartelle e sottocartelle, la funzione è un ciclo
//che man mano incrementa la variabiale maxbytes.
GetSize( diSource, diTarget) ;
CopyFilesAsync.maxbytes = CopyFilesAsync.maxbytes / 1024 ;
progressBar1.Maximum = CopyFilesAsync.maxbytes ;
await CopyFilesAsync.Copia ( label2, progressBar1, diSource, diTarget, progress => progressBar1.Step = progress, label => label1.Text = label) ;
progressBar1.PerformStep ( ) ;
label1.Refresh ( ) ;
MessageBox.Show ( "Completato..." ) ;
//backgroundWorker1.RunWorkerAsync();
}
Stesso risultato, copia tutti i file ma la progressBar non avanza e la finestra rimane bloccata.
Ultima modifica effettuata da lupetto77 il 30/06/2017 alle 1:33
lupetto77 (Normal User)
Pro
Messaggi: 75
Iscritto: 04/12/2011
Ti mostro anche la prove con il backgroundWorker1
Codice sorgente - presumibilmente C# / VB.NET
Codice sorgente - presumibilmente C# / VB.NET
/// <summary>
/// Funzione Copia Tutto
/// </summary>
/// <param name="lable1">Label su cui applicare le modifiche</param>
/// <param name="progressBar1">Progressbar su cui applicare le modifiche</param>
/// <param name="source">Cartella sorgente</param>
/// <param name="target">Cartella di destinazione</param>
public void Copia(Label label1, ProgressBar progressBar1, DirectoryInfo source, DirectoryInfo target)
{
//Controllo se esiste la directory di destinazione altrimenti la creo
if (Directory.Exists(target.FullName) == false)
{
Directory.CreateDirectory(target.FullName);
}
foreach (FileInfo fi in source.GetFiles())
{
fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
totali += (int)fi.Length;
copiati += (int)fi.Length;
copiati /= 1024;
//progressBar1.Step = copiati;
//progressBar1.PerformStep();
backgroundWorker1.ReportProgress(copiati);
//label1.Text = (totali / 1024).ToString() + "KB di " + maxbytes.ToString() + "KB copiati";
//label1.Refresh();
}
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
Copia(label1, progressBar1, diSourceSubDir, nextTargetSubDir);
}
}
/// <summary>
/// Funzione iniziale utilizzata per il recupero e successivamente
/// per la grandezza dei files
/// </summary>
/// <param name="source">cartella di sorgente</param>
/// <param name="target">cartella di destinazione</param>
public void GetSize(DirectoryInfo source, DirectoryInfo target)
{
foreach (FileInfo fi in source.GetFiles())
{
maxbytes += (int)fi.Length;
}
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
GetSize(diSourceSubDir, nextTargetSubDir);
}
}
private void btnSource_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if(fbd.ShowDialog() == DialogResult.OK)
{
source = fbd.SelectedPath;
txtSource.Text = source;
}
}
private void btnDestination_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
{
dest = fbd.SelectedPath;
txtDestination.Text = dest;
}
}
//Avvio del processo
private void btnCopia_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
DirectoryInfo diSource = new DirectoryInfo(source);
DirectoryInfo diTarget = new DirectoryInfo(dest);
//Creo un ciclo veloce per recuperare
//prima tutti i bytes totali di tutti i file contenuti
//nelle cartelle e sottocartelle, la funzione è un ciclo
//che man mano incrementa la variabiale maxbytes.
GetSize(diSource, diTarget);
maxbytes = maxbytes / 1024;
progressBar1.Maximum = maxbytes;
Copia(label2, progressBar1, diSource, diTarget);
MessageBox.Show("Completato...");
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Invoke((Action)delegate
{
progressBar1.Step = copiati;
progressBar1.PerformStep();
label1.Text = (totali / 1024).ToString() + "KB di " + maxbytes.ToString() + "KB copiati";
label1.Refresh();
});
}
Nella funzione Copia con questa riga:
Codice sorgente - presumibilmente Plain Text
Codice sorgente - presumibilmente Plain Text
backgroundWorker1.ReportProgress(copiati);
Vengono create solo due cartelle vuote e la progressBar e la label1 non avanzano.
Poi ho provato cosi:
Nell'evento ProgressChanged impostato cosi:
Codice sorgente - presumibilmente C# / VB.NET
Codice sorgente - presumibilmente C# / VB.NET
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Invoke((Action)delegate
{
progressBar1.Value = e.ProgressPercentage;
});
}
e nella funzione Copia:
Codice sorgente - presumibilmente C# / VB.NET
Codice sorgente - presumibilmente C# / VB.NET
/// <summary>
/// Funzione Copia Tutto
/// </summary>
/// <param name="lable1">Label su cui applicare le modifiche</param>
/// <param name="progressBar1">Progressbar su cui applicare le modifiche</param>
/// <param name="source">Cartella sorgente</param>
/// <param name="target">Cartella di destinazione</param>
public void Copia(Label label1, ProgressBar progressBar1, DirectoryInfo source, DirectoryInfo target)
{
//Controllo se esiste la directory di destinazione altrimenti la creo
if (Directory.Exists(target.FullName) == false)
{
Directory.CreateDirectory(target.FullName);
}
foreach (FileInfo fi in source.GetFiles())
{
fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
totali += (int)fi.Length;
copiati += (int)fi.Length;
copiati /= 1024;
Invoke((Action)delegate
{
progressBar1.Step = copiati;
progressBar1.PerformStep();
label1.Text = (totali / 1024).ToString() + "KB di " + maxbytes.ToString() + "KB copiati";
label1.Refresh();
});
}
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
Copia(label1, progressBar1, diSourceSubDir, nextTargetSubDir);
}
}
Si muove la finestra ma non copia e avanza la progressBar.
Scusami ancora ma ci sto provando e non ci riesco a far funzionare questa maledetta progressBar
Ultima modifica effettuata da lupetto77 il 30/06/2017 alle 0:34
Thejuster (Admin )
Guru^2
Messaggi: 2310
Iscritto: 04/05/2008
Non so cosa dirti lol.
Da me ha funzionato anche senza il background worker.
Ho testato su xp.
Quando torno da lavoro lo provo su win7 e ti faccio sapere
Edit:
Intanto prova sempre con i delegati avviando un thread anziché un Background worker.
Ho appena testato e funziona
https://s1.postimg.org/3ruzte6rj/Immagine.png
Codice sorgente - presumibilmente C++
//Avvio del processo
private void button3_Click( object sender, EventArgs e)
{
DirectoryInfo diSource = new DirectoryInfo( source) ;
DirectoryInfo diTarget = new DirectoryInfo( dest) ;
//Creo un ciclo veloce per recuperare
//prima tutti i bytes totali di tutti i file contenuti
//nelle cartelle e sottocartelle, la funzione è un ciclo
//che man mano incrementa la variabiale maxbytes.
GetSize( diSource, diTarget) ;
maxbytes = maxbytes / 1024 ;
progressBar1.Maximum = maxbytes;
Thread t = new Thread( ( ) => Copia( label4, progressBar1, diSource, diTarget) ) ;
//Copia(label4, progressBar1, diSource, diTarget);
t.Start ( ) ;
//MessageBox.Show("Completato...");
}
/// <summary>
/// Funzione Copia Tutto
/// </summary>
/// <param name="lable1">Label su cui applicare le modifiche</param>
/// <param name="progressBar1">Progressbar su cui applicare le modifiche</param>
/// <param name="source">Cartella sorgente</param>
/// <param name="target">Cartella di destinazione</param>
public void Copia( Label lable1, ProgressBar progressBar1, DirectoryInfo source, DirectoryInfo target)
{
if ( Directory.Exists ( target.FullName ) == false )
{
Directory.CreateDirectory ( target.FullName ) ;
}
foreach ( FileInfo fi in source.GetFiles ( ) )
{
Invoke( ( Action) delegate
{
fi.CopyTo ( Path.Combine ( target.ToString ( ) , fi.Name ) , true ) ;
totali + = ( int ) fi.Length ;
copiati + = ( int ) fi.Length ;
copiati / = 1024 ;
progressBar1.Step = copiati;
progressBar1.PerformStep ( ) ;
lable1.Text = ( totali / 1024 ) .ToString ( ) + "KB di " + maxbytes.ToString ( ) + "KB copiati" ;
lable1.Refresh ( ) ;
} ) ;
}
foreach ( DirectoryInfo diSourceSubDir in source.GetDirectories ( ) )
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory ( diSourceSubDir.Name ) ;
Copia( lable1, progressBar1, diSourceSubDir, nextTargetSubDir) ;
}
}
/// <summary>
/// Funzione iniziale utilizzata per il recupero e successivamente
/// per la grandezza dei files
/// </summary>
/// <param name="source">cartella di sorgente</param>
/// <param name="target">cartella di destinazione</param>
public void GetSize( DirectoryInfo source, DirectoryInfo target)
{
foreach ( FileInfo fi in source.GetFiles ( ) )
{
maxbytes + = ( int ) fi.Length ;
}
foreach ( DirectoryInfo diSourceSubDir in source.GetDirectories ( ) )
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory ( diSourceSubDir.Name ) ;
GetSize( diSourceSubDir, nextTargetSubDir) ;
}
}
Ultima modifica effettuata da Thejuster il 30/06/2017 alle 14:33
lupetto77 (Normal User)
Pro
Messaggi: 75
Iscritto: 04/12/2011
Ciao Thejuster ho tolto il backgroundworker e provato come mi hai suggerito, e sembra andare bene con cartelle di piccole dimensioni perchè provando a copiare una cartella di 15gb ma anche un unico file da 5gb mi da questa eccezione:
(ovviamente cambia solo la dimensione '-1597523')
Codice sorgente - presumibilmente Plain Text
System.ArgumentOutOfRangeException: ''-1597523' non è un valore valido per 'Maximum'. 'Maximum' deve essere maggiore o uguale a 0.'
Non vuole proprio saperne di funzionare la maledetta
Ultima modifica effettuata da lupetto77 il 30/06/2017 alle 18:20