Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid StorageFile.CopyAsync() throw exception when copying big file?

I'm going to copy some files from Video Library to my app storage through StorageFile.CopyAsync() method, but if a file's size is more than 1GB, it would throw an exception as follow:

Type: System.Runtime.InteropServices.COMException Message: Error HRESULT E_FAIL has been returned from a call to a COM component. Stacktrace: at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()

How can I import a big file, Is there have a solution to solve this problem?

like image 638
sunjinbo Avatar asked May 26 '14 08:05

sunjinbo


2 Answers

I would try to copy it via buffer - for example like this:

private async Task CopyBigFile(StorageFile fileSource, StorageFile fileDest, CancellationToken ct)
{
   using (Stream streamSource = await fileSource.OpenStreamForReadAsync())
   using (Stream streamDest = await fileDest.OpenStreamForWriteAsync())
       await streamSource.CopyToAsync(streamDest, 1024, ct);
   return;
}
like image 183
Romasz Avatar answered Nov 07 '22 01:11

Romasz


I write a extension method, it solved my problem, you can refer to it when you need as follows:

public static class FileExtentions
{
    #region Fields
    private static readonly ulong MaxBufferSize = 16 * 1024 * 1024;
    #endregion // Fields

    #region Methods
    public static async Task<StorageFile> CopyAsync(this StorageFile self, StorageFolder desiredFolder, string desiredNewName, CreationCollisionOption option)
    {
        StorageFile desiredFile = await desiredFolder.CreateFileAsync(desiredNewName, option);
        StorageStreamTransaction desiredTransaction = await desiredFile.OpenTransactedWriteAsync();
        BasicProperties props = await self.GetBasicPropertiesAsync();
        IInputStream stream = await self.OpenSequentialReadAsync();

        ulong copiedSize = 0L;
        while (copiedSize < props.Size)
        {
            ulong bufferSize = (props.Size - copiedSize) >= MaxBufferSize ? MaxBufferSize : props.Size - copiedSize;
            IBuffer buffer = BytesToBuffer(new byte[bufferSize]);
            await stream.ReadAsync(buffer, (uint)bufferSize, InputStreamOptions.None);
            await desiredTransaction.Stream.GetOutputStreamAt(copiedSize).WriteAsync(buffer);
            buffer = null;
            copiedSize += (bufferSize);

            Debug.WriteLine(DeviceStatus.ApplicationCurrentMemoryUsage);
        }

        await desiredTransaction.CommitAsync();

        return desiredFile;
    }

    private static IBuffer BytesToBuffer(byte[] bytes)
    {
        using (var dataWriter = new DataWriter())
        {
            dataWriter.WriteBytes(bytes);
            return dataWriter.DetachBuffer();
        }
    }
    #endregion // Methods
like image 20
sunjinbo Avatar answered Nov 06 '22 23:11

sunjinbo