Android mkdirs () creates file with zero byte instead of folder

In my Android app, I am trying to create the following folder on an SD card:

/mnt/sdcard/OSGiComponents/admin/felix-cache/ 

Here is the code:

 File cacheDir = new File( Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents/admin/felix-cache/" ); // Create the folder cacheDir.mkdirs(); // Check if it exists if ( ! cacheDir.exists() ) { Log.e ( "Debug" , "Cache directory cannot be created" ); } 

I have WRITE_STORAGE_PERMISSION in the manifest tag of an android manifest file. I can create other folders and files without problems on the SD card. The application works fine on the following phones:

  • Nexus S (root) runs Gingerbread (2.3)
  • Nexus S (unrooted) runs Jelly Bean (4.1.2)
  • HTC Desire (with root) runs Froyo (2.2)
  • HTC Desire (untouched) runs Froyo (2.2)

However, Ice Cream Sandwich (4.0.4) runs on the Samsung Galaxy Nexus (without root), the directory is created as a zero-size file that can be seen in Astro. Calling exists () returns false.

Astro showing a zero byte felix-cache file

  • As you can see from the folder name, I am using Apache Felix. Felix automatically creates a cache directory if it does not exist. At Galaxy Nexus, he always complained that he could not create a cache directory. Astro displays a 0-byte file instead of a folder. This is why I decided to try creating a cache folder before initializing Felix.
  • So, I create the cache folder myself. The application works fine for the first time, and I see a folder in Astro. If I close the application and then delete the folder in Astro and then run the application again, even my code will not mysteriously be able to create the cache directory, and Astro will display a 0-byte file.
  • A 0-byte file cannot be deleted in Astro. However, when I restart the phone, the folder there is magical and normal.
  • I use FileInstall to view the OSGiComponents / install folder. When I drop packets to this folder, it is detected and installed normally on all phones except Galaxy Nexus (when the application works for the first time). There are no logs / errors in FileInstall about the impossibility of viewing the directory.
  • I tested this on 2 Galaxy Nexus phones, same problem.

I suspect this is a permissions issue, but I'm not sure what it is and why a 0 byte file is being created and exists () returns false. Nowhere in the code do I create this file.

Any suggestions on what could be the problem?

Thanks:)

UPDATE: I think I have identified the problem, see the answer I posted.

+7
source share
5 answers

I found a workaround that solves this problem. Whenever I delete a file / directory, instead of using delete () directly, I will rename the file / folder and then delete () it. This weird workaround seems to fix the problem.

I got this idea after seeing the answers to this question - Open an idle EBUSY device or a busy resource

However, I'm not sure why this works or what caused the problem in the first place.

If someone else uses Felix on the Galaxy Nexus and faces the same problem, just change the Felix source code as shown below:

org.apache.felix.framework.util.SecureAction.java:

 public boolean deleteFile(File target) { if (System.getSecurityManager() != null) { try { Actions actions = (Actions) m_actions.get(); actions.set(Actions.DELETE_FILE_ACTION, target); return ((Boolean) AccessController.doPrivileged(actions, m_acc)) .booleanValue(); } catch (PrivilegedActionException ex) { throw (RuntimeException) ex.getException(); } } else { // Solution: Rename before deleting // /questions/159700/open-failed-ebusy-device-or-resource-busy File to = new File(target.getAbsolutePath() + System.currentTimeMillis()); boolean renameStatus = target.renameTo(to); boolean deleteStatus = to.delete(); boolean returnStatus = ( renameStatus && deleteStatus ); // Debug SecureAction //boolean returnStatus = target.delete(); Log.e ( "SecureAction" , "Deleting " + target + " delete(): " + returnStatus ); return returnStatus; } } 
+2
source

use instead

  File cacheDir = new File( Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents/admin/felix-cache/" ); cacheDir.mkdirs(); 

to

  File cacheDir = new File( Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents/admin/felix-cache" ); cacheDir.mkdir(); 
+2
source

I suggest connecting to the device using adb and using the ls -l in the directory to check what the operating system is reporting this 0 size file (permissions, etc.). This may ultimately cause some light in this matter.

If you cannot determine a working solution, perhaps you can do a workarround with exec() to execute mkdir directly.

You can use the bottom cobe strap to do this:

 public static boolean execCmd(String command, ArrayList<String> results){ Process process; try { process = Runtime.getRuntime().exec(new String [] {"sh", "-c", command}); } catch (IOException e) { e.printStackTrace(); return false; } int result; try { result = process.waitFor(); } catch (InterruptedException e1) { e1.printStackTrace(); return false; } if(result != 0){ //error executing command Log.d("execCmd", "result code : " + result); String line; BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); try { while ((line = bufferedReader.readLine()) != null){ if(results != null) results.add(line); Log.d("execCmd", "Error: " + line); } } catch (IOException e) { e.printStackTrace(); return false; } return false; } //Command execution is OK BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; try { while ((line = bufferedReader.readLine()) != null){ if(results != null) results.add(line); Log.d("execCmd", line); } } catch (IOException e) { e.printStackTrace(); return false; } return true; } 

To use it:

 boolean res= execCmd("mkdir "+ Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents", results); if(!res) return error; res= execCmd("mkdir "+ Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents/admin", results); if(!res) return error; res= execCmd("mkdir "+ Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents/admin/felix-cache", results); if(!res) return error; 

Sincerely.

+1
source
 String root = Environment.getExternalStorageDirectory() .getAbsolutePath()+"/OSGiComponents/admin/felix-cache"; File myDir = new File(root); String fname = "Image Name as you want"; File file = new File(myDir, fname); if (file.exists()) file.delete(); try { FileOutputStream out = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 90, out); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } 
+1
source

Although this is not a direct answer to your question, the information mentioned below may help you:

On some devices, Environment.getExternalStorageDirectory().getAbsolutePath() does not necessarily reflect the actual external path of the SD card. Sometimes it is an internal repository.

for example, in Galaxy Note 2:

 Log.i(TAG,Environment.getExternalStorageDirectory().getAbsolutePath()); 

will print

12-19 17: 35: 11.366: E / sample.Examples (10420): / storage / sdcard0

Meanwhile, the actual external SD card should be:

/ storage / extSdCard

Below are a few posts regarding these issues that may help you:

Building a utility to get a path to an external removable storage each time

Check if sdcard is present, boolean is always true

How can I get the correct external storage on Samsung and all other devices?

Android how to use Environment.getExternalStorageDirectory ()

0
source

All Articles