CopyFileEx包装器参数

时间:2012-12-20 16:17:11

标签: c# pinvoke

我最近不得不从使用File.Copy()更改为CopyFileEx,我正在努力寻找如何使用它。

经过大量的谷歌搜索,我发现this使用它的好包装,但我需要的是获取当前文件的复制字节的进度,如果可能的话,计算复制所有文件的进度我传递给它。

(我知道有些项目的进度条与CopyFileEx相关联,但我没有足够的经验来提取相关代码,我想使用这个包装器。)

大概只是将它与要复制的文件的总字节数进行比较,我会事先找到它,然后计算出百分比。

我目前的复制方法是

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

我所坚持的是如何使用获取进度信息所需的参数来重载它。

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
}

任何指针都非常感激。

2 个答案:

答案 0 :(得分:8)

包装器已经有处理进度所需的管道。只需在返回之前实现代码以在CallbackHandler中更新进度条。 progressBar1.Maximum默认为100,因此下面的代码将计算百分比。

用以下内容替换当前的CopyFile调用:

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);

答案 1 :(得分:0)

如果您只想显示文件副本的进度条,可以执行this。它使用Windows标准对话框显示进度条和剩余时间,并且它有一个取消按钮。这正是我基本上需要一行代码所需要的。

var jointData = (from d in db.DomainData
                 join s in db.SystemUrls on d.Id equals s.DomainId into sg
                 new { m.DomainName, m.OrgId, DomainId = m.Id, s.TypeId }).ToList();

var result = jointData.GroupBy(item => new { item.DomainName, item.OrgId, item.DomainId })
             .Select(g => new { 
                 g.Key.DomainName, 
                 g.Key.OrgId, 
                 g.Key.DomainId, 
                 TypeId = string.Join(", ", g.Select(item => item.TypeId))
             });