Share a large file between two UWP apps using Stream Sockets

Fei Xue - MSFT 1,111 Reputation points
2019-10-30T06:27:51.737+00:00

I need to share a large file between two UWP apps which are running in two different machines using stream sockets. In order to share the file successfully, I have to share file size before sharing the actual file. So I had to set a separate event in separate page to share the file size. Otherwise, the shared file is corrupted and can't open.

I have provided related code for server and client below.

Server - First Page

  private async void init_Click (object sender, RoutedEventArgs e) {  
      byte[] byteArray;  
      StorageFolder localFolder = ApplicationData.Current.LocalFolder;  
      StorageFile zipFile = await localFolder.GetFileAsync (App.fileName);  
      await Frame.Dispatcher.RunAsync (CoreDispatcherPriority.Normal, async () => {  
          using (Stream stream = await zipFile.OpenStreamForReadAsync ()) {  
              using (var memoryStream = new MemoryStream ()) {  
                  stream.CopyTo (memoryStream);  
                  byteArray = memoryStream.ToArray ();  
              }  
          }  
          StreamWriter streamWriter = new StreamWriter (App.outputStream);  
          await streamWriter.WriteLineAsync (byteArray.Length.ToString ());  
          await streamWriter.FlushAsync ();  
          await App.outputStream.FlushAsync ();  
      });  
  }  
  

Second Page

private async void ShareVideo_Click (object sender, RoutedEventArgs e) {  
    byte[] byteArray;  
    StorageFolder localFolder = ApplicationData.Current.LocalFolder;  
    StorageFile zipFile = await localFolder.GetFileAsync (App.fileName);  
    await Frame.Dispatcher.RunAsync (CoreDispatcherPriority.Normal, async () => {  
        using (Stream stream = await zipFile.OpenStreamForReadAsync ()) {  
            using (var memoryStream = new MemoryStream ()) {  
                stream.CopyTo (memoryStream);  
                byteArray = memoryStream.ToArray ();  
            }  
        }  
        App.outputStream.Write (byteArray, 0, byteArray.Length);  
        await App.outputStream.FlushAsync ();  
    });  
}  

Client

private async void Page_Loaded (object sender, RoutedEventArgs e) {  
    if (App.clientSocket != null) {  
        StreamReader streamReader = new StreamReader (App.inputStream);  
        string size = await streamReader.ReadLineAsync ();  
        if (size != null) {  
            App.fileSize = Convert.ToInt32 (size);  
            byte[] buffer = new byte[App.fileSize];  
            await App.inputStream.ReadAsync (buffer, 0, App.fileSize);  
            string copiedFileName = "test.zip";  
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;  
            StorageFile file = await localFolder.CreateFileAsync (copiedFileName, CreationCollisionOption.ReplaceExisting);  
            await FileIO.WriteBytesAsync (file, buffer);  
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync (CoreDispatcherPriority.Normal, async () => {  
                MessageDialog successMsg = new MessageDialog ("Shared zip file.");  
                successMsg.Title = "Success Message";  
                IAsyncOperation show = successMsg.ShowAsync ();  
                await Task.Delay (TimeSpan.FromSeconds (1));  
                show.Cancel ();  
            });  
        }  
    }  
}  

When I send file size and actual file in one event, it sets file size correctly on the client-side even though file sharing gets corrupted.

How can I send file size and actual data from one event to share the file successfully? Any idea on this is much appreciated.

Thanks

Universal Windows Platform (UWP)
0 comments No comments
{count} votes

Accepted answer
  1. Roy Li - MSFT 33,371 Reputation points Microsoft Vendor
    2019-10-31T01:31:49.187+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    When you transfer a file, you can write the file size directly into the stream. It is recommended to use DataWriter as following:

    writer = new DataWriter(socket.OutputStream);  
    // if we have a StorageFile named file  
    using (var stream=await file.OpenStreamForReadAsync())  
    using(var ms=new MemoryStream())  
    {  
        await stream.CopyToAsync(ms);  
        var bytes = ms.ToArray();  
        writer.WriteUInt32(Convert.ToUInt32(bytes.Length));  
        writer.WriteBytes(ms.ToArray());  
        await writer.StoreAsync();  
    }  
    

    The size of the incoming stream can be pre-read by the DataReader when receiving the file as following:

    var reader = new DataReader(args.Socket.InputStream);  
    try  
    {  
        while (true)  
        {  
            //Read first 4 bytes(length of the subsequent string).  
            uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));  
            if (sizeFieldCount != sizeof(uint))  
            {  
                // The underlying socket was closed before we were able to read the whole data.  
                return;  
            }  
    // Read the string.  
            uint fileLength = reader.ReadUInt32();  
            uint actualFileLength = await reader.LoadAsync(fileLength);  
            if (fileLength != actualFileLength)  
            {  
                // The underlying socket was closed before we were able to read the whole data.  
                return;  
            }  
    var file =await ApplicationData.Current.LocalFolder.CreateFileAsync("test.zip", CreationCollisionOption.ReplaceIfExists);  
            var bytes =new byte[actualFileLength];  
            reader.ReadBytes(bytes);  
              
            await FileIO.WriteBytesAsync(file, bytes);  
        }  
    }  
    catch (Exception exception)  
    {  
        // If this is an unknown status it means that the error is fatal and retry will likely fail.  
          
    }  
      
    

    The above simple code that explains how to combine the file size with the actual content of the file. I hope it will help you.

    Thanks

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.