2012-12-20 19 views
6

Niedawno musiałem zmienić korzystanie z File.Copy() na CopyFileEx i staram się znaleźć sposób korzystania z niego.Parametry opakowania CopyFileEx:

Po dużo googlowania znalazłem ładne opakowanie, aby go użyć, ale potrzebuję uzyskać postęp kopiowanych bajtów bieżącego pliku, a jeśli to możliwe, obliczyć postęp kopiowania wszystkich plików, które mu przekazuję .

(Wiem, że są projekty, które mają paski postępu powiązane z CopyFileEx, ale nie mam wystarczająco dużo doświadczenia, aby wyciągnąć odpowiedni kod i chciałbym użyć tego opakowania).

Prawdopodobnie po prostu porównując go z łącznymi bajtami plików do skopiowania, które znajdę wcześniej i obliczając procent.

Moja obecna metoda kopiowania jest

FileRoutines.CopyFile(new FileInfo("source.txt"), new FileInfo("dest.txt")); 

Co siedzę na to, jak przeciążać go z parametrem jest potrzebne, aby uzyskać informacje o postępach.

public sealed class FileRoutines 
{ 
    public static void CopyFile(FileInfo source, FileInfo destination) 
    { 
     CopyFile(source, destination, CopyFileOptions.None); 
    } 

    public static void CopyFile(FileInfo source, FileInfo destination, 
     CopyFileOptions options) 
    { 
     CopyFile(source, destination, options, null); 
    } 

    public static void CopyFile(FileInfo source, FileInfo destination, 
     CopyFileOptions options, CopyFileCallback callback) 
    { 
     CopyFile(source, destination, options, callback, null); 
    } 

    public static void CopyFile(FileInfo source, FileInfo destination, 
     CopyFileOptions options, CopyFileCallback callback, object state) 
    { 
     if (source == null) throw new ArgumentNullException("source"); 
     if (destination == null) 
      throw new ArgumentNullException("destination"); 
     if ((options & ~CopyFileOptions.All) != 0) 
      throw new ArgumentOutOfRangeException("options"); 

     new FileIOPermission(
      FileIOPermissionAccess.Read, source.FullName).Demand(); 
     new FileIOPermission(
      FileIOPermissionAccess.Write, destination.FullName).Demand(); 

     CopyProgressRoutine cpr = callback == null ? 
      null : new CopyProgressRoutine(new CopyProgressData(
       source, destination, callback, state).CallbackHandler); 

     bool cancel = false; 
     if (!CopyFileEx(source.FullName, destination.FullName, cpr, 
      IntPtr.Zero, ref cancel, (int)options)) 
     { 
      throw new IOException(new Win32Exception().Message); 
     } 
    } 

    private class CopyProgressData 
    { 
     private FileInfo _source = null; 
     private FileInfo _destination = null; 
     private CopyFileCallback _callback = null; 
     private object _state = null; 

     public CopyProgressData(FileInfo source, FileInfo destination, 
      CopyFileCallback callback, object state) 
     { 
      _source = source; 
      _destination = destination; 
      _callback = callback; 
      _state = state; 
     } 

     public int CallbackHandler(
      long totalFileSize, long totalBytesTransferred, 
      long streamSize, long streamBytesTransferred, 
      int streamNumber, int callbackReason, 
      IntPtr sourceFile, IntPtr destinationFile, IntPtr data) 
     { 
      return (int)_callback(_source, _destination, _state, 
       totalFileSize, totalBytesTransferred); 
     } 
    } 

    private delegate int CopyProgressRoutine(
     long totalFileSize, long TotalBytesTransferred, long streamSize, 
     long streamBytesTransferred, int streamNumber, int callbackReason, 
     IntPtr sourceFile, IntPtr destinationFile, IntPtr data); 

    [SuppressUnmanagedCodeSecurity] 
    [DllImport("Kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
    private static extern bool CopyFileEx(
     string lpExistingFileName, string lpNewFileName, 
     CopyProgressRoutine lpProgressRoutine, 
     IntPtr lpData, ref bool pbCancel, int dwCopyFlags); 
} 

public delegate CopyFileCallbackAction CopyFileCallback(
    FileInfo source, FileInfo destination, object state, 
    long totalFileSize, long totalBytesTransferred); 

public enum CopyFileCallbackAction 
{ 
    Continue = 0, 
    Cancel = 1, 
    Stop = 2, 
    Quiet = 3 
} 

[Flags] 
public enum CopyFileOptions 
{ 
    None = 0x0, 
    FailIfDestinationExists = 0x1, 
    Restartable = 0x2, 
    AllowDecryptedDestination = 0x8, 
    All = FailIfDestinationExists | Restartable | AllowDecryptedDestination 
} 

Wszelkie wskazówki naprawdę docenione.

+0

Kod ten wygląda identycznie jak kod artykułu MSDN Magazine. Jeśli tak, powinieneś przyznać oryginał. http://msdn.microsoft.com/en-us/magazine/cc163851.aspx –

+1

@ChrisDolan - link wskazuje tylko na magazyn MSDN Magazine - patrz chm dla MSDN Magazine luty 2005.Net Matters Rysunek 1 FileRoutines.CopyFile Korzystanie Win32 CopyFileEx –

+1

@TheLonelyCoder - Hmm, masz rację. Ponownie znalazłem go tutaj: https://web.archive.org/web/20130304214632/http://msdn.microsoft.com/en-us/magazine/cc163851.aspx, ale bez CSS, więc jest o wiele trudniej przeczytaj –

Odpowiedz

8

Opakowanie ma już hydraulikę potrzebną do obsługi postępów. Wystarczy zaimplementować kod, aby zaktualizować pasek postępu w CallbackHandler przed powrotem. ProgresBar1.Maksymalna wartość domyślna to 100, więc poniższy kod obliczy procent.

Wymień bieżącego połączenia CopyFile z tym:

CopyFileCallbackAction myCallback(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred) 
{ 
    double dProgress = (totalBytesTransferred/(double)totalFileSize) * 100.0; 
    progressBar1.Value = (int)dProgress; 
    return CopyFileCallbackAction.Continue; 
} 

FileRoutines.CopyFile(new FileInfo("source.txt"), new FileInfo("dest.txt"), myCallback); 
+0

Dziękuję za odpowiedź. Wiem, że kod już tam jest, po prostu nie wiem jak go użyć :) Czy mógłbyś podać mi przykład kodu? –

+0

@BaliC - Kod został dodany zgodnie z życzeniem. :) –

+0

Bardzo dziękuję, przetestuję to dziś wieczorem i dam znać, jeśli to działa :) –

0

Jeśli chcesz tylko pokazać pasek postępu dla kopii plików, można zrobić this. Używa standardowego okna dialogowego Windows, które pokazuje pasek postępu i pozostały czas, i ma przycisk Anuluj. Właśnie tego potrzebowałem w zasadzie w jednej linii kodu.

// The following using directive requires a project reference to Microsoft.VisualBasic. 
using Microsoft.VisualBasic.FileIO; 

class FileProgress 
{ 
    static void Main() 
    { 
     // Specify the path to a folder that you want to copy. If the folder is small, 
     // you won't have time to see the progress dialog box. 
     string sourcePath = @"C:\Windows\symbols\"; 
     // Choose a destination for the copied files. 
     string destinationPath = @"C:\TestFolder"; 

     FileSystem.CopyDirectory(sourcePath, destinationPath, 
      UIOption.AllDialogs); 
    } 
} 
Powiązane problemy