Considered we have two methods:
Task DownloadFromAToStreamAsync(Stream destinationStream);
Task UploadToBFromStreamAsync(Stream sourceStream);
Now we need to download content from A and upload it to B in a single operation.
One of the solutions:
using (var stream = new MemoryStream())
{
await DownloadFromAToStreamAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
await UploadToBFromStreamAsync(stream);
}
But this solution requires the whole stream content to be loaded in memory.
How to solve the task more efficiently?
Change the Download method to accept an additional size parameter which indicates how much to download. Then loop downloading and uploading untill a download returns an empty stream.
Related
I am writing a discord bot using DSharp plus library.
The command I am currently writing gets an image from the discord chat I then edit the image and send the edited image back as a single frame gif.
I retrieve the image from the image url by using:
HttpClient client = new HttpClient();
Stream stream = await client.GetStreamAsync(attachments[0].Url);
Bitmap image = new Bitmap(System.Drawing.Image.FromStream(stream));
I then call my edit function and edit the image. I then save the image to my files using:
using (var stream = new FileStream("Images/output.gif", FileMode.Create))
{
imgToGif.SaveAsGif(stream);
}
where .SaveAsGif() is a function from the KGySoft.Drawing library I found online.
To send the edited image back I use:
FileStream file = new FileStream("Images/output.gif", FileMode.Open);
DiscordMessageBuilder messagefile = new DiscordMessageBuilder();
messagefile.AddFile(file);
ctx.RespondAsync(messagefile);
But this throws a "The process cannot access the file "Image/output.gif" because it is being used by another process." error.
After some googling I tried to close the FileStream which saves my image to my files using stream.close() or stream.dispose(). The problem however is that I cannot acces the stream again because it will throw the "Cannot acces closed stream error".
I also tried using FileShare.read, FileShare.ReadWrite.
Tried closing both stream and tried to use 1 stream only. So I kept the stream open and used it to send the message in discord chat but that would send a file with 0 bytes in the discord chat.
I think you closed the stream too early while sending the gif
you need to call file.Close() after you call RespondAsync() and you need to change ctx.RespondAsync(messagefile); to await ctx.RespondAsync(messagefile); because RespondAsync() is an asynchronous method if you dont use await rest of the code will continue running so the stream will close while ctx.RespondAsync(messagefile); is still running and it will give an error.
sending a gif part should look like this:
FileStream file = new FileStream("Images/output.gif", FileMode.Open);
DiscordMessageBuilder messagefile = new DiscordMessageBuilder();
messagefile.AddFile(file);
await ctx.RespondAsync(messagefile);
file.Close();
if you have done the rest of the code correct this should work.
I send an audio file to a server API in MultiPartFormData. for this purpose, first, I convert storage File to Byte format, then I convert Byte to Stream and after that I post with MultiPartFormData request.That server answer my request in MultiPartformData format with an another Audio file too.
I receive that respond in HttpResponceMesseage, my question is how can I convert it to mp3 file?
I am using windows iot with UWP coding platform.
multipartContent.Add(new ByteArrayContent(await GetBytesAsync(storageFile)),"audio","audio.mp3");
request.Content = multipartContent;
var response = await httpClient.SendAsync(request);
var content = new StreamReader(await response.Content.ReadAsStreamAsync()).ReadToEnd();
In UWP, if you want to write to a file using stream, we will following the four-step model:
Open the file to get a stream
Get an output stream.
Create a DataWriter object and call the corresponding Write method.
Commit the data in the data writer and flush the output stream.
Please see Create, write, and read a file and Best practices for writing to files for more information.
The official File access sample for your reference.
I done it with extra following code.
first, I convert response to byte[] array, then I write bytes to file within new task thread,that because of main thread correspond to UI won't let another Async task run on it.
var response = await httpClient.SendAsync(request);
byte[] x=await response.Content.ReadAsByteArrayAsync();
await Task.Run(() =>
System.IO.File.WriteAllBytes(storageFile.Path,x));
I have a webapi (asp.net core) that receive a file and post to another webAPI
for now, I create a FileStream , and using HttpClient to Post this file.
But I wonder is that a two way Stream that can replace the FileStream, I mean a Stream that's ReadAsync will wait until it have enough bytes for read's buffer.
var content = new MultipartFormDataContent();
// the problem is here, the stream must be ready for "read to end",
// so I buffered the uploaded file to a FileStream
content.Add(new StreamContent(filestream),"file1","myfilename");
await client.PostAsync("url",content )
How to dispose file stream in api ?
Let assume that I need to call this api 10 times.
[HttpGet("{fileName}")]
public async Task<IActionResult> Get(string fileName)
{
var res = File.Open(path, FileMode.Open);
var file = File(res, "application/zip", fileName);
return file;
}
I can't dispose stream before is returned from api method.
When I call it second time I will get exception:
The process cannot access the file 'C:\test\example.zip' because it is
being used by another process.
First of all, remember about concurrency and thread safety. (many request can pass to your controller at the same time. And in this case if you are writing som,ething to the file - the behaviour of app can be wrong).
If you are not writing to the file (only reading), then you can just specify the sharing mode for other threads like this:
using(var file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
//your code goes here
}
I want to write an Image to a stream and read it afterwards.
Im on Win 10 UWP.
My code:
InMemoryRandomAccessStream imrasIn = new InMemoryRandomAccessStream();
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), imrasIn);
DetectedFaces = await _faceClient.DetectAsync(imrasIn.GetInputStreamAt(0).AsStreamForRead());
It does not work, DetectAsync gets an empty stream (Error: Image size is too small).
Do I need other classes? CapturePhotoToStreamAsync wants an IRandomAccessStream and DetectAsync wants a Stream.
I had to rewind the stream before reading (and after writing to it):
imrasIn.Seek(0);