Search code examples
javaandroidfileinputstreamandroid-context

Problems understanding context and contextwrapper


I'm not able to understand these classes. I've been trying to create a new file in a new directory on my internal storage, put some text in it and then to read it out. This does not seem to work without the ContextWrapper. So I tried this:

public class DownloadActivity extends Activity {
  ...
 class Download extends AsyncTask<String, Void, String>{

 ....
 private void searchAndSave(String s) throws IOException {
....
   ContextWrapper cw = new ContextWrapper(getBaseContext());
   File folder = cw.getDir("folder", Context.MODE_PRIVATE);
   File fileInFolder = new File(folder, "fileInFolder");

   String string = "Hello world!";
   FileOutputStream outputStream = openFileOutput("fileInFolder",
                                Context.MODE_PRIVATE);
   outputStream.write(string.getBytes());
   outputStream.close();

   File fl = new File(cw.getDir("folder", Context.MODE_PRIVATE)+"/fileInFolder");
   FileInputStream fin = new FileInputStream(fl);

   BufferedReader reader = new BufferedReader(
                                new   InputStreamReader(fin));
   StringBuilder sb = new StringBuilder();
   String line = null;
   while ((line = reader.readLine()) != null) {
       sb.append(line).append("\n");
   }
   String result = sb.toString();
   reader.close();
   fin.close();
   }
}

Creating the file does not work without the ContextWrapper. I've been reading a lot, but I still have problems to understand, what the Context and the Contextwrapper actually do and why I need them to create a file. Additionally in my code the creating of the FileInputStream does not work. When the program reaches

FileInputStream fin = new FileInputStream(fl);

I always get the error:

05-21 11:18:25.721: W/System.err(7344): java.io.FileNotFoundException: 
/data/data/com.example.dice/app_folder/fileInFolder: open failed: 
ENOENT (No such file or directory)

I really would appreciate some help with understanding and solving this problem.

UPDATE: I made a more spare Activity, maybe now it's easier to reconstruct the whole thing. (Should I have done this in a new answer, or is it okay to edit my first posting?) Even though I don't get an error message when trying to create a file, is doesn't seem to work. Here I try reading the "Hello world" string, but I get a FileNotFoundException (EISDIR). Just for you to know :)

public class FolderActivity extends Activity {
public final static String TAG = "FolderActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_folder);

    Button button = (Button) findViewById(R.id.button_folder);

    button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            try {
                folder();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });
}
    private void folder() throws IOException{
        Log.d(TAG, "folder");
        ContextWrapper cw = new ContextWrapper(getBaseContext());
        Log.d(TAG, "cw = new ContextWrapper");
        File folder = cw.getDir("folder", Context.MODE_PRIVATE);
        Log.d(TAG, "folder = cw.getDir");
        File fileInFolder = new File(folder, "fileInFolder");
        Log.d(TAG, "fileInFolder = new File");
        /*Log.d(TAG,
                "fileInFolder.getAbsolutePath()"
                        + fileInFolder.getAbsolutePath());*/

        String string = "Hello world!";
// Aksioms suggestion
        if (!fileInFolder.exists() && !fileInFolder.mkdirs()) {
            Log.e("file", "Couldn't create file " + fileInFolder);
        } else { Log.d(TAG, "file created"); }
        FileOutputStream outputStream = openFileOutput("fileInFolder",
                Context.MODE_PRIVATE);
        outputStream.write(string.getBytes());
        outputStream.close();
        Log.d(TAG,
                "fileInFolder.getAbsolutePath()"
                        + fileInFolder.getAbsolutePath());
        String s = fileInFolder.getAbsolutePath();
        try {
            getStringFromFile(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

public static String getStringFromFile (String filePath) throws Exception {
    File fl = new File(filePath);
    FileInputStream fin = new FileInputStream(fl);
    String ret = convertStreamToString(fin);
    //Make sure you close all streams.
    fin.close();        
    return ret;
}

public static String convertStreamToString(InputStream is) throws Exception {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String line = null;
    while ((line = reader.readLine()) != null) {
      sb.append(line).append("\n");
    }
    reader.close();
    return sb.toString();
}
}

Solution

  • You are trying to open a file which does not exists. Make sure that you check and create the file if it does not exsist:

    if (!fl.exists() && !fl.mkdirs()) { 
                    Log.e("file", "Couldn't create file " + fl);
    }
    

    EDIT:

    Yes the getDir creats the folder if it is not created.

    File folder = cw.getDir("folder", Context.MODE_PRIVATE);
    

    But the problem is here

     File fileInFolder = new File(folder, "fileInFolder");
       String string = "Hello world!";
       FileOutputStream outputStream = openFileOutput("fileInFolder",
                                    Context.MODE_PRIVATE);
    

    In here you try to open a file that does not exsist, you just constructed a new file named fileInFolder, but you actually do not have that folder yet.

    Try to use the code that I wrote at the first place, before the openFileOutput("fileInFolder", Context.MODE_PRIVATE); :

    if (!fileInFolder.exists() && !fileInFolder.mkdirs()) { 
                        Log.e("file", "Couldn't create file " + fileInFolder);
        }
    

    Try this and tell me how it goes.

    EDIT 2:

    OK I found the problem it was so obvious. The mistake was that we created the fileInFolder as a directory, and you can not write anything there :D

    What we should have done is this:

    Remove my code for creating the fileInFolder.

    if (!fileInFolder .exists() && !fileInFolder .mkdirs()) {
        Log.e("file", "Couldn't create file " + fileInFolder );
    } else {
        Log.d(TAG, "file created");
    }
    

    we do not need to create it because we will use it as a file. So the change I have made in your code is this:

    FileOutputStream outputStream = new FileOutputStream(fileInFolder);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream));
        out.write(string);
        out.close();
    

    Add this between the line String string = "Hello world!"; and the first Log.d... This is the correct way to write in a file.

    The whole code:

    public class MainActivity extends Activity {
    public final static String TAG = "FolderActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        Button button = (Button) findViewById(R.id.button_folder);
    
        button.setOnClickListener(new OnClickListener() {
    
            @Override
            public void onClick(View v) {
                try {
                    folder();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
    
    private void folder() throws IOException {
        Log.d(TAG, "folder");
        ContextWrapper cw = new ContextWrapper(getBaseContext());
        Log.d(TAG, "cw = new ContextWrapper");
        File folder = cw.getDir("folder", Context.MODE_PRIVATE);
        Log.d(TAG, "folder = cw.getDir");
        File fileInFolder = new File(folder, "fileInFolder");
        Log.d(TAG, "fileInFolder = new File");
        /*
         * Log.d(TAG, "fileInFolder.getAbsolutePath()" +
         * fileInFolder.getAbsolutePath());
         */
    
        String string = "Hello world!";
    
        FileOutputStream outputStream = new FileOutputStream(fileInFolder);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream));
        out.write(string);
        out.close();
        Log.d(TAG,
                "fileInFolder.getAbsolutePath()"
                        + fileInFolder.getAbsolutePath());
        String s = fileInFolder.getAbsolutePath();
        try {
            getStringFromFile(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static String getStringFromFile(String filePath) throws Exception {
        File fl = new File(filePath);
        FileInputStream fin = new FileInputStream(fl);
        String ret = convertStreamToString(fin);
        // Make sure you close all streams.
        fin.close();
        return ret;
    }
    
    public static String convertStreamToString(InputStream is) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }
        reader.close();
        return sb.toString();
    }}
    

    Check if you have this permission in your manifest:

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

    I hope everything is clear now.