Saving to sd card challenge


#1

Hey guys.

So I’m a bit stuck with the saving to external memory challenge. I believe I’m making some kind of mistake with the Context class’ openFileOutput() and openFileInput() methods.

Method for saving crimes.

public void saveCrimes(ArrayList<Crime> crimes) throws JSONException, IOException {
		// Build an array in JSON
		JSONArray array = new JSONArray();
		for (Crime c: crimes)
			array.put(c.toJSON());
		
		// Write the file to disk
		Writer writer = null;
		try {
			OutputStream out = null;
			if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
				// Save to sd card if available.
				out = mContext.openFileOutput(Environment.getExternalStorageDirectory().getPath() + "/CriminalIntent/" + mFilename, Context.MODE_WORLD_READABLE); // Mode is deprecated?
			else
				out = mContext.openFileOutput(mFilename, Context.MODE_PRIVATE);
			writer = new OutputStreamWriter(out);
			writer.write(array.toString());
		} finally {
			if (writer != null)
				writer.close();
		}
	}

Method for loading crimes.

	public ArrayList<Crime> loadCrimes() throws IOException, JSONException {
		ArrayList<Crime> crimes = new ArrayList<Crime>();
		BufferedReader reader = null;
		try {
			InputStream in = null;
			// Open and read the file into a StringBuilder.
			if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
				// Load from sd card if available.
				in = mContext.openFileInput(Environment.getExternalStorageDirectory().getPath() + "/CriminalIntent/" + mFilename);
			else
				in = mContext.openFileInput(mFilename);
			reader = new BufferedReader(new InputStreamReader(in));
			StringBuilder jsonString = new StringBuilder();
			
			String line = null;
			while ((line = reader.readLine()) != null)
				// Line breaks are omitted and irrelevant
				jsonString.append(line);
			
			// Parse the JSON using JSONTokener.
			JSONArray array = (JSONArray) new JSONTokener(jsonString.toString()).nextValue();
			
			// Build the array of crimes from JSONObjects
			for (int i = 0; i <array.length(); ++i)
				crimes.add(new Crime(array.getJSONObject(i)));
		} catch (FileNotFoundException e) {
			// Starting without a file, so ignore.
		} finally {
			if (reader != null)
				reader.close();
		}		
		return crimes;
	}

Whenever I try to read or write I get an IllegalArgumentException saying that the file contains a path separator. The file I’m trying to read and write from has an absolute path of “/mnt/sdcard/CriminalIntent/crimes.json” which is correctly reflected in the exception. Does the openFileInput and openFileOutput methods not take a path name? Am I suppose to use one of the other Java I/O classes to achieve this? I also looked up how to add read/write permissions in the manifest file but it didn’t make a difference either.

Also this is probably related to my core issue but Context.MODE_WORLD_READABLE has been deprecated. What mode should I be using for this operation?

Thanks!


#2

Me too
I got the same problem but instead of using Context.MODE_WORLD_READABLE I used 0 which is quite legitimate
My unhelpful solution was to go into GIT Reflog and reset to the previous commit :confused:
this tidied everything up and I could then start again on the problem, or maybe not


#3

Instead of using OutputStreamWriter and InputStreamReader try substituting FileWriter and FileReader respectively. Wrap the FileReader with a BufferedReader object and then proceed the same as if writing/reading to internal app storage in terms of serializing/deserializing the JSON object.


#4

You could also make these small changes to your methods:

saveCrimes:

 public void saveCrimes(ArrayList<Crime> crimes) throws JSONException, IOException {
          // Build an array in JSON
          JSONArray array = new JSONArray();
          for (Crime c: crimes)
             array.put(c.toJSON());
          
          // Write the file to disk
          OutputStreamWriter writer = null;
          try {
             FileOutputStream out = null;
             if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                // Save to sd card if available.
                out = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/CriminalIntent/" + mFilename);
             else
                out = mContext.openFileOutput(mFilename, Context.MODE_PRIVATE);
             writer = new OutputStreamWriter(out);
             writer.write(array.toString());
          } finally {
             if (writer != null)
                writer.close();
          }
       }

loadCrimes:

public ArrayList<Crime> loadCrimes() throws IOException, JSONException {
          ArrayList<Crime> crimes = new ArrayList<Crime>();
          BufferedReader reader = null;
          try {
             FileInputStream in = null;
             // Open and read the file into a StringBuilder.
             if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                // Load from sd card if available.
                in = new FileInputStream(Environment.getExternalStorageDirectory().getPath() + "/CriminalIntent/" + mFilename);
             else
                in = mContext.openFileInput(mFilename);
             reader = new BufferedReader(new InputStreamReader(in));
             StringBuilder jsonString = new StringBuilder();
             
             String line = null;
             while ((line = reader.readLine()) != null)
                // Line breaks are omitted and irrelevant
                jsonString.append(line);
             
             // Parse the JSON using JSONTokener.
             JSONArray array = (JSONArray) new JSONTokener(jsonString.toString()).nextValue();
             
             // Build the array of crimes from JSONObjects
             for (int i = 0; i <array.length(); ++i)
                crimes.add(new Crime(array.getJSONObject(i)));
          } catch (FileNotFoundException e) {
             // Starting without a file, so ignore.
          } finally {
             if (reader != null)
                reader.close();
          }      
          return crimes;
       }