Can someone possibly help me with this?
I want to observe a file to see if it gets modified so that I can update the activity. After several tests, I've determined it's just plain not working.
Am I doing something wrong?
I'm creating a FileObserver with an onEvent method to display a Toast and log data just to see if it's working, however the onEvent is never getting called.
I have tried it both with an existing and a new file, but it doesn't seem to work in either case.
Context context = this;
File fileFolder = context.getFilesDir();
String fileName = "quest";
FileObserver questObserver = new FileObserver(fileFolder.getPath()) { // also tried fileFolder.getName()
#Override
public void onEvent(int event, String path) {
Toast.makeText(getApplicationContext(), "onEvent fired", Toast.LENGTH_LONG).show();
Log.d(TAG, "FileObserver().onEvent");
}
};
questObserver.startWatching();
/* create file */
ObjectOutputStream objectOut = null;
try {
FileOutputStream fileOut = context.openFileOutput(fileName, Context.MODE_PRIVATE);
objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(new Quest());
fileOut.getFD().sync();
} catch (IOException e) {
Log.d(TAG, e.getMessage());
} finally {
if (objectOut != null) {
try {
objectOut.close();
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
}
}
/* read file */
ObjectInputStream objectIn = null;
Quest quest = null;
try {
FileInputStream fileIn = context.openFileInput(fileName);
objectIn = new ObjectInputStream(fileIn);
quest = (Quest) objectIn.readObject();
} catch (FileNotFoundException e) {
// Do nothing
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (objectIn != null) {
try {
objectIn.close();
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
}
}
Toast.makeText(context, quest.getTitle(), Toast.LENGTH_LONG).show();
questObserver.stopWatching();
Any help would be greatly appreciated.
'public abstract void onEvent (int event, String path)" -
This method is invoked on a special FileObserver thread. It runs
independently of any threads, so take care to use appropriate
synchronization! Consider using post(Runnable) to shift event handling
work to the main thread to avoid concurrency problems.
http://developer.android.com/reference/android/os/FileObserver.html
If you put the toast through a handler.post(new Runnable(){...}), that should work.
Assuming your file doesn't (always) exist you should probably put your observer on the files folder, obtained like so:
Context ctx = ...;
File filesFolder = ctx.getFilesDir();
Note that this will also ensure that the filesFolder directory will be created.
Your observer will now be notified whenever a file is written, deleted or updated using for instance Context#.openFileOutput(..) - and you can filter in your FileObserver for the file name, in your example "quest".
Related
I am currently on the beginner level when it comes to Android & I am currently scratching my head over an issue that I am currently facing.
I am creating an Android app to check if "cache.json" exists in the internal storage:
If it does not exist then first create it & write a string fetched from HTTP API to the file (replaced with fixed string in code below).
Regardless, read the file after writing is done (if necessary) & do appropriate stuff.
This is the code snippet:
public class ShowClasses extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
filename = "cache.json";
file = new File(getApplicationContext().getFilesDir(), filename);
if (file.exists()) {
System.out.println("EXISTS");
} else {
System.out.println("DOES NOT EXIST");
writeFile();
}
readFile();
}
public void writeFile() {
new JsonTask().execute(email);
}
public void readFile() {
FileInputStream fin = null;
try {
fin = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int c;
result = "";
try {
while( (c = fin.read()) != -1){
result = result + Character.toString((char)c);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
return;
}
private class JsonTask extends AsyncTask<String, Void, String> {
protected void onPreExecute() {
result = ""; // Clear result
super.onPreExecute();
pd.setMessage("Please wait");
pd.setCancelable(false);
pd.show();
}
protected String doInBackground(String... params) {
return "THIS STRING IS GOING TO BE RETURNED " + params[0];
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
FileOutputStream fileout = null;
try {
fileout = new FileOutputStream(file);
fileout.write(result.getBytes());
//display file saved message
msg("File saved successfully!");
} catch (Exception e) {
e.printStackTrace();
}
try {
fileout.close();
} catch (IOException e) {
e.printStackTrace();
}
if (pd.isShowing()){
pd.dismiss();
}
}
}
}
I have tried to remove un-necessary part of the code so that it is smaller in length.
The actual issue I am facing is when writeFile() & readFile() both are called. I get a FileNotFoundException in readFile() when I open the stream even though the file should be created since writeFile() is called before readFile().
If I writeFile on one execution & then call readFile() on the other, it simply works as it should be.
This is the error that I am facing.
System.err: java.io.FileNotFoundException: /data/user/0/host.timetable.timetablenotifier/files/cache.json (No such file or directory)
System.err: at java.io.FileInputStream.open(Native Method)
Any help would be really appreciated.
Thanks
writeFile() is asynchronous. When that method returns, nothing has happened with respect to this file. At most, onPreExecute() of your JsonTask might be called. So, when you call readFile(), the file will not exist yet.
Beyond that:
You have an AsyncTask that you use in writeFile(), but you do your disk I/O in onPostExecute(), and that method is called on the main application thread.
You are doing disk I/O on the main application thread in readFile().
You catch exceptions, log them, but then continue executing your code, when most of those exceptions mean that the later statements are going to fail as well.
Reading in data one int at a time has not been a recommended approach for getting close to 20 years, for performance reasons.
You will have multiple issues related to configuration changes, such as screen rotations, as neither your AsyncTask nor your ProgressDialog account for configuration changes
Also:
getApplicationContext().getFilesDir() could be replaced by getFilesDir() in onCreate()
You do not need createNewFile()
AsyncTask runs in a background thread so the other code in the main thread doesn't wait for the execution to complete. In simpler terms, your readFile() method is executed before writeFile() completes and hence there is a FileNotFoundException. What would work for you is if you put the readFile() method at the end of the onPostExecute() method inside your Asynctask
This question already has answers here:
java.io.FileNotFoundException when creating FileInputStream
(2 answers)
Closed 6 years ago.
For my application I want to use a Map to act as a database. To save and load a map, I am writing/reading it to/from database.ser using this 2 methods:
private synchronized void saveDB() {
try {
fileOut = new FileOutputStream(db);
out = new ObjectOutputStream(fileOut);
out.writeObject(accounts);
fileOut.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#SuppressWarnings("unchecked")
private void loadDB() {
try {
fileIn = new FileInputStream(db);
in = new ObjectInputStream(fileIn); // that is where error is produced if fileIn is empty
accounts = (Map<String, Client>) in.readObject();
in.close();
fileIn.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I want to load into Map when application starts, so I invoke method in constructor like this:
protected DriveatorImpl() {
accounts = new ConcurrentHashMap<String, Client>();
db = new File("C:/Users/eduar/git/Multy-Threaded-Bank-System/Bank-Services/database.ser");
// also, any suggestions how can I make path to a file more flexible in case I want to run Server side of an app on different machine?
if (!db.exists()) {
try {
db.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
loadDB(); // loads database when server start
}
I am aware of what causing an error, but I don't know what should I change in my design to avoid ObjectInputStream constructor receiving empty stream!
Any suggestions on what I can do differently?
Edit: I want to note that in fresh application run database.ser is empty since there was no entries made into Map yet.
Thank You!
First why the EOFExcpetion occur?
There are no contents in file or file is empty and you tried to read file.
You can avoid the EOFException for an empty file by checking file content length if it is less than or equal to zero means file is empty. another way to check if file is empty
Some code change and it worked for me.
#SuppressWarnings("unchecked")
private void loadDB() {
try {
if (db.length() <= 0) {
// if statement evaluates to true even if file doesn't exists
saveDB(); // save to a file an empty map
// if file doesn't exist, it creates a new one
// call loadDB inside constructor
}
FileInputStream fileIn = new FileInputStream(db);
ObjectInputStream in = new ObjectInputStream(fileIn); // that is where error is produced if fileIn is empty
in.readObject();
in.close();
fileIn.close();
System.out.println(accounts);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Get rid of the file.exists()/file.createNewFile() crap. All it is doing for you is masking the original FileNotFoundException problem, and turning into a thoroughly predictable EOFException because of trying to construct an ObjectInputStream around an empty stream. Handle the original problem. Don't just move it, or turn it into something else.
I have a program that needs to load data at launch. The data comes from a serialized object. I have a method loadData(), which is called upon construction of the Data class. Sometimes, (I.e. after a loss of saveData, or on first program launch on a new system), the file can be empty. (The file will exist though, the method ensures that).
When I try to run the program, I recieve an EOFException. So, in the method, I try to catch it, and just print a line to the console explaining what happened and return to the caller of the method. (so, upon return, the program will think loadData() is complete and has returned. However, it still crashes throwing the exception without printing a line to the console or anything. It is like it is totally ignoring the catch I have in place.
CODE:
protected void loadData()
{
// Gets/creates file object.
saveFileObject = new File("savedata.ser");
if(!saveFileObject.exists())
{
try
{
saveFileObject.createNewFile();
}
catch(IOException e)
{
System.out.println("Uh oh...");
e.printStackTrace();
}
}
// Create file input stream
try
{
fileIn = new FileInputStream(saveFileObject);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
// Create object input stream
try
{
inputStream = new ObjectInputStream(fileIn);
}
catch(IOException e)
{
e.printStackTrace();
}
// Try to deserialize
try
{
parts = (ArrayList<Part>)inputStream.readObject();
}
catch(EOFException e)
{
System.out.println("EOFException thrown! Attempting to recover!");
return;
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
catch(IOException e)
{
e.printStackTrace();
}
// close input stream
try
{
inputStream.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
Any help please?
Try writing your code like :
protected void loadData() {
// Gets/creates file object.
saveFileObject = new File("savedata.ser");
try {
if (!saveFileObject.exists()) {
saveFileObject.createNewFile();
}
// Create file input stream
fileIn = new FileInputStream(saveFileObject);
// Create object input stream
inputStream = new ObjectInputStream(fileIn);
// Try to deserialize
parts = (ArrayList<Part>) inputStream.readObject();
// close input stream
inputStream.close();
} catch (EOFException e) {
System.out.println("EOFException thrown! Attempting to recover!");
} catch (IOException e) {
System.out.println("Uh oh...");
e.printStackTrace();
}
}
Also note that EOFException is a sub-class of IOException
How about making one try and then making catches respectively like here?
Currently I'm developing an android app where the user has to click on a button this adds +1 to a count. After 100 there is another button which causes a reset of the count and increase the level and difficulty which is stored in another 2 "ints". Well its all working but I seriously have big problems with creating a save file.
-I gave me the permission via AndroidManifest.xml
-Tryed 3 other code examples
I did import everything that is necessary and the rest of the code is working
There has to be a mistake in this part of my code:
(my part for the Saving the "Stats")
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
FileOutputStream savelvl = openFileOutput("savelvl.data", Context.MODE_PRIVATE);
savelvl.write(level);
savelvl.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
can anyone suggest an improvement to the code or tell me the mistake in saving the file to the internal storage?
I've had success with using a BufferedWriter instead of FileOutputStream, although I'm sure it could given a different setup. Below is some code with "FileOutputStream out", which I was trying to use initially, commented out.
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file,true));
//out = new FileOutputStream(file);
Log.i("file","file opened");
writer.write(someString);
//out.write(someString.getBytes());
Log.i("file","file written");
} catch (Exception e) {
Log.e("fileNotFound","file not found exception");
e.printStackTrace();
}/*
try {
out.write(someString.getBytes());
Log.i("file","file written");
Log.i("str2File",someString.getBytes().toString());
} catch (IOException e) {
Log.e("fileWrite","file write error");
e.printStackTrace();
}*/ finally {
try {
//out.getFD().sync();
//out.close();
writer.close();
Log.i("file","file closed");
} catch (Exception e) {
Log.e("closeError","error closing file");
e.printStackTrace();
}
}
You cannot flush your data. When you use writer you must call flush method after write method.
OutputStrem stream = ... // I cannot create new reference because "OutStream" class is abstract
stream.write(data, offset, length);
stream.flush();
stream.close();
I have this method supposed to read a file:
/* Read file's content */
private ArrayList<String> readFromFile() {
File file = new File("jokesBody1.bjk");
ArrayList<String> list = new ArrayList<String>();
try {
file.createNewFile();
ObjectInputStream ois = new ObjectInputStream( new FileInputStream( file ) );
try {
list = (ArrayList)ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
ois.close();
} catch (IOException e) {
Log.e("log activity", "Can not read file: " + e.toString());
}
return list;
}
When I call it, it returns:
02-16 06:15:32.686: E/log activity(1380): Can not read file: java.io.IOException: open failed: EROFS (Read-only file system)
Even, if the file is read only, why I can't read it? I really can't understand what is wroong. I have this premission in my manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Can someone give me a clue? I know that I'm missing something small, but I really can't spot it.
Here is how I write the file:
/* Write content to a file */
private void writeToFile(ArrayList<String> list, Context cont) {
File file = new File("jokesBody1.bjk");
FileOutputStream fos;
if(list != null){
try {
fos = cont.openFileOutput("jokesBody1.bjk", Context.MODE_PRIVATE);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(list);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else{
try {
file.createNewFile();
fos = openFileOutput("jokesBody1.bjk",Context.MODE_PRIVATE);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject("");
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
You are trying to create the file, which of course fails on a read-only file.
Remove this line:
file.createNewFile();
This is usually used to create a new empty file before writing to it. You really don't need it if you just want to read a file that already exists.
EDIT:
Just use this:
ObjectInputStream ois = new ObjectInputStream( context.openFileInput("jokesBody1.bjk"));
Of course, you'll also have to pass a Context to the function.
You can only use File with a full path. For accessing your private files, use Context, just as you do when saving the file.
Your full function should look like:
private ArrayList<String> readFromFile(Context context) {
ArrayList<String> list = new ArrayList<String>();
try {
ObjectInputStream ois = new ObjectInputStream( context.openFileInput("jokesBody1.bjk"));
try {
list = (ArrayList)ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
ois.close();
} catch (IOException e) {
Log.e("log activity", "Can not read file: " + e.toString());
}
return list;
}
You aren't specifying any path:
File file = new File("jokesBody1.bjk");
So, you are not saying the app WHERE to look for the file.
Maybe, you want to search it here?
Environment.getExternalStorageDirectory()