سؤال

Here is the thing, I want to create a simply app that copy many files from one site, and move them to another; but using async methods and create a new thread.

private void button3_Click(object sender, RoutedEventArgs e)
{

    //progressBar1.Maximum = _FileInfoArray.Count;

    DispatcherTimer dt1 = new DispatcherTimer();
    foreach (FileInfo Fi in _FileInfoArray)
    {
        Thread t = new Thread(new ThreadStart(delegate()
        {
            DispatcherOperation _dispOp = progressBar1.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate()
            {

                File.Copy(txtdestino.Text, Fi.FullName, true);

                //progressBar1.Value = n;
                //txtstatus.Content = ("Copiados " + n.ToString() + " archivos");
                //Thread.Sleep(100);
            }
            ));
            _dispOp.Completed += new EventHandler(_dispOp_Completed);
        }
            ));
        t.Start();
    }
}

UnauthorizedAccessException is throw! It says that I can't access to txtdestino content. Some clues?

-------------------------------------------------------------------------------Edited This is the version with all the changes, get the same error :( any clues?

private void button4_Click(object sender, RoutedEventArgs e)
{
    //First: Build mynames
    List<string> mynames = new List<string>();
    foreach (FileInfo fi in _FileInfoArray)
    {
        mynames.Add(fi.FullName);
    }



    Thread t = new Thread(new ThreadStart(delegate()
       {
          foreach (string fullname in mynames)
            {
            DispatcherOperation _dispOp = progressBar1.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate()
            {
                string destino = System.IO.Path.Combine(@"C:\", System.IO.Path.GetFileName(fullname));
                File.Copy(fullname, destino, true);
                //Some progressbar changes
            }
            ));
            _dispOp.Completed += new EventHandler(_dispOp_Completed);
          }
        }
                ));
        t.Start();
    }

File.Copy(txtdestino.Text, Fi.FullName, true); // here the exception is throw

هل كانت مفيدة؟

المحلول

If multiple threads try to access (simultaneously) the file at txtdestino.Text - isn't that doomed from the start? You might want to read the contents into memory first and write from there...

Equally, you are going to hammer the IO; I wonder if a more practical answer (that solves the issue above and below) is to simply do the copies sequentially on the worker.

It also looks like you might actually be pushing all the work here back to the UI thread anyway...? surely you should do something like:

string path = txtdestino.Text;
Thread t = new Thread(new ThreadStart(delegate() {
    foreach (FileInfo Fi in _FileInfoArray) {
        File.Copy(path, Fi.FullName, true);
    }
}));
t.Start();

which:

  • avoids the foreach/capture issue (Fi is not captured)
  • reads the path from the UI thread and uses it (captured) on the worker
  • process each file sequentially to avoid hammering IO

You also have the foreach/capture issue; change it to:

foreach (FileInfo tmp in _FileInfoArray)
{
    FileInfo Fi = tmp;
    ...

The problem is that most likely all the threads are trying to access the last file. No, really. This is because foreach technically declares the variable (tmp above) outside the loop; and the variable capture rules (used by lambdas / anon-methods) say that therefore this is the same variable (important: lambdas / anon-methods are full lexical closures, and capture the variable, not the value).

Re-declaring a variable inside the loop changes the scope, and now the lambda / anon-method treats the variable as different per loop iteration.

If you really want, I could write it out in something that shows the underlying objects involved, but it depends whether you want that level of detail ;p

نصائح أخرى

Calls to UI elements must be done in the UI thread. try getting the text value before your loop.

string txt = txtdestino.Text;
foreach (FileInfo Fi in _FileInfoArray)
{
    ....
    File.Copy(txt, Fi.FullName, true);

You are creating multiple threads(1 for each file you find).
The problem is that only your main thread can access your form elements, otherwise all the threads would be changing your form elements at the same time.

Pass the value of txtdestino.Text to your new thread and you should be fine.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top