Xamarin Forms: File was not saved on the android storage - c#

private async Task DoDownloadFile(ChatMessageListRefDataModel chatMessage)
{
var status = await Permissions.RequestAsync<Permissions.StorageWrite>();
if(status == PermissionStatus.Granted)
{
await HttpRequestHelper.DownloadFile(chatMessage.FileUrl, chatMessage.FileName);
}
}
public static async Task DownloadFile(string url, string fileName) {
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), fileName);
using (var downloadStream = await client.GetStreamAsync(url))
{
using (var memoryStream = new MemoryStream())
{
await downloadStream.CopyToAsync(memoryStream);
using(FileStream file = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
byte[] bytes = new byte[memoryStream.Length];
memoryStream.Read(bytes, 0, (int)memoryStream.Length);
file.Write(bytes, 0, bytes.Length);
memoryStream.Close();
}
}
}
The code produces no error it is just the file was not found on the phone's directory. What could have gone wrong. Thanks.

I have created a new sample to test your code. And meet the same problem as yours. But the problem just appeared on the physical device. When I run it on the andorid emulator, I can find the file by the Android Studio's emulator device file explorer.
The path Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), fileName); seems be hidden. I can't find it by the device's file manager.
So you can try to use the following code to get the path, such as:
var filename1 = Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath;
var filename = System.IO.Path.Combine(filename1, "xxx.txt");
using (System.IO.FileStream os = new System.IO.FileStream(filename, System.IO.FileMode.OpenOrCreate))
{
}
This file path can be found by the device's file manager. You can have a try.

Turns Out the Launcher.OpenAsync(fileUrl) is just okay to me.

Related

C# big filedownload resumable from azure blob storage

I really need some rubber ducking...
I have a file that is at least 2.3 GiB.
I am currently downloading this file to a temp directory.
But when the download is interrupted (connection error, or windows crash) I want the user to resume download where it stopped. And not download the whole file all over again.
The code works in the fact that it continues downloading the file, but I see that the download stream is starting from the beginning again. So that means that the file ends to be (2.3 GiB + the amount bytes that were downloaded previously), which ofc corrupts my file.
I used the following snippet to resume downloading, so I hoped the stream would resume, where it stopped
localStream.Seek(positionInFile, SeekOrigin.Begin);
Any ideas on what I am missing here?
Here is my code.
BlobContainerClient containerClient = new BlobContainerClient(connectionString, container);
var blobClient = containerClient.GetBlobClient(downloadFile);
fullOutputPath = createOutputFilePath(updateFileUri.OriginalString, outputFolder);
downloadFileInfo = new FileInfo(fullOutputPath);
var response = blobClient.Download(cts.Token);
contentLength = response.Value.ContentLength;
if (contentLength.HasValue && contentLength.Value > 0)
{
if (_fileSystemService.FileExists(fullOutputPath))
{
from = downloadFileInfo.Length;
to = contentLength;
if (from == to)
{
//file is already downloaded
//skip it
progress.Report(1);
return;
}
fileMode = FileMode.Open;
positionInFile = downloadFileInfo.Length;
}
using FileStream localStream = _fileSystemService.CreateFile(fullOutputPath, fileMode, FileAccess.Write);
localStream.Seek(positionInFile, SeekOrigin.Begin);
bytesDownloaded = positionInFile;
double dprog = ((double)bytesDownloaded / (double)(contentLength.Value + positionInFile));
do
{
bytesRead = await response.Value.Content.ReadAsync(buffer, 0, buffer.Length, cts.Token);
await localStream.WriteAsync(buffer, 0, bytesRead, cts.Token);
await localStream.FlushAsync();
bytesDownloaded += bytesRead;
dprog = ((double)bytesDownloaded / (double)(contentLength.Value + positionInFile));
progress.Report(dprog);
} while (bytesRead > 0);
}
I did some test for you, in my case, I use a .txt file to demo your requirement. You can see the .txt file here.
As you can see, at line 151, I made an end mark:
I also created a local file that ends with this end mark to emulate that download is interrupted and we will continue to download from storage:
This is my code for fast demo below:
static void Main(string[] args)
{
string containerName = "container name";
string blobName = ".txt file name";
string storageConnStr = "storage account conn str";
string localFilePath = #"local file path";
var localFileStream = new FileStream(localFilePath, FileMode.Append);
var localFileLength = new FileInfo(localFilePath).Length;
localFileStream.Seek(localFileLength, SeekOrigin.Begin);
var blobServiceClient = new BlobServiceClient(storageConnStr);
var blobClient = blobServiceClient.GetBlobContainerClient(containerName).GetBlobClient(blobName);
var stream = blobClient.Download(new Azure.HttpRange(localFileLength)).Value.Content;
var contentStrting = new StreamReader(stream).ReadToEnd();
Console.WriteLine(contentStrting);
localFileStream.Write(Encoding.ASCII.GetBytes(contentStrting));
localFileStream.Flush();
}
Result:
We only downloaded the content behind the end mark:
Content has been downloaded to local .txt file:
Pls let me know if you have any more questions.

Certain big '.xlsx' extension files failed to open after downloaded via SftpClient

I am trying to download file from a remote linux server to my local computer using SftpClient.
Here is my code to download the file
public MemoryStream DownloadFile2(string path)
{
var connectionInfo = _taskService.GetBioinformaticsServerConnection();
MemoryStream fileStream = new MemoryStream();
using (SftpClient client = new SftpClient(connectionInfo))
{
client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(200);
client.Connect();
client.DownloadFile(path, fileStream);
fileStream.Seek(0, SeekOrigin.Begin);
var response = new MemoryStream(fileStream.GetBuffer());
return fileStream;
}
}
And here is the controller that called above method.
public FileResult DownloadFile(string fullPath, string fileName)
{
if (!string.IsNullOrEmpty(fileName))
{
fullPath = string.Concat(fullPath, "/", fileName);
}
var ms = _reportAPI.DownloadFile2(fullPath);
var ext = Path.GetExtension(fullPath);
if (ext == ".xlsx")
{
return File(ms, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
}
return File(ms, "application/octet-stream", fileName);
}
I have manage to do it for most of the files, however for certain large '.xlsx' extension files, when I tried to open it, for some reason, I received below error.
If I am on IISExpress, I still manage to open it after I clicked on 'Yes' button, but if I'm using the normal IIS, it failed to open the file after clicked on 'Yes' button.
For other type of files or smaller excel files, it works as expected.
Any idea how can I modified my code to solve this issue?
I was able to resolve this by modifying my code as below
public MemoryStream DownloadFile2(string path)
{
var connectionInfo = _taskService.GetBioinformaticsServerConnection();
MemoryStream fileStream = new MemoryStream();
byte[] fileBytes = null;
using (SftpClient client = new SftpClient(connectionInfo))
{
client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(200);
client.Connect();
client.DownloadFile(path, fileStream);
fileBytes = fileStream.ToArray();
var response = new MemoryStream(fileBytes);
return response;
}
}

Xamarin Forms Image to Stream

My goal is to take an embedded image which is saved in each project's image folder, stream it, convert it to a byte array and save it to the device's local storage file system using PCLStorage. The part which I cannot figure out is how to stream from the embedded image.
var embeddedImage = new Image { Aspect = Aspect.AspectFit };
embeddedImage.Source = ImageSource.FromResource("applicationIcon.png");
then I could stream it if I had the path, or I could convert it to a byte [] if I had a stream. The code below does not work because the file source is not found (obviously).
string localFileUri = string.Empty;
// Get hold of the file system.
IFolder localFolder = FileSystem.Current.LocalStorage;
IFile file = await FileSystem.Current.GetFileFromPathAsync("applicationIcon.png");
using (Stream stream = await file.OpenAsync(FileAccess.Read))
{
using (var ms = new MemoryStream())
{
var byteArray = ms.ToArray();
var storeragePath = await iStorageService.SaveBinaryObjectToStorageAsync(string.Format(FileNames.ApplicationIcon, app.ApplicationId), byteArray);
app.IconURLLocal = storeragePath;
}
}
The only option seems to be to use some kind of resource locator, and then maintain that code for each type of project you add. Not very elegant. Is there another way?
First off, thank you to deckertron_9000 for putting me on the right path to figuring it out, and secondly these two links:
http://www.itgo.me/a/3956119637998661919/xamarin-forms-how-to-load-an-image-from-resources-into-a-byte-array
Xamarin Forms: How to use Embedded Resources in PCL Project for Image
In the end, this is what worked for me:
Firstly I added the image to a folder in my PCL. Then I made sure to change the image's Build Action to Embedded Resource.
Secondly, I added using System.Reflection;
Thirdly, this code worked for me:
string imagePath = "NameOfProject.Assets.applicationIcon.png";
Assembly assembly = typeof(NameOfClass).GetTypeInfo().Assembly;
byte[] buffer;
using (Stream stream = assembly.GetManifestResourceStream(imagePath))
{
long length = stream.Length;
buffer = new byte[length];
stream.Read(buffer, 0, (int)length);
var storeragePath = await iStorageService.SaveBinaryObjectToStorageAsync(string.Format(FileNames.ApplicationIcon, app.ApplicationId), buffer);
app.IconURLLocal = storeragePath;
}
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await App.CurrentApp.MainPage.DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
_mediaFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg"
});
if (_mediaFile == null)
return;
//ViewModel.StoreImageUrl(file.Path);
await App.CurrentApp.MainPage.DisplayAlert("Snap", "Your photo have been added to your Items collection.", "OK");
ImageSource = ImageSource.FromStream(() =>
{
var stream = _mediaFile.GetStream();
_mediaFile.Dispose();
return stream;
});

How do I write a binary file in a Windows Store App?

I'm trying to implement a StreamSocket communication and the server is now sending me a ".zip" file in byte[] chuncks. It looks like my byte[] in memory is fine (amount of bytes are the same as original .zip file in the server) but when I save those bytes in a file the unzip program says it's 'corrupted'.
I've tried several options but none of them worked for me:
1
var file = await StorageFile.CreateFileAsync();
using(var stream = await file.OpenStreamForWriteAsync())
{
stream.Write(myBytes, ...);
}
2
var file = await StorageFile.CreateFileAsync();
await FileIO.WriteBytesAsync(file, myBytes);
3
var file = await StorageFile.CreateFileAsync();
using (var fileStream = await file.OpenStreamForWriteAsync())
{
var sessionData = new MemoryStream(myBytes);
sessionData.Seek(0, SeekOrigin.Begin);
await sessionData.CopyToAsync(fileStream);
}
4
var file = await StorageFile.CreateFileAsync();
using (var writer = new BinaryWriter(await file.OpenStreamForWriteAsync())
{
writer.WriteBytes(myBytes);
}
If anyone has some new ideas please share.
Regards.

Amazon S3 Save Response Stream

I am trying to load a .gz file out of a bucket.
Connection and authentication work finde, I even do get a file, but the problem is, the file is a lot bigger then the file should be. it is, original size, 155MB within the bucket but when it comes onto my hard disk it gets up to about 288MB
here is the function code:
public bool SaveBucketToFile(string Filename)
{
//Response check into file
using (StreamReader StRead = new StreamReader(_ObjResponse.ResponseStream))
{
string TempFile = Path.GetTempFileName();
StreamWriter StWrite = new StreamWriter(TempFile, false);
StWrite.Write(StRead.ReadToEnd());
StWrite.Close();
StRead.Close();
// Move to real destination
if (File.Exists(Filename))
{
File.Delete(Filename);
}
File.Move(TempFile, Filename);
}
return true;
}
the download and filling of _ObjResponse is made over usage of the AmazonS3 Client from their SDK. I am using a proxy but the same code on a different machine without proxy brings back the same result.
Any hints what to do here? the object request is simple:
_ObjRequest = new GetObjectRequest
{
BucketName = BucketName,
Key = Key
};
glad for any help...
for everyone to stumble upon this.
I needed to first save the stream via bufferedStream into a memorystream.
the code looks like this:
MemoryStream MemStream = new MemoryStream();
BufferedStream Stream2 = new BufferedStream(_ObjResponse.ResponseStream);
byte[] Buffer = new byte[0x2000];
int Count;
while ((Count = Stream2.Read(Buffer, 0, Buffer.Length)) > 0)
{
MemStream.Write(Buffer, 0, Count);
}
// Pfad auslesen
string TempFile = Path.GetTempFileName();
//Stream zum Tempfile öffnen
FileStream Newfile = new FileStream(TempFile,FileMode.Create);
//Stream wieder auf Position 0 ziehen
MemStream.Position = 0;
// in Tempdatei speichern
MemStream.CopyTo(Newfile);
Newfile.Close();
// Endgültigen Speicherpunkt prüfen und Tempdatei dorthin schieben
if (File.Exists(Filename))
{
File.Delete(Filename);
}
File.Move(TempFile, Filename);
I found this somewhere here:
http://www.codeproject.com/Articles/186132/Beginning-with-Amazon-S under the Caption "Get a file from Amazon S3"

Categories

Resources