Can't create a directory in external sd card (

2019-07-08 02:49发布

问题:

I have no problem with internal storage but I want to create a directory on the external SD card, with versions prior to KitKat, File.mkdirs() works.

There is part of my code:

//external sd card
DocumentFile.fromFile(new File("/storage/sdcard1/")).exists(); //returns true
DocumentFile.fromFile(new File("/storage/sdcard1/")).canRead(); //returns true
DocumentFile.fromFile(new File("/storage/sdcard1/")).canWrite(); //returns true
DocumentFile.fromFile(new File("/storage/sdcard1/test")).exists(); //returns false
DocumentFile.fromFile(new File("/storage/sdcard1/")).createDirectory("test"); //returns null

//internal storage
DocumentFile.fromFile(new File("/storage/emulated/0/")).exists(); //returns true
DocumentFile.fromFile(new File("/storage/emulated/0/test")).exists(); //returns false
DocumentFile.fromFile(new File("/storage/emulated/0/")).createDirectory("test"); //it works
DocumentFile.fromFile(new File("/storage/emulated/0/test")).exists(); //returns true
DocumentFile.fromFile(new File("/storage/emulated/0/test")).createFile("text", "file.txt"); //it works

//external sd card
(new File("/storage/sdcard1/test2/subfolder")).exists(); //returns false
(new File("/storage/sdcard1/test2/subfolder")).mkdirs(); //returns false

//internal storage
(new File("/storage/emulated/0/test2/subfolder")).exists(); //returns false
(new File("/storage/emulated/0/test2/subfolder")).mkdirs(); //returns true

In AndroidManifest.xml:

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

Testing with an BQ Aquaris e4, Android Lollipop 5.0 and a 1GB micro SD card.

UPDATE: This is how I get the volume list:

private static ArrayList<StorageInfo> listAvaliableStorage(Context context) {
        ArrayList<StorageInfo> storagges = new ArrayList<>();
        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        try {
            Class<?>[] paramClasses = {};
            Method getVolumeList = StorageManager.class.getMethod("getVolumeList", paramClasses);
            getVolumeList.setAccessible(true);
            Object[] params = {};
            Object[] invokes = (Object[]) getVolumeList.invoke(storageManager, params);
            if (invokes != null) {
                StorageInfo info;
                for (Object obj : invokes) {
                    Method getPath = obj.getClass().getMethod("getPath");
                    String path = (String) getPath.invoke(obj);
                    info = new StorageInfo(path);
                    File file = new File(info.getPath());
                    if ((file.exists()) && (file.isDirectory())
                        //&& (file.canWrite())
                            ) {
                        info.setTotalStorage(file.getTotalSpace());
                        info.setFreeStorage(file.getUsableSpace());
                        Method isRemovable = obj.getClass().getMethod("isRemovable");
                        String state;
                        try {
                            Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);
                            state = (String) getVolumeState.invoke(storageManager, info.getPath());
                            info.setState(state);
                            info.setRemovable((Boolean) isRemovable.invoke(obj));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        storagges.add(info);
                    }
                }
            }
        } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        storagges.trimToSize();

        return storagges;
    }

The hard coded paths is only for this example

UPDATE 2: I've created the directory: "test" in SD Card with a file explorer. When I execute this code:

File file = new File("/storage/sdcard1/test/", "file.txt");
fileOutput = new FileOutputStream(file);

The second line throws FileNotFoundException: /storage/sdcard1/test/file.txt: open failed: EACCES (Permission denied)

What am I doing wrong?

回答1:

That is due to the design of Android Lollipop. Environment.getExternalStorageDirectory() will return only the path of emulated external storage. Android does not expose any API that gives you the path of the sdcard.

Also, in Lollipop, apps cannot write to location outside of their own directory in the sdcard, unless user permission is obtained through Storage Access Framework.

Try context.getExternalFilesDirs(). That gives you a list of paths where your app can write data to. One of it will be in the sdcard and will go like /storage/sdcardname/Android/data/yourAppName/files



回答2:

you have to explicitly define the location, here is a short script I made to create a folder and a folder inside that folder, hope this helps

    import java.io.File;
    import android.app.Activity;
    import android.content.Context;
    import android.os.Bundle;
    import android.os.Environment;
    import android.widget.Toast;

public class DirectoryPicker extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.chooser_list);//your xml layout file name
}
@Override
public void onStart() {
    super.onStart();
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) { // **Check that we have access to create the folder(s)**
        File Root = Environment.getExternalStorageDirectory(); //**Get the path and hold it**
//**Alternativly you can select a certain directory with**
//File Root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File folder = new File(Root.getAbsolutePath() + "/main_folder_to_add/second_folder/");//**This puts everything together CORRECTLY**
        folder.mkdirs();//**Makes the directory folders, make sure to use mkdirs not mkdir**
        if (!folder.exists()) {
            folder.mkdirs();
        }
        Context context = getApplicationContext();//**Prove we were successful**
        String msg = folder.toString();
        Toast toast = Toast.makeText(context, msg, Toast.LENGTH_LONG);
        toast.show();
        return;
    }
}
public void onBackPressed() {

finish();
}
}