简体   繁体   中英

Can't write to SD card

My app allows user to take a picture and I want that picture to be stored in the app's external files directory ( getExternalFilesDir(null) ). It all works except for the call to renameTo() , this call returns false and I don't know why.

The src file is:

/storage/extSdCard/DCIM/Camera/20140424_154458.jpg

Dest file is:

/storage/emulated/0/Android/data/com.myapp.myapp/files/20140424_154458.jpg

I also have specified the WRITE_EXTERNAL_STORAGE permission.

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    if (item.getItemId() == R.id.action_take_picture)
    {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, TAKE_PICTURE_REQUEST_CODE);
        return true;
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    if (requestCode == TAKE_PICTURE_REQUEST_CODE && resultCode == RESULT_OK)
    {
        File dest = new File(
            getExternalFilesDir(null),
            new SimpleDateFormat("yyyyMMdd_hhmmss", Locale.getDefault()).format(new Date()) + ".jpg");

        File src = new File(convertMediaUriToPath(data.getData()));
        if (src.renameTo(dest)) // Always returns false
        {
            mAdapter.add(dest);
            mAdapter.notifyDataSetChanged();
        }
    }
}

private String convertMediaUriToPath(Uri uri)
{
    String[] proj = {MediaStore.Images.Media.DATA};
    Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String path = cursor.getString(column_index);
    cursor.close();

    return path;
}

I have ran into this problem previously - unfortunately, you are not allowed to use renameTo to move files and/or directories between different mount points (for example, internal and external storage). Consider using a different way of moving files, such as the one outlined here:

http://www.mkyong.com/java/how-to-copy-directory-in-java/

public static void copyFolder(File src, File dest) throws IOException{

    if(src.isDirectory()){

        //if directory not exists, create it
        if(!dest.exists()){
           dest.mkdir();
           System.out.println("Directory copied from " 
                          + src + "  to " + dest);
        }

        //list all the directory contents
        String files[] = src.list();

        for (String file : files) {
           //construct the src and dest file structure
           File srcFile = new File(src, file);
           File destFile = new File(dest, file);
           //recursive copy
           copyFolder(srcFile,destFile);
        }

    }else{
        //if file, then copy it
        //Use bytes stream to support all file types
        InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest); 

            byte[] buffer = new byte[1024];

            int length;
            //copy the file content in bytes 
            while ((length = in.read(buffer)) > 0){
               out.write(buffer, 0, length);
            }

            in.close();
            out.close();
            System.out.println("File copied from " + src + " to " + dest);
    }
}

The problem is with the method renameTo , the renameTo doesn't create subdirectories,

Reason being The current File API isn't very well implemented in Java. There is a lot of functionality that would be desirable in a File API that isn't currently present such as move, copy and retrieving file metadata.

I don't think anyone will be able to give you an answer as to why the API is written as is. Probably a poor first draft that went live and couldn't be changed due to backwards compatibility issues.

These issue have been addressed in the Java 7. A entirely new API has been created to deal with files java.nio.file.Files .

To Solve this issue, try to get directory path of destination file eg /storage/emulated/0/Android/data/com.myapp.myapp/files/20140424_154458.jpg

Destination Directory is /storage/emulated/0/Android/data/com.myapp.myapp/files/

Use mkdirs() , it will create all sub directories for you

If you want to add a file or folder or move application into your SD Card just do the following:

steps:

1) Open your Android application's source code file with a text or programming editor. 2) Browse to the location in the source code where you wish to call the function that writes a file to the device's external storage. 3) Insert this single line of code to check for the SD card:

File sdCard = Environment.getExternalStorageDirectory();

4) Insert these lines of code to set the directory and file name:

File dir = new File (sdcard.getAbsolutePath() + "/folder1/folder2");
dir.mkdirs();
File file = new File(dir, "example_file");

// The mkdirs function will create the directory folder for you, use it only you want to create a new one.

5) Replace "/folder1/folder2" in the above code with the actual path where you intend to save the file. This should be a location in which you normally save your application files. Also, change the "example_file" value to the actual file name you wish to use.

6) Insert the following line of code to output the file to the SD card:

FileOutputStream f = new FileOutputStream(file);
Finally step 7:

Save the file, then compile it and test the application using the Android emulator software or the device.

This will work!!! ;-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM