UWP how to get access to file in folder - file

Help me please, I can't get access to file which I choose by FileOpenPicker.
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.Desktop;
openPicker.CommitButtonText = "Открыть";
openPicker.FileTypeFilter.Add(".xlsx");
var file = await openPicker.PickSingleFileAsync();
using (FileStream fs = new FileStream(file.Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
}
What is wrong?

Because of how UWP sandboxes access to the filesystem, you can't construct a FileStream directly from a StorageFile's path. Instead, you have a few options, in order from simplest to most complex:
1) If your file is small enough, you can just use the helpers in the FileIO static class to read it all at once:
string text = await FileIO.ReadTextAsync(file); // or ReadLinesAsync or ReadBufferAsync, depending on what you need
2) Use the OpenAsync() method on StorageFile:
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read, StorageOpenOptions.AllowReadersAndWriters))
{
// your reading code here
}
If you need to, you can convert between IRandomAccessStream and .NET Streams with the AsStream(), AsStreamForRead() and AsStreamForWrite() extension methods on IRandomAccessStream, the docs for which are here.
3) If you want complete control, you can get a SafeFileHandle to the underlying file using CreateSafeFileHandle(), like so:
SafeFileHandle fileHandle = file.CreateSafeFileHandle(FileAccess.Read, FileShare.ReadWrite);
You can then use this file handle to create a standard FileStream:
using (FileStream fs = new FileStream(fileHandle, FileAccess.Read))
{
// Read stuff here
}
This is the only way to reliably use a FileStream on a UWP StorageFile, and should be used with some caution. The official docs have more details on the implications of doing this.

FileOpenPicker gives you a StorageFile which wraps the opened files and gives you permission to it. This doesn't give you access to the file in general - e.g. you cannot use its Path only to open it with a FileStream. Instead, you need to use the respective Windows.Storage APIs to do this. I usually use the OpenStreamForReadAsync extension method. Add using System.IO to the file header and then:
var stream = await file.OpenStreamForReadAsync();
This method returns a System.IO.Stream which you can use with classic System.IO-enabled APIs.

Please avoid use file Path to access file stream in UWP platform, if you have get the file with FileOpenPicker. You could get the file stream with following.
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.Desktop;
openPicker.CommitButtonText = "Открыть";
openPicker.FileTypeFilter.Add(".xlsx");
var file = await openPicker.PickSingleFileAsync();
if (file != null)
{
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
}
And if you need use stream in System.IO namespace. please call AsStream method for IRandomAccessStream object.
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
System.IO.Stream iostream = stream.AsStream();
For more detail please refer this official document.

Related

Folder acess denied wpf

I am opening a FileDialog, to let the user select an Audio file, in an MP3 file, and convert it to WAV, the error appears when I am trying to save the file in a new folder that I am creating
var dlg = new OpenFileDialog
{
DefaultExt = ".mp3",
Filter = "Audio files (.mp3)|*.mp3"
};
var res = dlg.ShowDialog();
if (res! == true)
{
var projectPath = Directory.GetParent(Directory.GetCurrentDirectory())?.Parent?.Parent?.FullName;
var FoderName = Path.Combine(projectPath!, "Audios");
Directory.CreateDirectory(FoderName);
using (var mp3 = new Mp3FileReader(dlg.FileName))
{
using (var ws = WaveFormatConversionStream.CreatePcmStream(mp3))
{
WaveFileWriter.CreateWaveFile(FoderName, was) // Error
System.UnauthorizedAccessException: 'Access to the path
'C:\XXX\XXX\XXX\XXX\XXX\XXX' is denied.'
}
}
Thanks
Inside some folders including "Program Files", an app usually has no permission to write a file. Therefore, it is recommended to use a folder dedicated for a specific purpose and made available for apps (you can get path to "Music" by Environment.GetFolderPath(Environment.SpecialFolder.MyMusic).
In general, an app must expect UnauthorizedAccessException when attempting to write a file and prepare a fallback for the case of that exception.

Save file to device with memorystream

I was wondering if it is possible with xamarin.forms to download any type of file to the device.. de files are stored on Azure, i get a Memorystream of the file, its very important for my app. my question excists of 2 parts actually,
how to download de file to the device of the user?,
and how to show the file of Any type in a default application of the type ( like pdf reader)
this is what i tried
MemoryStream memoryStream = AzureDownloader.DownloadFromAzureBlobStorage(null, doc.azure_container, doc.file_path, ref filen, true);
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string localFilename = doc.filename;
string localPath = Path.Combine(documentsPath, localFilename);
File.WriteAllBytes(localPath, memoryStream.ToArray()); // this is a try to save to local storage
any help appreciated
how to download the file to the device of the user?
Use PCLStorage as its cross-platform and would work for iOS and Android:
public async Task CreateRealFileAsync()
{
// get hold of the file system
IFolder rootFolder = FileSystem.Current.LocalStorage;
// create a folder, if one does not exist already
IFolder folder = await rootFolder.CreateFolderAsync("MySubFolder", CreationCollisionOption.OpenIfExists);
// create a file, overwriting any existing file
IFile file = await folder.CreateFileAsync("MyFile.txt", CreationCollisionOption.ReplaceExisting);
// populate the file with some text
await file.WriteAllTextAsync("Sample Text...");
}
how to show the file of Any type in a default application of the type
( like pdf reader)
this is too broad and could have several solutions depending on what exactly you want to achieve.
Hope this helps

Copying a file to the root path in Codename One

In my code I am prompting the user to load a json file.
I am then attempting to copy this file into an sqlite database.
Once I have the data I am then able to manipulate it as needed - but I need to get it there in the first place.
So step 1 is to get the data in.
I have progressed as far as prompting the user to navigate to the file they want - but when I try and read the file I get this error ..
ERROR: resources must reside in the root directory thus must start with a '/' character in Codename One! Invalid resource: file:///tmp/temp3257201851214246357..json
So I think that I need to copy this file to the root directory
I cannot find a link that shows me how to do this.
Here is my code so far ...
case "Import Script":
try
{
JSONParser json = new JSONParser();
if (FileChooser.isAvailable()) {
FileChooser.showOpenDialog(".json", e2-> {
String file = (String)e2.getSource();
if (file == null) {
home.add("No file was selected");
home.revalidate();
} else {
home.add("Please wait - busy importing");
home.revalidate();
String extension = null;
if (file.lastIndexOf(".") > 0) {
extension = file.substring(file.lastIndexOf(".")+1);
}
if ("json".equals(extension)) {
FileSystemStorage fs = FileSystemStorage.getInstance();
try {
InputStream fis = fs.openInputStream(file);
try(Reader r = new InputStreamReader(Display.getInstance().getResourceAsStream(getClass(), file), "UTF-8"))
{
Map<String, Object> data = json.parseJSON(r);
Result result = Result.fromContent(data);
...... I progress from here
The error is occurring on this line ...
try(Reader r = new InputStreamReader(Display.getInstance().getResourceAsStream(getClass(), file), "UTF-8"))
If I hard code a filename and manually place it in the /src folder it works ... like this ...
try(Reader r = new InputStreamReader(Display.getInstance().getResourceAsStream(getClass(), '/test.json'), "UTF-8"))
But that defeats the purpose of them selecting a file
Any help would be appreciated
Thanks
I suggest watching this video.
It explains the different ways data is stored. One of the core sources of confusion is the 3 different ways to store files:
Resources
File System
Storage
getResourceAsStream returns a read only path that's physically embedded in the jar. It's flat so all paths to getResourceAsStream must start with / and must have only one of those. I would suggest avoiding more than one . as well although this should work in theory.
The sqlite database must be stored in file system which is encapsulated as FileSystemStorage and that's really the OS native file system. But you can't store it anywhere you want you need to give the DB name to the system and it notifies you where the file is stored and that's whats explained in the code above.

How do I append to a file in an Azure storage file share?

I want to write entries to a log file stored in Azure file storage. I currently have this:
var log = "My log entry";
var client = _storageAccount.CreateCloudFileClient();
var share = client.GetShareReference(Config.LogShare);
share.CreateIfNotExists();
var root = share.GetRootDirectoryReference();
var logfile = root.GetFileReference("log.txt");
if (!logfile.Exists()) logfile.Create(0);
// What goes here to append to the file...?
I can see plenty of examples of how to do this with Blobs, or how to upload an entire file, but how do I just append to an existing file?
I have tried this:
var buffer = Encoding.GetEncoding("UTF-8").GetBytes(log.ToCharArray());
using (var fileStream = logfile.OpenWrite(0)) {
fileStream.Write(buffer, (int)logfile.Properties.Length, buffer.Length);
}
But then I get this error:
The remote server returned an error: (416) The range specified is invalid for the current size of the resource..
I managed to work this out myself. You just need to increase the size of the file by the number of new bytes you want to write to it, and then write the new data to that new empty space at the end of the file, like this:
var client = _storageAccount.CreateCloudFileClient();
var share = client.GetShareReference(Config.LogShare);
share.CreateIfNotExists();
var root = share.GetRootDirectoryReference();
var logfile = root.GetFileReference("log.txt");
if (!logfile.Exists()) logfile.Create(0);
var buffer = Encoding.UTF8.GetBytes($"{log}\r\n");
logfile.Resize(logfile.Properties.Length + buffer.Length);
using (var fileStream = logfile.OpenWrite(null)) {
fileStream.Seek(buffer.Length * -1, SeekOrigin.End);
fileStream.Write(buffer, 0, buffer.Length);
}
You can do this with blobs https://blogs.msdn.microsoft.com/windowsazurestorage/2015/04/13/introducing-azure-storage-append-blob/
Shame it doesn't work with files too
Azure file storage REST API doesn't support appending to an existing file. To achieve this, please mount the file share to your machine as a drive, and append to the file just like simple local files.
Actually, I don't think you really need appending functionality per your code above. You can specify the file size in CloudFile.OpenWrite() / CloudFile.Create(), or try CloudFile.UploadFromStream() instead of CloudFile.OpenWrite().
This error could also be due to multi-threaded access.
I bet if you tried to lock the file before you access it, you will not face this problem.
There are many ways to update the file.
Since you already managed to get the share, the root, the folder and the file.. Here is a portion of my code that worked for me.
if (!fileLock.IsWriteLockHeld) fileLock.EnterWriteLock();
try
{
using (var stream = new MemoryStream(content, false))
{
file.UploadFromStream(stream, null, options);
}
}
catch (Exception ex)
{
File.AppendAllText(FileName, ex.ToString());
}
finally
{
if (fileLock.IsWriteLockHeld)
fileLock.ExitWriteLock();
}
Where fileLock is declared as:
protected ReaderWriterLockSlim fileLock = new ReaderWriterLockSlim();
Having said that, I am not saying that this is the best way ever to do it.
The two things I would like you to keep in mind :
1-Lock the resource that is likely to be accessed by more than one thread (That is so common in AZURE)
2- Get familiar with asynchronous methods that Azure provides.. use them when they suit well.
Coming back to your original problem about appending to the existing file..
All the methods of the CloudFile will overwrite the existing file. Cloud Files are not for frequent writing, and they indeed impact performance if you keep writing on them frequently, add the lock impact on performance, they will be horrible.
Cloud files are meant to store big bulk of data once and for all, if you want to add another bulk you have the choice of creating another file.
Have all your data with the client till they reach some size and create an algorith to select the file name and upload them all at once.

Sharepoint 2010 Upload file using Silverlight 4.0

I am trying to do a file upload from Silverlight(Client Object Model) to Sharepoint 2010 library.. Please see the code below..
try{
context = new ClientContext("http://deepu-pc/");
web = context.Web;
context.Load(web);
OpenFileDialog oFileDialog = new OpenFileDialog();
oFileDialog.FilterIndex = 1;
oFileDialog.Multiselect = false;
if (oFileDialog.ShowDialog().Value == true)
{
var localFile = new FileCreationInformation();
localFile.Content = System.IO.File.ReadAllBytes(oFileDialog.File.FullName);
localFile.Url = System.IO.Path.GetFileName(oFileDialog.File.Name);
List docs = web.Lists.GetByTitle("Gallery");
context.Load(docs);
File file = docs.RootFolder.Files.Add(localFile);
context.Load(file);
context.ExecuteQueryAsync(OnSiteLoadSuccess, OnSiteLoadFailure);
}
}
catch (Exception exp)
{
MessageBox.Show(exp.ToString());
}
But I am getting the following error
System.Security.SecurityException: File operation not permitted. Access to path '' is denied.
at System.IO.FileSecurityState.EnsureState()
at System.IO.FileSystemInfo.get_FullName()
at ImageUploadSilverlight.MainPage.FileUpload_Click(Object sender, RoutedEventArgs e)
Any help would be appreciated
Thanks
Deepu
Silverlight runs with very restricted access to the client user's filesystem. When using an open-file dialog, you can get the name of the selected file within its parent folder, the length of the file, and a stream from which to read the data in the file, but not much more than that. You can't read the full path of the file selected, and you are getting the exception because you are attempting to do precisely that.
If you want to read the entire content of the file into a byte array, you'll have to replace the line
localFile.Content = System.IO.File.ReadAllBytes(oFileDialog.File.FullName);
with something like
localFile.content = ReadFully(oFileDialog.File.OpenRead());
The ReadFully method reads the entire content of a stream into a byte array. It's not a standard Silverlight method; instead it
is taken from this answer. (I gave this method a quick test on Silverlight, and it appears to work.)

Resources