Share a large file between two UWP apps using Stream Sockets

Fei Xue - MSFT 1,111 Reputation points

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

Locked Question. You can vote on whether it's helpful, but you can't add comments or replies or follow the question.

0 comments No comments

Answer accepted by question author

Anonymous

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

0 comments No comments

1 additional answer

  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more