I am trying to merge some txt-Files from a folder in a Xamarin Form app.
The path is selectable by the user (i´ve created a simple folder browser for that).
e.g. the source path is
/storage/1EE7-170F/
I collect e.g. all txt-files in that folder, read them using File.ReadAllText, do some processing.
That is working fine so far.
I also want to write the results to a new file in the same folder using File.WriteAllText. Target file would be:
/storage/1EE7-170F/SomeResultFile.txt
Getting the directories content is in AppName.Android:
var fileContents = Directory.GetFiles(baseDirectory.FullPath, searchPattern)
.Select(fullPath =>
{
var fileName = Path.GetFileName(fullPath);
var extension = Path.GetExtension(fullPath);
return new FileContent(fileName, fullPath, extension);
});
Reading of the files goes like this in common project:
var content = File.ReadAllText(fileContent.FullPath);
The files are written like this (also in common project):
var baseDir = Path.GetDirectoryName(sourceFiles.First().FullPath);
var targetFilePath = Path.Combine(baseDir, filename);
File.WriteAllLines(targetFilePath, lines);
But i always get an UnauthorizedAccessException saying 'Access to the path "/storage/1EE7-170F/SomeResultFile.txt" is denied.'
I wonder why i can read from that folder, but not write to it.
Writing to System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) is working fine, but that´s not what i need.
I need the result files in the same directory as the source files.
I have both permission "READ_EXTERNAL_STORAGE" and "WRITE_EXTERNAL_STORAGE" enabled in the manifest.
In MainActivity.OnCreate i have added the following:
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
{
ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.WriteExternalStorage }, 0);
}
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted)
{
ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.ReadExternalStorage }, 0);
}
I´ve tried that both on Android emulator and a S10 with latest Android installed (on S10 i selected the "Documents" folder). Same result on both systems with different folders...
Any ideas what could be the problem?
Thanks a lot for help!
Related
I have an image file day.jpg in Resources folder and I want to access it in the code as string path not as byte[] img
Here's what I have tried.
string dayWallpaper = Assembly.GetExecutingAssembly().Location + #"..\..\Resources\day.jpg";
// Didn't found it
string dayWallpaper = Resource.day;
// Outputs byte[] and gives me an error
Then I tried to convert the byte[] to String didn't work as well
static byte[] SliceMe(byte[]? source, int pos)
{
byte[]? destfoo = new byte[source.Length - pos];
Array.Copy(source, pos, destfoo, 0, destfoo.Length);
return destfoo;
}
static string ByteToPath(path)
{
String file = Encoding.Unicode.GetString(SliceMe(path, 24)).TrimEnd("\0".ToCharArray());
return file
}
Outputs black screen
Later I search for the file
if (File.Exists(dayWallpaper))
{
do stuff
}
else
{
Console.WriteLine("File does not exists");
}
And gives me the else statement.
In the answer you posted to your question, the fact that your relative path works is an "accident" that would fail on any other device deploying your app because without the existence of the source code project the path doesn't exist. One good option is to mark the day.jpg file as Copy to Output Directory at which point most installer bundlers will pick it up and deploy it in your setup.exe, msi etc. If you are specifically using the Visual Studio IDE, you would do it like this:
Now, at runtime, to acquire the path to the copied file:
var srce = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "day.jpg");
However, there is more work to be done, because you state that you "want to store the image in a folder in the executable and the user could add more images later on." The present location of the file is not suitable for that purpose, so I would recommend the additional step of creating an AppData entry for the user to store their created content.
// Obtain a folder that "the user could add to later on".
var appData =
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
typeof(Program).Assembly.GetName().Name
);
Directory.CreateDirectory(appData);
Since you mention wanting to store the day.jpg image in that folder, go ahead and copy it to the AppData location (if not already there from a previous run of your app).
var dest = Path.Combine(appData, "day.jpg");
// Copy the image (if it's not there already) into folder that the user can add to.
if (!File.Exists(dest))
{
File.Copy(
sourceFileName: srce,
destFileName: dest
);
}
Alternatively, you could set the BuildAction to EmbeddedResource and manipulate the file as a byte stream and achieve the same end result.
I managed to do it this way
string resourcePath = Path.GetFullPath(Assembly.GetExecutingAssembly().Location + #"\..\..\..\..\Resources");
string dayWallpaper = resourcePath + #"\day.jpg";
I have added downloading functionality and it is working fine but the downloaded file is storing in storage/emulated/0/Application/data/file/Download folder. But I want to change the path of download and want to download at storage/emulated/0/Download folder. My code is as below.
public void Downloaded()
{
CrossDownloadManager.Current.PathNameForDownloadedFile = new System.Func < IDownloadFile, string > (file = > {
string fileName = Android.Net.Uri.Parse(file.Url).Path.Split('/').Last();
return Path.Combine(ApplicationContext.GetExternalFilesDir(Android.OS.Environment.DirectoryDownloads).AbsolutePath, fileName);
});
}
And if I add Static path for download then it shows error for permission as current process has android.permission.WRITE_EXTERNAL_STORAGE. I already provided permissions for writing.
You could use the storage directory for public files on external storage as PUBLIC_EXTERNAL_STORAGE. https://learn.microsoft.com/en-us/xamarin/android/platform/files/external-storage?tabs=windows
The code could get the download folder which you want.
var DIR = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads);
I have the following lines of code that work for creating a zip using ZipFile.CreateFromDirectory(selectedFile, zipPath)
if (selectedFolder == string.Empty)
{
Console.WriteLine("Invalid folder, try again");
}
else
{
Console.WriteLine("\nSelect zipfile name: ");
var zipName = Console.ReadLine();
// Also available: extractToDirectory
var zipPath = #"C:\Users\User\Documents\Dev\" + zipName + ".zip";
ZipFile.CreateFromDirectory(selectedFolder, zipPath);
However, the following code which should for all intents and purposes do the same thing except for multiple files being archived into a single zip folder refuses to work:
public static void CreateZipFile(string folderToCreateZip, IEnumerable<string> files)
{
var zipPath = folderToCreateZip + "\\test6.zip";
// Create a new ZIP in this location
using (var zip = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
foreach (var file in files)
{
// Add entry for files
zip.CreateEntryFromFile(file, zipPath, CompressionLevel.Optimal);
}
}
// Dispose of zip object after files have been zipped
//zip.Dispose();
}
var zip == ZipArchive zip
I've tried disabling read-only mode on the folders where the zip should get created, but I don't think this matters since the prior function with CreateFromDirectory() works fine. I've also tried creating a ZIP on desktop, but I get the same error.
This is the exception I'm getting:
As a note, I noticed that it does initially create the zip despite this error, just that it cannot add anything to it unlike CreateFromDirectory() can due to the folder either being in use, no permissions to that area or the folder already existing. Is there a way I can get CreateEntryFromFile() working or an alternative that would work for multiple files?
I had the same problem. The solution was post the full path name at the destinationArchiveFileName parameter (and also a write alowed path). For example c:\my apps folder\my app\my temp\zipfile.zip
I am developing a windows 8 app using Microsoft visual studio 2013. I needed to store the user entered data in a text file. I have wrote the following code segment to create the file and its working. But the text file is created in C:\Users...... I want to create the text file in a given folder. How can I modify my code to create the file in a folder where I specify.
StorageFile sampleFile;
const string fileName = "Sample.txt";
This is how you can create a file in C temp folder
String folderPath = #"C:/temp";
FileStream fs = new FileStream(folderPath + "\\Samplee.txt",FileMode.OpenOrCreate, FileAccess.Write);
As told before, Universal apps are sandboxed which means you can't write a file in an arbitrary folder.
You should take a look at the File access sample on how to do it.
Also, you should take a look at the ApplicationData which gives you a lot of choices for saving user entered data. Is it temporary, do you want it to be synced, is it a setting? There sure is a property that suits your needs.
edit: from http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.applicationdata.localfolder.aspx this is what you should do
var applicationData = Windows.Storage.ApplicationData.current;
var localFolder = applicationData.localFolder;
// Write data to a file
function writeTimestamp() {
localFolder.createFileAsync("dataFile.txt", Windows.Storage.CreationCollisionOption.replaceExisting)
.then(function (sampleFile) {
var formatter = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("longtime");
var timestamp = formatter.format(new Date());
return Windows.Storage.FileIO.writeTextAsync(sampleFile, timestamp);
}).done(function () {
});
}
You need to set the directory where you want to save the file.
Try this
string dirctory = #"D:\Folder Name"; //This is the location where you want to save the file
if (!Directory.Exists(dirctory))
{
Directory.CreateDirectory(dirctory);
}
File.WriteAllText(Path.Combine(dirctory, "Sample.txt"), "Text you want to Insert");
After looking at many topics I decided to ask this
I have a WCF service that reads a file from the local file system. When the service is tested locally on my computer it was no problem doing that.
But when I publish the service in IIS8 i am getting this error
The system cannot find the file specified
I have tried creating a new user and new ApplicationPool that uses that identity to run the service and also given full control to the folder that is trying to be read but the problem continues.
I have also tried even using the Administrator as the identity of the new Application Pool but did not solve the problem either
What am i missing ?
Assuming that you have a relative URL and the account that is running the application has the proper permissions, you're probably not getting the correct pathname to your file.
You can try something like this to find the full path of your file:
using System.IO;
public FileInfo GetFileInfo(string filename)
{
if(filename == null)
throw new ArgumentNullException("filename");
FileInfo info = new FileInfo(filename);
if(!Path.IsPathRooted(filename) && !info.Exists)
{
string[] paths = {
Environment.CurrentDirectory,
AppDomain.CurrentDomain.BaseDirectory,
HostingEnvironment.ApplicationPhysicalPath,
};
foreach(var path in paths)
{
if(path != null)
{
string file = null;
file = Path.Combine(path, filename);
if(File.Exists(file))
{
return new FileInfo(file);
}
}
}
}
throw new FileNotFoundException("Couldn not find the requested file", filename);
}
It's returning an instance of System.IO.FileInfo but you can easily adapt it to return a string (full pathname).