Writing to Internal Storage - File Not Found - android

I have read a ton of articles on writing to the internal storage of an android device, and I need some help figuring out what I am doing wrong. In the main activity of my app, I read a value from a file stored in the internal storage like this:
string ID = GetID();
Where GetID looks like this:
string GetID()
{
try
{
using (var i = new StreamReader (OpenFileInput (FILENAME)))
{
return i.ReadToEnd();
}
}
catch
{
return "";
}
}
If the file doesn't exist, "" is returned and the user is sent off to another activity to register. In that activity, I use this to call a function to write to internal storage like this:
WriteID (uniqueID);
Where WriteID looks like this:
void WriteID(string uniqueID)
{
using (var o = new StreamWriter (
OpenFileOutput (FILENAME, FileCreationMode.Private)))
o.Write (uniqueID);
}
This is where it gets weird for me, if I put these two functions in the same activity, write to the file and then call the function to read from it, I get uniqueID returned correctly. However if I stop the app and then restart it, I get a File Not Found exception thrown and nothing returned from the read function. However, if I create a new project, and use the same code, everything works as expected (file is created and written to, then on restart the data persists).
So I am thinking there is some setting that I have changed or some reference that I may be missing in my original app that causes the internal storage file to be removed when the app is stopped?
Any ideas as to why this works correctly in my test app, but not in the other?

Related

How can I make my Android app read and write a .txt file?

I'm using Xamarin, C# and Monogame and I'm taking a fully-working Desktop game and porting it over to Android.
My problem is that I have this "Content folder" that you would always use in the Desktop version of the app. But I cannot access it or any other folder through the code directly using Android.
basicShader = new Effect(game1.GraphicsDevice,System.IO.File.ReadAllBytes("Content/TextureShader.mgfxo"));
This works just fine in the Desktop app but throws System.IO.DirectoryNotFoundException:'Could not find a part of the path "/Content/TextureShader.mgfxo".' on Android.
I'd like to mention that I already had the code and the project working perfectly when it was a desktop program. I also have a private class-level variable string[] list_of_files and in the constructor, I had the line list_of_files = Directory.GetFiles("./Content","*.txt");
This is for saving and loading player data. It may have been rudimentary but I had a fully functioning program that saved and loaded data on my computer. I am transitioning this program to be an Android app and this is the only part of the project that isn't working. When I run the code as it was originally written, I get "System.IO.DirectoryNotFoundException: 'Could not find a part of the path '/Content'.' ".
I've tried playing around with trying to read the contents of different folders.
I've messed around with different paths, including the Resources folder instead.
I added <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> to my manifest.
I know that I'm trying to access internal storage, not external, so I also tried <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" /> just to see if that might work.
Nothing works.
In another stack overflow post, a guy commented:
For the people who are facing NullPointerException - you are trying to access the files in the app's internal storage which are private sorry you can't do that. –
coderpc
Jun 23, 2017 at 16:00
I cannot imagine why this would be true. Why would a programmer not be able to write a program that can access it's own internal storage? That makes no sense to me. Obviously my app needs to be able to read and write it's own internal storage! And if this is true, then how else can I save persistent data on my phone? I don't want a database or a shared thingamabobber that uses key-value pairs, I have a self-made system that works as a text file and I want to continue to use it. I refuse to believe that an Android app can't keep track of a simple .txt file in one of it's own folders, that's just too hard for me to imagine. It can't be true.
I wanted to ask the commenter about his comment but Stack Overflow wouldn't let me because I don't have over 50xp.
Just like CommonsWare sayed, you can use the Intent.ActionOpenDocument to get the uri of the file. Such as
static readonly int READ_REQUEST_CODE = 1337;
Intent intent = new Intent(Intent.ActionOpenDocument);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType("*/*");
StartActivityForResult(intent, READ_REQUEST_CODE);
And override the OnActivityResult method:
if (requestCode == READ_REQUEST_CODE && resultCode == Result.Ok)
{
// The document selected by the user won't be returned in the intent.
// Instead, a URI to that document will be contained in the return intent
// provided to this method as a parameter. Pull that uri using "resultData.getData()"
if (data != null)
{
Android.Net.Uri uri = data.Data;
DocumentFile documentFile = DocumentFile.FromSingleUri(this.ApplicationContext,uri);
// Then you can operate the file with input and output stream
}
}
More information please check the simple on the github:
https://github.com/xamarin/monodroid-samples/blob/main/StorageClient/StorageClientFragment.cs
In addition, if you can ensure the file's path. You can use the StreamWriter and the StreamReader to write and read the file. Such as:
using (StreamWriter sw = new StreamWriter(path))
{
sw.WriteLine(content);
}
Furthermore, you can try to create the content folder and the txt file in the Android with the following code.
var filename1 = Android.App.Application.Context.GetExternalFilesDir(System.DateTime.Now.ToString("Content")).AbsolutePath;
var filename = System.IO.Path.Combine(filename1, "xxx.txt");
using (System.IO.FileStream os = new System.IO.FileStream(filename, System.IO.FileMode.Create))
{
}
The folder and the files created by this way belongs to the app and you can access it easily.
You can read the official document about the storage in the Android.
Link : https://developer.android.com/training/data-storage/shared/documents-files

Xamarin.Android : Deserialize a file in ApplicationData?

I'm storing user data in ApplicationData folder. Its path is obtained with :
userDataPath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "userData");
This variable is equal to /data/user/0/APPNAME/files/.config/userData.
Each time I rebuild the project, if I delete the userData file with File.Delete(userDataPath), I can successfully create the file, write and read to it several times. I can indeed check the created file in /data/data/APPNAME/files/.config/userData.
I check in /data/data/.../.config/userData and not in /data/user/.../.config/userData because apparently the latter is a symlink to the former, so it should be equivalent ? Moreother I don't have access to /data/user/.../.config/userData.
The problem is that if I rebuild the app without deleting the file, I got an unhandled exception at the following Deserialization (which worked fine before) :
if (File.Exists(userDataPath))
{
Stream reader = new FileStream(userDataPath, FileMode.Open);
Console.WriteLine(userDataPath);
userData = (UserData)serializer.Deserialize(reader); // ERROR HERE
reader.Close();
}
It is very strange because the file located at /data/data/APPNAME/files/.config/userData does not exist but since File.Exists(userDataPath) is true, the file located at /data/user/0/APPNAME/files/.config/userData does exist.
So how can this be explained and is this the correct way to store data in ApplicationData folder ?
After switching to another SpecialFolder (LocalApplicationData), I can't reproduce the unhandeld exception anymore (even when switching back to ApplicationData).
I'll keep this post updated if it ever happens again.

Saved data disappears from cell phone

I have made an app for Android which saves results for skeet shooting. During a session, the user either presses hit or miss. When the session is over, the user press save and the new result is appended to the json-object. After that the result is appended, it is saved to the phone via
public static void saveData(Context context) {
File path = context.getFilesDir();
File file = new File(path, "jsonUsr.json");
if (file.exists()) {
try {
FileOutputStream stream = new FileOutputStream(file);
String objString = usrObject.toString();
stream.write(objString.getBytes());
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Now, my friend who has my app used it when we were at a competition today. During the session when my app was running and he had started to fill in his result, he receives an sms. He opens the message and reads it. Then instead of reopen my app from the current apps running, he goes to the meny and presses the icon. Suddenly he discovers that all data is gone! Not just the current session, but all results he has entered. I cannot understand that, because there does not even exists in the code a call which deletes the saved json string file.
I have tried to imitate what he did on my phone, but it works perfectly. He has had a lot of problems with the memory with his phone. For a couple of days ago, it complained about that there were not enough memory for upgrading, so he moved things to the SD-card? Is it possible that the data has either been removed due to lack of memory or that it is moved to the SD card?
It is not so much to work with, but I do not have more. Since I cannot recreate it myself, it is hard to know exactly what has happened.
It is a good idea to always write to a new file in the same directory. If that write succeeds, move the new file onto the config file by changing its name. (this change is atomic)
That way, you will always end up with a valid file, even if the call to write fails for some reason (out of disk, toString() fails, etc.).

Trouble reading user names and password from a text file

I'm creating automated tests for an android app with very little knowledge of Java. I'm using a test recorder to generate the basic robotium scripts and then updating them manually. The tests are working fine with the log in credentials hard coded in the scripts, but to apply these tests to more than one account I wanted to read the user name and password in from a text file. A Scanner instance seemed to me to the the logical method to read line delimited strings from a text file into the variables for the log in credentials but I'm having trouble figuring out where to put the code. It seems like whatever I try the variables are either out of scope (not being used) or I come up with a some exception or other.
Here's the Scanner code I'm using, currently positioned at the top of my test code:
public void testRecorded() throws Exception {
String userName;
String passWord;
Scanner scanFile = null;
try {
scanFile = new Scanner("C:/...path to file...file.txt");
//Read the password from file
userName = scanFile.nextLine();
//Consume the line break
scanFile.nextLine();
//Read the password from file
passWord = scanFile.nextLine();
}
finally {
scanFile.close();
}
Test code continues...
Running this fails at the nextLine statement where I consume the line break with a NoSuchElementException
Is Scanner the best method to use to read user names and passwords from text files? Is there something wrong with my Scanner code? Where do I put the Scanner code in my test? Does it require a separate class or can I keep this code with the rest of my test code?
You want to scan file from host machine ("C:/..."). Device has no access to that. You have to put file to device, for instance on sdcard.
If you want to use Scanner for scanning files you cannot pass String there. You should rather use:
// if you put file.txt directly on sdcard (/sdcard/file.txt)
String path = String.format("%s/%s", Environment.getExternalStorageDirectory(), "file.txt");
Scanner scan = new Scanner(new File(path));
...

Files are getting deleted from the SD card

I have developed a Service which will start when I receive the "ON_BOOTUP_COMPLETED" intent,
in "onCreate" of my Service I wrote the logic to create a text file in SD card of the device.
Below is the logic I have used to do so:
File abc = new File(Environment.getExternalStorageDirectory()+"\abc.txt");
if(!abc .exists())
abc.createNewFile();
abcwriter = new FileWriter(abc);
I am using "abcwriter" in other methods to write some content in to text file.
So far it is working fine.
But when rebooted the device, I observed that "abc.txt" file is creating again.
but I put a check before creating file "if(!abc .exists())". But still new file is created.
I suspect that when I rebooted the device my files are deleted. Is this the android behaviour..??
If it is please help me what I can do to make sure my files not created again.
You have to use the constructor below and pass true as the second parameter if you want to append to the file. Otherwise it will just get overwritten each time your code runs (when you reboot).Also get rid of the createNewFile() call, you don't need it since the writer will create it.
FileWriter(File file, boolean append)
abcwriter = new FileWriter(abc); -> this line (re)creates the file.
Make sure it's called only when needed:
File abc = new File(Environment.getExternalStorageDirectory()+"\abc.txt");
if(!abc.exists()) {
// abc.createNewFile(); -> this is not needed since following line handles this
abcwriter = new FileWriter(abc);
}

Categories

Resources