Pascal Burkard
Pascal Burkard

Reputation: 21

Writing an serialized object to a file

I have problems with saving a Java Object to a file. I'm writing the App with Android Studio.

Outgoing is the object which I want to save, it contains two Strings, and an int.

private FileOutputStream fileOutputStream;
private ObjectOutputStream objectOutputStream;

public void save(String name, String category, int price){

    // Open file
    try {
        fileOutputStream = new FileOutputStream("outgoings.tmp");
        objectOutputStream = new ObjectOutputStream(fileOutputStream);
    } catch (IOException ioException) {
        System.err.println(ioException.getMessage());
    }

    // Saving
    Outgoing record;
    Scanner input = new Scanner(System.in);

    while (input.hasNext()) {
        try{
            if(name != null){
                record = new Outgoing(name, category, price);
                objectOutputStream.writeObject(record);
            }
        }
        catch(IOException ioException){
            System.err.println(ioException.getMessage());
        }
    }

    // Close file
    try{
        objectOutputStream.close();
    }
    catch (IOException ioException) {
        System.err.println(ioException.getMessage());
    }
}

When I am starting the app, execute the method save(), the app crashes.

// Open file
try {
    fileOutputStream = new FileOutputStream("outgoings.tmp");
    objectOutputStream = new ObjectOutputStream(fileOutputStream);
} catch (IOException ioException) {
    System.err.println(ioException.getMessage());
}

--> the IOException gets thrown and the Logcat shows me this:

Logcat

What would be a suitable File-Path & which datatype should I use?

thank you for your help

Upvotes: 1

Views: 1285

Answers (2)

First of all we can try to write in public directory so results can be easily checked with any file manager app.

Before writing to the filesystem ensure that AndroidManifest.xml contains two permission requests:

<manifest ...>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

...
</manifest>

We can proceed to writing files if your device or emulator/VM running Android 5 or below. If it is not, please take a look at the part of android developer documentation about requesting permissions at runtime.

Here's some code that will give you writable directory with 95% probability:

File destination = new File(Environment.getExternalStorageDirectory(), "My Cool Folder");
destination.mkdirs();

So now you can try to write a file there

fileOutputStream = new FileOutputStream(new File(destination, "outgoings.tmp"));
//write there anything you want

Upvotes: 0

Stephen C
Stephen C

Reputation: 719661

If you are getting the message "Error opening file." that means that the call to openFile() has failed:

public void openFile() {
    try {
        fileOutputStream = new FileOutputStream("outgoings.tmp");
        objectOutputStream = new ObjectOutputStream(fileOutputStream);
    } catch (IOException ioException) {
        System.err.println("Error opening file.");
    }

The ObjectOutputStream constructor pretty much can't fail in this context, so the problem must be that new FileOutputStream("outgoings.tmp") threw the IOException, and the most likely explanation for that is that you don't have permission to create a file in the current directory. (Other explanations are possible ....)

To get to the bottom of this, you need to modify your code to print or log the stacktrace for the IOException.


A couple of other points that should be made about this "beginner" code.

  1. Doing this is a bad idea:

    } catch (IOException ioException) {
        System.err.println("Error opening file.");
    }
    

    Why? Because after reporting the error, you are telling the code to continue as if nothing has happened. And the next thing that you will try to do is to use objectOutputStream ... which has not been initialized!

    You should structure the code so that you don't continue after what should be treated as a fatal error by your code.

  2. If you do this in real-life program that potentially opens files repeatedly, then you are liable to leak file descriptors. The correct pattern for opening and using files (for Java 6 and later) is to use the "try-with-resources" construct; e.g.

    try (FileOutputStream out = new FileOutputStream(...)) {
        // write stuff
    }
    

    when the body of the try ends, the resources that were opened at the start will be autoclosed. This happens in all circumstances that matter. By contrast, if you close resources manually, there is a risk that they won't all be closed in all circumstances.

Upvotes: 1

Related Questions