Is there a way to convert an IAsyncOperation to System.IO.Steam? - c#

I have a list of StorageFiles for my Windows 8 app. I need to submit them to a server via the Stream class. I've tried converting the Storage files like this:
Stream fs = temp[i].OpenAsync(FileAccessMode.Read);
temp[] is the list of StorageFiles that I have containing images. Obviously that code I have doesn't work. The error message suggests I might be missing a cast or something. Is there anyway to convert the StorageFiles or IAsyncOperation to a Stream?

Check if this works:
Stream fs = (await temp[i].OpenAsync(FileAccessMode.Read)).AsStream();
You have all the information in your error message - OpenAsync returns (after you await it) IRandomAccessStream, you can convert it to System.IO.Stream with AsStream method.

Related

How to correctly use streams to retrieve, edit, save and send image via discordbot

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.

How does the UploadObjectAsync() method work?

https://forge.autodesk.com/en/docs/bim360/v1/tutorials/documen-management/upload-document/
I am following the tutorial above to upload a file into a BIM 360 folder through Autodesk Forge. I have reached Step 6: Upload the File to the Storage Object and I am trying to use the method UploadObjectAsync() to upload a file but I am getting an error stating: error getting value from 'ReadTimeout' on 'System.Web.HttpInputStream' and I am unsure how to fix this.
Am I using the wrong method or there something I am missing in the code? Below is the method I am using on .NET.
HttpPostedFile file = req.Files[0];
ObjectsApi objectsApi = new ObjectsApi();
dynamic objects = await objectsApi.UploadObjectAsync(bucketKey, objectName, file.ContentLength, file.InputStream);
Try use the underlying stream of a StreamReader from the file to upload, instead of the raw InputStream from multipart form:
using (StreamReader streamReader = new StreamReader(fileSavePath))
{
await objects.UploadObjectAsync(bucketKey, objectName,(int)streamReader.BaseStream.Length, streamReader.BaseStream, "application/octet-stream");
...
}
Given how the UploadObjectAsync and its chained method UploadObjectAsyncWith(code here) is implemented you'd better saved the posted file and then upload it instead of piping streams. See an example here.

BitmapFrame - No imaging component suitable to complete this operation was found [duplicate]

I'm downloading in image from web to save it locally. It works great with any other image formats but it this method below fails with an argument exception when I try to read a WebP image.
private static Image GetImage(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return Image.FromStream(response.GetResponseStream());
}
catch
{
return null;
}
}
How do you read .webp images in C#?
I found this other question that allows for converting between types but I do not want to do that WebP library for C#
Reason I'm not wanting to do it is because I think it might lose some quality. Besides, I want to know why is this not working.
The base class libraries won't help you to deal with WebP images. However, if you only want to save the received file to the disk, you don't have to even know that you are dealing with a WebP images. You can simply treat the received data as a binary blob and dump it to a file, for example using Stream.CopyTo and a FileStream.
The Content-Type HTTP header will give you the mime type of the file you're downloading, and the Content-Disposition header can provide you with a filename and extension (though you might have to do some parsing). You can access those using HttpWebResponse.ContentType and HttpWebResponse.Headers["Content-Disposition"].
#Trillian nailed it. Here is a code snippet for what I did based on his suggestion. Wanted to add code so not posting this as a comment.
To get just the image file extension, you can do this
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string fileExt = response.ContentType.Replace("image/", string.Empty);
To get the file name with extension, you can do the following and the do parsing like I did above. It just has some more data in it.
response.Headers["Content-Disposition"];
Once you have you file name you want to save as, create a file stream and copy the response stream into it.
FileStream fs = new FileStream(targetPath + fileName, FileMode.Create);
response.GetResponseStream().CopyTo(fs);
Assuming you app has access to the destination, image should get saved. Make sure to add try catch and handle exceptions properly. Also note that FileMode.Create will overwrite if the file already exists!

Uploading string as text file to SkyDrive?

I'm trying to use C# with the Live Connect API to upload a blank (or one that says "test") text file to SkyDrive. The code I have so far:
LiveConnectClient client = await LiveSignin();
string folderID = await getFolder(client);
client.BackgroundUploadAsync(folderID, "pins.txt", "", OverwriteOption.Rename);
where LiveSignin() is a function that handles the sign in code and returns a LiveConnectClient, and getFolder(LiveConnectClient client) is a function that gets the folder ID that I'm trying to upload to.
That code throws an error about the blank string (third parameter on the last line) having to be a "Windows.Storage.Streams.IInputStream", but I can't seem to find any documentation on how to convert a String to an IInputStream, or, for that matter, much of any documentation on "IInputStream" that I can find.
With earlier versions of the Windows Runtime/Live Connect (on another project) I had used:
byte[] byteArray = System.Text.Encoding.Unicode.GetBytes(Doc);
MemoryStream stream = new MemoryStream(byteArray);
App.client.UploadCompleted += client_UploadCompleted;
App.client.UploadAsync(roamingSettings.Values["folderID"].ToString(), docTitle.Text + ".txt", stream);
but that throws a lot of errors now (most of them because UploadAsync has been replaced with BackgroundUploadAsync).
So, is there a way to convert a string to an IInputStream, or do I not even need to use an IInputStream? If my method just doesn't work, how would one upload a blank text file to SkyDrive from a C# Metro app? (developing in Visual Studio 2012 Express on the evaluation of Windows 8 Enterprise, if that makes much of a difference)
EDIT: I finally found "Stream.AsInputStream", but now I'm getting the same error as this
An unhandled exception of type 'System.AccessViolationException'
occurred in Windows.Foundation.winmd
Additional information: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt
the code now:
LiveConnectClient client = await LiveSignin();
string folderID = await getFolder(client);
Stream OrigStream = new System.IO.MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes("test"));
LiveOperationResult result = await client.BackgroundUploadAsync(folderID, "pins.txt", OrigStream.AsInputStream(), OverwriteOption.Rename);
Hi
Had same problem today and as far as I can see the only solution to this problem is to write your text into a local file first and then upload it.
My solution looks like this:
var tmpFile= await ApplicationData.Current.
LocalFolder.CreateFileAsync
("tmp.txt", CreationCollisionOption.ReplaceExisting);
using (var writer = new StreamWriter(await tmpFile.OpenStreamForWriteAsync()))
{
await writer.WriteAsync("File content");
}
var operationResult =
await client.BackgroundUploadAsync(folderId, tmpFile.Name, tmpFile,
OverwriteOption.Overwrite);

Does binarywriter.flush() also flush the underlying filestream object?

I have got a code snippet as follows:
Dim fstream = new filestream(some file here)
dim bwriter = new binarywriter(fstream)
while not end of file
read from source file
bwriter.write()
bwriter.flush()
end while
The question I have is the following. When I call bwriter.flush() does it also flush the fstream object? Or should I have to explicitly call fstream.flush() such as given in the following example:
while not end of file
read from source file
bwriter.write()
bwriter.flush()
fstream.flush()
end while
A few people suggested that I need to call fstream.flush() explicitly to make sure that the data is written to the disk (or the device). However, my testing shows that the data is written to the disk as soon as I call flush() method on the bwriter object.
Can some one confirm this?
According to Reflector, BinaryWriter.Flush calls the Flush method of the underlying stream.

Categories

Resources