1

I'm building a FileManager class to handle all of my file management needs. Ideally, this FileManager should rely entirely on methods provided by the Android SDK. I'm running into a road block as far as properly managing subdirectories. When I attempt to load a file using a new FileInputStream object, I'm met with a FileNotFoundException. If I attempt to do so using the context.openFileInput with a custom filepath, I'm met with an IllegalArgumentException related to my path separators.

Here are my writefile and readfile methods. All Directory strings passed to these methods are subdirectories in internal storage (such as data/user/0/com.app.package/files/recordings, where recordings is my created subdirectory). :

 /**
 * Writes the provided data to a file based on the designated filename and directory
 * @param data - Array of Strings to be written to the file
 * @param fileName - Relative path of the file being written
 * @param dir - Path of the directory where the file will be written
 * @throws IOException
 */
    private void writeFile(String[] data, String fileName, String dir) throws     IOException {
    Log.v(LOG_TAG, "writeFile");
    if(fileName == null) {
        Log.w(LOG_TAG, "No File Path Provided. File Not Written.");
        return;
    }

    /* Creates and Appends the directory to the provided filename */
    if(dir != null && dir.length() > 0) {
        createDirectory(dir);
        fileName = String.format("%s/%s", dir, fileName);
    }

    /* Opens the Output Stream */
    FileOutputStream fileStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);

    /* Joins String Array into one string to be written to the file */
    String text = TextUtils.join(" ", data);

    /* Writes the String in bytes to the file stream */
    fileStream.write(text.getBytes());

    /* Closes the output stream */
    fileStream.close();

    //This Commented block was part of my previous method of writing files.
    /*
    OutputStreamWriter outputStream = new OutputStreamWriter(fileStream);

    for(int i = 0; i < data.length; i++){
        outputStream.write(data[i]);
        if(i < data.length - 1)
            outputStream.write("\n");
    }
    outputStream.close();
    */
}

 /**
 *
 * @param filePath - Relative Filepath of the file being accessed
 * @param dir - Path of the Directory the file can be found in
 * @return - Array of Strings for containing each line of the accessed file.
 * @throws IOException
 */
private String[] readFile(String filePath, String dir) throws IOException {
    Log.v(LOG_TAG, "readFile");
    if(filePath == null)
        return null;

    /* Updates the Filepath with the directory */
    if(dir != null && dir.length() > 0)
        filePath = String.format("%s/%s", dir, filePath);

    String temp;
    ArrayList<String> list = new ArrayList<>();

    /* Initializing Input Stream & Reader */
    FileInputStream fileStream = new FileInputStream(new File(filePath));
    InputStreamReader inputStream = new InputStreamReader(fileStream);
    BufferedReader input = new BufferedReader(inputStream);

    /* Reads Each line into an Array List */
    while((temp = input.readLine()) != null){
        list.add(temp);
    }

    /* Close the Input Streams */
    input.close();
    inputStream.close();

    if(list.size() < 1)
        return null;

    String[] arr = new String[list.size()];
    arr = list.toArray(arr);

    return arr;
}

I need to be able to read, write, and delete text files and their containing directories in internal memory with consistency, and I'm quite confused as to what I'm doing wrong, as I know that should be relatively simple. Some information as to why these methods are not behaving as expected would be greatly appreciated.

4
  • Have you given your app permission to access files/folders? Commented Aug 1, 2016 at 21:24
  • @Robotia - apps always have permission to their internal storage folders, and cannot get permission to anyone else's unless the other party has given world access. This is more an misunderstanding of file names and a misuse of file methods. Commented Aug 1, 2016 at 22:53
  • As Chris mentioned I shouldn't really need it, but I DO have the WRITE_EXTERNAL_STORAGE permission in my manifest regardless, as I'm intending to provide this functionality as well (one step at a time, of course). Commented Aug 2, 2016 at 1:35
  • My bad, didn't catch that by internal you meant internal app storage! Commented Aug 3, 2016 at 13:13

1 Answer 1

1

In your readFile-method you get the filepath, which I assume might look like this: data/user/0/com.app.package/files/recordings/examplefile1.xml and this paths directory, which in this case might look like this: data/user/0/com.app.package/files/recordings.

Afterwards you concatenate these two strings with an path separator inbetween. This would result in following in my example: data/user/0/com.app.package/files/recordings/data/user/0/com.app.package/files/recordings/examplefile1.xml

Let's say you pass in the directory as follows: data/user/0/com.app.package/files/recordings/ This path would then result in following: data/user/0/com.app.package/files/recordings//data/user/0/com.app.package/files/recordings/examplefile1.xml

So I see two points

  1. You have to make sure the filePath parameter only contains the filename
  2. You have to make sure that there is no path separator at the end of the dir parameter already
Sign up to request clarification or add additional context in comments.

3 Comments

Indeed - but it's actually worse than that. Context's openFileInput() and openFileOutput() methods themselves expect bare file names without a path, so if the exception weren't thrown, the directory path would actually be in there three times in whatever access were ultimately attempted.
I've confirmed that both your points are met. Here is logcat output (only 2 lines) indicating the values for each variable (it's uniform for each method call): 08-01 22:31:13.647 7183-7183/com.app.package D/FILE-MANAGER: Directory: data/user/0/com.app.package/files/recordings 08-01 22:31:13.647 7183-7183/com.app.package D/FILE-MANAGER: Filepath: 2016_08_02_02_31_13.txt
How did you obtain the directory? I just tested getting the path of the internal storage of an own app with the getFilesDir-method, and in my case it had a leading path seperator... So it looks like this /data/data/com.jonny9298.backboardtest/files

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.