2012-05-09 6 views
2

Я ищу способ обновить индикатор выполнения при копировании файла из одного места в другое.Обновить индикатор выполнения при копировании большого файла

Я делаю копию в BackgroundWorker и обновляю индикатор выполнения в фоновом режиме. Я попытался использовать file.length, чтобы получить размер файла и использовать его для работы с процентом и обновить панель таким образом, но без радости.

Я прикрепляю код, и любая помощь будет принята с благодарностью, спасибо.

namespace Copier 

{ общественный частичный класс Form1: Form { общественного Form1() { InitializeComponent(); }

// Declare for use in all methods 
    public string copyFrom; 
    public string copyTo; 

    private void btnCopyFrom_Click(object sender, EventArgs e) 
    { 
     // uses a openFileDialog, openFD, to chose the file to copy 
     copyFrom = ""; 

     openFD.InitialDirectory = @"C:\Documents and Settings\user\My Documents"; 
     openFD.FileName = ""; 

     //openFD.ShowDialog(); 

     if (openFD.ShowDialog() == DialogResult.Cancel) 
     { 
      MessageBox.Show("cancel button clicked"); 
     } 

     else 
     { 
      // sets copyFrom = to the file chosen from the openFD 
      copyFrom = openFD.FileName; 
      // shows it in a textbox 
      txtCopyFrom.Text = copyFrom; 
     } 
    } 

    private void btnCopyTo_Click(object sender, EventArgs e) 
    { 
     //uses folderBrowserDialog, folderBD, to chose the folder to copy to 
     copyTo = ""; 

     this.folderBD.RootFolder = System.Environment.SpecialFolder.MyComputer; 
     this.folderBD.ShowNewFolderButton = false; 
     //folderBD.ShowDialog(); 
     //DialogResult result = this.folderBD.ShowDialog(); 

     if (folderBD.ShowDialog() == DialogResult.Cancel) 
     { 
      MessageBox.Show("cancel button clicked"); 
     } 
     else 
     { 
      // sets copyTo = to the folder chosen from folderBD 
      copyTo = this.folderBD.SelectedPath; 
      //shows it in a textbox. 
      txtCopyTo.Text = copyTo; 
     } 
    } 

    private void btnCopy_Click(object sender, EventArgs e) 
    { 
     copyBGW.RunWorkerAsync(); 
    } 

    private void btnCancel_Click(object sender, EventArgs e) 
    { 
     Application.Exit(); 
    } 

    //================================================================= 
    //      BackGroundWorkers 
    //================================================================= 

    private void copyBGW_DoWork(object sender, DoWorkEventArgs e) 
    { 
     try 
     { 
      // copies file 
      string destinatationPath = Path.Combine(copyTo, Path.GetFileName(copyFrom)); 
      File.Copy(copyFrom, destinatationPath); 
      MessageBox.Show("File Copied"); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
    } 
} 

Или кто-то может показать мне путь, чтобы просто сделать прогресс бар пойти по его себе, так это показывает, что форма не замерзла?

ли вымыли код

Спасибо за вход до сих пор

+3

http://stackoverflow.com/questions/187768/can-i-show-file-copy-progress-using-fileinfo-copyto -in-net –

+0

В качестве примечания, я предлагаю вам прочитать этот [учебник] (http://www.albahari.com/threading/part3.aspx#_BackgroundWorker) в потоках BackgroundWorker.Поместите код наподобие 'MessageBox.Show' и обработки исключений в событие RunWorkerCompleted вашего потока BackgroundWorker. –

ответ

2

Это не может работать на нескольких уровнях. Прежде всего, фонового работника нужно установить «сообщить об изменениях» с помощью WorkerReportsProgress, но этот флаг не означает, что он может сделать это автоматически, конечно, это не сработает. Для этого Worker предоставляет метод ReportProgress, вам нужно вызвать этот метод, чтобы показать текущий прогресс. И это показывает окончательный недостаток вашего подхода. Метод File.Copy блокируется, но вашему работнику требуется время для вызова метода ReportProgress. Поэтому вам нужно найти способ скопировать файл асинхронно. This вопрос может помочь, и, конечно же, комментарий Дэйва Бикса - очень хорошая ссылка для копирования асинхронного файла.

+1

Вот еще один пример того, как скопировать файл и сообщить о прогрессе: http://stackoverflow.com/a/6055385/519244, обработчик событий DoWork в BackgroundWorker может выглядеть как метод Copy здесь, заменив вызов OnProgressChanged на вызов метода ReportProgress для BackgroundWorker. –

+0

@Renaud Dumont Я не уверен, что создание собственного метода копирования с использованием потоков - это мудро. Я бы подумал, что фактический метод копирования намного эффективнее для такого рода операций io, но у меня нет ссылки на это. Но да, если есть какая-то оптимизация с реальной копией, возможно, именно поэтому нет асинхронной версии. – dowhilefor

+0

Прежде всего спасибо за вход. Я не являюсь программистом в мире, только начал изучать C# неделю или две назад. Я знаю, что первый код был полон маленьких глупых ошибок, я поставил их, чтобы попытаться показать, что я пытался сделать. Я пошел использовать 'progressBar1.Style = ProgressBarStyle.Marquee;' чтобы показать, что программа не замерзает, и метка, которая изменяется при копировании и копировании файла. Еще раз спасибо за вход, и я знаю, что мое решение сильно ошарашено от того, что я просил, но я просто не могу полностью обойти асинхронно. Спасибо – ELSheepO

0

Мое предложение было бы переместить содержимое btnCopyTo_Click и btnCopyFrom_Click отделить DoWork фона рабочих для каждого из них, а затем использовать btnCopyTo_Click и btnCopyFrom_Click для запуска фоновых рабочих. Фоновые работники могут использоваться для сообщения о прогрессе, поэтому вы даже не сможете начать, не делая этого.

Что касается фактического обновления индикатора выполнения, я рекомендую каждый раз определять размер файлов, которые вы копируете.

Если вы затем разделите файлы на блоки определенного размера и затем используете цикл для копирования по одному блоку за раз, то вы должны иметь возможность увеличивать индикатор выполнения на определенную величину для многих циклов цикла.

Альтернативно можно найти способ иметь асинхронный поток, который непрерывно перемещает индикатор выполнения от 0 до 100 во время копирования. Это довольно простое решение, но, по крайней мере, позволяет пользователю узнать, что что-то происходит.

3

Я думаю, что было бы проще просто вызвать CopyFileEx, который позволит вам указать обработчик прогресса, чтобы вы получали обновления от ОС по мере копирования файла. Вот пример кода скопирован со страницы Pinvoke.net для CopyFileEx:

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName, 
    CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref Int32 pbCancel, 
    CopyFileFlags dwCopyFlags); 

delegate CopyProgressResult CopyProgressRoutine(
long TotalFileSize, 
long TotalBytesTransferred, 
long StreamSize, 
long StreamBytesTransferred, 
uint dwStreamNumber, 
CopyProgressCallbackReason dwCallbackReason, 
IntPtr hSourceFile, 
IntPtr hDestinationFile, 
IntPtr lpData); 

int pbCancel; 

enum CopyProgressResult : uint 
{ 
    PROGRESS_CONTINUE = 0, 
    PROGRESS_CANCEL = 1, 
    PROGRESS_STOP = 2, 
    PROGRESS_QUIET = 3 
} 

enum CopyProgressCallbackReason : uint 
{ 
    CALLBACK_CHUNK_FINISHED = 0x00000000, 
    CALLBACK_STREAM_SWITCH = 0x00000001 
} 

[Flags] 
enum CopyFileFlags : uint 
{ 
    COPY_FILE_FAIL_IF_EXISTS = 0x00000001, 
    COPY_FILE_RESTARTABLE = 0x00000002, 
    COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004, 
    COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008 
} 

private void XCopy(string oldFile, string newFile) 
{ 
    CopyFileEx(oldFile, newFile, new CopyProgressRoutine(this.CopyProgressHandler), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE); 
} 

private CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize, long StreamByteTrans, uint dwStreamNumber,CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData) 
{ 
    return CopyProgressResult.PROGRESS_CONTINUE; 
} 
+0

Технически это все равно блокирует вызывающий поток, но уверен, что это хороший способ добиться прогресса от копирования файлов и отмены, а также «перезапустить» поведение (что может быть нежелательным, поэтому будьте осторожны). Но да, вызов FileCopyEX блокирует вызывающий поток, пока копия не будет закончена или отменена. Однако это не мешает вам обновить индикатор выполнения на форме. – TCC

Смежные вопросы