我在c#中使用CopyFileEx pinvoke将小型和大型文件从辅助驱动器复制到闪存驱动器。有问题的文件是MP4文件。较小的文件可以复制,但较大的文件大约1GB或更多,复制文件的大小,但不包括使MP4不可播放的元数据。是什么原因可以导致我做到这一点?
关闭程序后,Windows会告诉我写入失败。
public class XCopy
{
#region DLL Imports
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName, CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref int pbCancel, CopyFileFlags dwCopyFlags);
#endregion
#region Delegates
private delegate CopyProgressResult CopyProgressRoutine(long TotalFileSize, long TotalBytesTransferred, long StreamSize,
long StreamBytesTransferred, uint dwStreamNumber, CopyProgressCallbackReason dwCallbackReason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);
#endregion
#region Fields
private int isCancelled;
private int filePercentCompleted;
private static bool finished = true;
private static bool errorOccurred;
private static License license;
#endregion
#region Properties
/// <summary>
/// Gets the flag indicating that copying has finished.
/// </summary>
public static bool Finished => finished;
/// <summary>
/// Gets the flag indicating that an error occurred while copying.
/// </summary>
public static bool ErrorOccurred => errorOccurred;
#endregion
#region Event Handlers
private event EventHandler<ProgressChangedEventArgs> ProgressChanged;
#endregion
#region Enumerations
/// <summary>
/// Progress result.
/// </summary>
private enum CopyProgressResult : uint
{
PROGRESS_CONTINUE = 0
}
/// <summary>
/// Callback reason.
/// </summary>
private enum CopyProgressCallbackReason : uint
{
CALLBACK_CHUNK_FINISHED = 0x00000000
}
/// <summary>
/// File flags.
/// </summary>
[Flags]
private enum CopyFileFlags : uint
{
COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
COPY_FILE_NO_BUFFERING = 0x00001000,
COPY_FILE_RESTARTABLE = 0x00000002
}
#endregion
#region Constructors
/// <summary>
/// Constructor that is internal.
/// </summary>
private XCopy()
{
license = LicenseManager.Validate(typeof(XCopy), this);
isCancelled = 0;
}
/// <summary>
/// Constructor.
/// </summary>
static XCopy()
{
license = LicenseManager.Validate(typeof(XCopy), IntPtr.Zero);
}
#endregion
#region Internal Members
/// <summary>
/// Copy source file to destination.
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <param name="overwrite"></param>
/// <param name="nobuffering"></param>
/// <param name="handler"></param>
private void CopyInternal(string source, string destination, bool overwrite, bool nobuffering, EventHandler<ProgressChangedEventArgs> handler)
{
errorOccurred = false;
finished = false;
try
{
var copyFileFlags = CopyFileFlags.COPY_FILE_RESTARTABLE;
if (!overwrite)
{
copyFileFlags |= CopyFileFlags.COPY_FILE_FAIL_IF_EXISTS;
}
if (nobuffering)
{
copyFileFlags |= CopyFileFlags.COPY_FILE_NO_BUFFERING;
}
if (handler != null)
{
ProgressChanged += handler;
}
var result = CopyFileEx(source, destination, CopyProgressHandler, IntPtr.Zero, ref isCancelled, copyFileFlags);
if (!result)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
catch (Exception e)
{
LogManager.Log(LogType.ERROR, "Copy: " + e.Message);
if (handler != null)
{
ProgressChanged -= handler;
errorOccurred = true;
}
finished = true;
}
}
/// <summary>
/// Progress handler.
/// </summary>
/// <param name="total"></param>
/// <param name="transferred"></param>
/// <param name="streamSize"></param>
/// <param name="streamByteTrans"></param>
/// <param name="dwStreamNumber"></param>
/// <param name="reason"></param>
/// <param name="hSourceFile"></param>
/// <param name="hDestinationFile"></param>
/// <param name="lpData"></param>
/// <returns></returns>
private CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize, long streamByteTrans, uint dwStreamNumber,
CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
{
if (reason == CopyProgressCallbackReason.CALLBACK_CHUNK_FINISHED)
{
OnProgressChanged((transferred / (double)total) * 100.0);
}
if (transferred >= total)
{
finished = true;
}
return CopyProgressResult.PROGRESS_CONTINUE;
}
#endregion
#region External Members
/// <summary>
/// Copy using an overwrite and buffer flag.
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <param name="overwrite"></param>
/// <param name="nobuffering"></param>
public static void Copy(string source, string destination, bool overwrite, bool nobuffering)
{
Task.Factory.StartNew(() =>
{
try
{
new XCopy().CopyInternal(source, destination, overwrite, nobuffering, null);
}
catch (AggregateException e)
{
foreach (var error in e.InnerExceptions)
{
LogManager.Log(LogType.DEBUG, error.Message);
}
}
});
}
/// <summary>
/// Copy using an overwrite and buffer flag along with a progress event handler.
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <param name="overwrite"></param>
/// <param name="nobuffering"></param>
/// <param name="handler"></param>
public static void Copy(string source, string destination, bool overwrite, bool nobuffering, EventHandler<ProgressChangedEventArgs> handler)
{
Task.Factory.StartNew(() =>
{
try
{
new XCopy().CopyInternal(source, destination, overwrite, nobuffering, handler);
}
catch (AggregateException e)
{
foreach (var error in e.InnerExceptions)
{
LogManager.Log(LogType.DEBUG, error.Message);
}
}
});
}
/// <summary>
/// Dispose of the license.
/// </summary>
public void Dispose()
{
if (license != null)
{
license.Dispose();
license = null;
}
}
#endregion
#region Events
/// <summary>
/// Handle changing progress.
/// </summary>
/// <param name="percent"></param>
private void OnProgressChanged(double percent)
{
if ((int)percent > filePercentCompleted)
{
filePercentCompleted = (int)percent;
ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(filePercentCompleted, null));
}
}
#endregion
}