How to save existing StorageFile using FileSavePicker? - c#

I'm trying to save existing file to another place. It's some kind of copy, but I want to allow choosing of new destination to user with FileSavePicker.
Here is my code:
StorageFile currentImage = await StorageFile.GetFileFromPathAsync(item.UniqueId);
var savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add("JPEG-Image",new List<string>() { ".jpg"});
savePicker.FileTypeChoices.Add("PNG-Image", new List<string>() { ".png" });
savePicker.SuggestedSaveFile = currentImage;
savePicker.SuggestedFileName = currentImage.Name;
var file = await savePicker.PickSaveFileAsync();
After that the file will be created, but it empty (0 KB). How to save file correctly?

I found the solution and it's a little bit different than presumed above. It is based on copying and writing of byte arrays.
var curItem = (SampleDataItem)flipView.SelectedItem;
StorageFile currentImage = await StorageFile.GetFileFromPathAsync(curItem.UniqueId);
byte[] buffer;
Stream stream = await currentImage.OpenStreamForReadAsync();
buffer = new byte[stream.Length];
await stream.ReadAsync(buffer, 0, (int)stream.Length);
var savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add("JPEG-Image",new List<string>() { ".jpg"});
savePicker.FileTypeChoices.Add("PNG-Image", new List<string>() { ".png" });
savePicker.SuggestedSaveFile = currentImage;
savePicker.SuggestedFileName = currentImage.Name;
var file = await savePicker.PickSaveFileAsync();
if (file != null)
{
CachedFileManager.DeferUpdates(file);
await FileIO.WriteBytesAsync(file, buffer);
CachedFileManager.CompleteUpdatesAsync(file);
}
Why this way is better than CopyAsync() method of StorageFile?
StorageFile methods allow to write files only to folders that specified in appxmanifest. Direct writing to the file that was selected by PickSaveFileAsync() allows to create a file at any place that user want (if he has write access to that folder of course). I checked this and it really works.
Hope, it will help other developers if they will face with this issue.

You should use FolderPicker see this http://lunarfrog.com/blog/2011/10/07/winrt-file-and-folder-pickers/ and then use CopyAsync() or MoveAsync() methods of StorageFile.

Related

File path when uploading files through OneDrive SDK

Use the OneDrive SDK to upload files.
At this time, you have to pass the file path, but uploading using the code takes a long time.
Can I upload files even if I pass the temporary file path?
Currently I get the file path after saving the file to the server.
In this case, an issue arises from speed problems.
Is there any way to look at the temporary file path?
public async Task<JObject> UploadLargeFiles(string upn, IFormFile files)
{
var jObject = new JObject();
int fileSize = Convert.ToInt32(files.Length);
var folderName = Path.Combine("wwwroot", "saveLargeFiles");
var pathToSave = Path.Combine(System.IO.Directory.GetCurrentDirectory(), folderName);
var fullPath = "";
if (files.Length > 0)
{
var fileName = files.FileName;
fullPath = Path.Combine(pathToSave, fileName);
using (var stream = new FileStream(fullPath, FileMode.Create))
files.CopyTo(stream);
}
var filePath = fullPath;
var fileStream = System.IO.File.OpenRead(filePath);
GraphServiceClient client = await MicrosoftGraphClient.GetGraphServiceClient();
var uploadProps = new DriveItemUploadableProperties
{
ODataType = null,
AdditionalData = new Dictionary<string, object>
{
{ "#microsoft.graph.conflictBehavior", "rename" }
}
};
var item = this.SelectUploadFolderID(upn).Result;
var uploadSession = await client.Users[upn].Drive.Items[item].ItemWithPath(files.FileName).CreateUploadSession(uploadProps).Request().PostAsync();
int maxChunkSize = 320 * 1024;
var uploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, fileStream, maxChunkSize);
var response = await uploadTask.UploadAsync();
if (response.UploadSucceeded)
{
return
}
else
{
return null;
}
}
Your server's disk is probably not what makes this slow. By default, uploaded files are stored in a temporary directory, which you can save permanently by using CopyTo(FileStream) like you do.
You can skip this step and call IFormFile.OpenReadStream() to obtain a stream to the temporary file, then pass that to the LargeFileUploadTask.
Point is, it's probably the uploading to OneDrive that takes the largest amount of time. Depending on your setup, you may want to save files into a queue directory (the temp file gets deleted after the request completes), and have a background service read that queue and upload them to OneDrive.

uploading a file from local folder to firebase

I am having trouble uploading files(.mp3) stored in the local folder by user to firebase.
This is how a file is retrieved from local folder:
StorageFolder folder = ApplicationData.Current.LocalFolder;
var songfolder = await folder.GetFolderAsync("Songs");
StorageFile mp3file = await songfolder.GetFileAsync(mp3fileforupload);
And this is how I create a stream file of the file and upload:
var stream = File.Open(mp3file.Path, FileMode.Open);
var task = new FirebaseStorage("-my-bucket-.appspot.com")
.Child("songs")
.Child(new_song_id)
.PutAsync(stream);
task.Progress.ProgressChanged += (s, f) => uploadProgress(f.Percentage);
var downloadurl = await task;
Debug.WriteLine("DOWNLOAD_URL " + downloadurl);
The file fails to upload. From the Step-up-labs documentation, the file should be uploaded as a stream of a file. This worked when uploading files from the Assets folder, but does not work with files from local folder. I have tried uploading from the MostRecentlyUsedList but it still fails to upload. Any idea why this is failing?
Try this instead to open the file
Windows.Storage.StorageFolder storageFolder =
Windows.Storage.ApplicationData.Current.LocalFolder;
Windows.Storage.StorageFile sampleFile =
await storageFolder.GetFileAsync(mp3file.Path);
var stream = await sampleFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
The Step-Up-Labs C# Firebase-Storage API uses Stream for file uploads. Files should be uploaded as a Stream. What has worked for me is using a Memory Stream.
First I retrieved the file from local folder:
StorageFolder folder = ApplicationData.Current.LocalFolder;
var songfolder = await folder.GetFolderAsync("Songs");
StorageFile mp3file = await songfolder.GetFileAsync(mp3fileforupload);
Then I read the bytes of the file using a DataReader:
byte[] fileBytes = null;
using (IRandomAccessStreamWithContentType stream = await mp3file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (DataReader reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
Then I used a MemoryStream for the upload:
Stream stream = new MemoryStream(fileBytes);
var task = new FirebaseStorage("-my-bucket-.appspot.com")
.Child("songs")
.Child(new_song_id)
.PutAsync(stream);
task.Progress.ProgressChanged += (s, f) => uploadProgress(f.Percentage);
var downloadurl = await task;
That did the trick. The file uploaded.

Windows Phone 8.1 Writing to File Not Working

I am writing text to a file in Windows Phone 8.1 like this:
private static async Task WriteData(String fileName, String content)
{
Byte[] data = Encoding.Unicode.GetBytes(content);
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (var s = await file.OpenStreamForWriteAsync())
{
await s.WriteAsync(data, 0, data.Length);
}
}
But when I read the file, it comes back empty. I have verified that there isn't some other method overwriting it by reading from the file immediately after I write to it. Am I missing something obvious here?
Maybe you can try:
public async Task SaveStreamToFile(Stream streamToSave, string fileName, CancellationToken cancelToken)
{
Byte[] buf= Encoding.Unicode.GetBytes(content);
var folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream fileStram = await file.OpenStreamForWriteAsync())
{
int bytesread = 0;
while ((bytesread = await streamToSave.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
{
await fileStram.WriteAsync(buf, 0, bytesread);
cancelToken.ThrowIfCancellationRequested();
}
}
}
I was having the same problem. I save 2 files, one with debug information, and one with application specific information (a list of routes).The debug information seems to work OK
StorageFolder local = ApplicationData.Current.LocalFolder;
var file = await local.CreateFileAsync "debug.txt",CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(file, sbDebugInformation.ToString());
but the CreateCollisionOption.ReplaceExisting seemed to be causing problems with the other information, and I ended up with this, after many alternate attempts
StorageFolder local = ApplicationData.Current.LocalFolder;
var json = new DataContractJsonSerializer(typeof(RouteList));
var file = await local.CreateFileAsync(filename,CreationCollisionOption.OpenIfExists);
MemoryStream stream = new MemoryStream();
json.WriteObject(stream, routes);
await FileIO.WriteBytesAsync(file, stream.ToArray());

OneDrive Downloaded *.jpeg Image File Corrupt in Windows Phone 8

I'm doing a backup of my app database to OneDrive. The database records refer to images that are stored in isolated storage. I backup those images too. The database files.
The destinations of the backup file is:
me/skydrive/my_documents/MyCompany/MyApp/MyBackup.bak
The destination of the jpg image files is
me/skydrive/my_documents/MyCompany/MyApp/MyBackup Images/*.jpg
The database restores fine, but the images don't. I've verified that the image is backed up properly on SkyDrive - I can see it and open it fine from SkyDrive. However, when I restore, the file is corrupt. Here's the code I use to restore:
dynamic cmpFolder = await oneDrive.FindFolder("MyCompany", "me/skydrive/my_documents");
dynamic appFolder = await oneDrive.FindFolder(AppName, cmpFolder.id);
string imagesFileName = Path.GetFileNameWithoutExtension(selectedFile.FileName) + " Images";
dynamic imgFolder = await oneDrive.FindFolder(imagesFileName, appFolder.id);
dynamic fileList = await oneDrive.FindFiles(imgFolder.id);
foreach (var fileData in fileList.data)
{
string fileName = fileData.name;
var file =
await wilFolder.CreateFileAsync(
Path.GetFileName(fileName), CreationCollisionOption.ReplaceExisting);
var result = await client.BackgroundDownloadAsync(selectedFile.FileID +
"/content/", new Uri(#"\shared\transfers\" + fileName, UriKind.Relative));
}
Using ISETool and viewing \shared\transfers, I can see that the file is no longer readable. It's size is about 128k, whereas the original image was much larger.
I've also tried this, which was my original code until I began seeing the problem:
var downloadResult = await client.DownloadAsync(selectedFile.FileID + "/content/");
using (Stream oneDriveStream = downloadResult.Stream)
{
oneDriveStream.Position = 0;
byte[] imageBytes = new byte[oneDriveStream.Length];
int count = oneDriveStream.Read(imageBytes, 0, imageBytes.Length);
using (var s = await file.OpenStreamForWriteAsync())
{
oneDriveStream.CopyTo(s);
// and tried this
//s.Write(imageBytes, 0, imageBytes.Length);
}
}
For reference, here's the FindFolder and FindFiles implementations:
public async Task<dynamic> FindFiles(string folderName)
{
LiveOperationResult filesResult = await client.GetAsync(folderName + "/files");
dynamic files = filesResult.Result;
return files;
}
public async Task<dynamic> FindFolder(string folderName, string parentFolder)
{
LiveOperationResult folderResult = await client.GetAsync(parentFolder + "/files?filter=folders");
dynamic folders = folderResult.Result;
foreach (var folder in folders.data)
if (folder.name == folderName)
return folder;
return null;
}
How do I successfully download *.jpg images from my OneDrive folder?
Try this for your download path instead:
var downloadResult = await client.DownloadAsync(selectedFile.FileID + "/picture?type=full");

Rotating images in WinRT

I have a Windows 8 app in which I want to rotate an image file.
In shot, I want to open an image file, rotate it and save the content back to the file.
Is that possible in WinRT? If so, how? Thanks.
Update:
Base on Vasile's answer, I could do some work on this. However I'm not sure what to do next:
public static async Task RotateImage(StorageFile file)
{
if (file == null)
return;
var data = await FileIO.ReadBufferAsync(file);
// create a stream from the file
var ms = new InMemoryRandomAccessStream();
var dw = new DataWriter(ms);
dw.WriteBuffer(data);
await dw.StoreAsync();
ms.Seek(0);
// find out how big the image is, don't need this if you already know
var bm = new BitmapImage();
await bm.SetSourceAsync(ms);
// create a writable bitmap of the right size
var wb = new WriteableBitmap(bm.PixelWidth, bm.PixelHeight);
ms.Seek(0);
// load the writable bitpamp from the stream
await wb.SetSourceAsync(ms);
wb.Rotate(90);
//How should I save the image to the file now?
}
Ofcourse it is possible. You can do it yourself with a pixel manipulation and create a new WriteableBitmapObject or, you could reuse the already implemented functionality from the WriteableBitmapEx (WriteableBitmap Extensions). You can get it via NuGet.
Here you can find a description of the implemented functionality which it offers, and few short samples.
Use this to save WriteableBitmap to StorageFile
private async Task<StorageFile> WriteableBitmapToStorageFile(WriteableBitmap writeableBitmap)
{
var picker = new FileSavePicker();
picker.FileTypeChoices.Add("JPEG Image", new string[] { ".jpg" });
StorageFile file = await picker.PickSaveFileAsync();
if (file != null && writeableBitmap != null)
{
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId, stream);
Stream pixelStream = writeableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
(uint)writeableBitmap.PixelWidth, (uint)writeableBitmap.PixelHeight, 96.0, 96.0, pixels);
await encoder.FlushAsync();
}
return file;
}
else
{
return null;
}
}

Categories