Reputation: 3858
I need to copy a file from the assets to the external storage. Here is my code:
File f = new File(Environment.getExternalStorageDirectory() + File.separator
+ "MyApp" + File.separator + "tessdata" + File.separator + "eng.traineddata");
if (!f.exists()) {
AssetManager assetManager = getAssets();
try {
f.createNewFile();
InputStream in = assetManager.open("eng.traineddata");
OutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory() + File.separator
+ "MyApp" + File.separator + "tessdata" + File.separator + "eng.traineddata");
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
out.write(buffer, 0, read);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (IOException e) {
Log.e("tag", "Failed to copy asset file: ", e);
}
}
I've also added the permission in the manifet
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The exception occurred when is executed f.createNewFile()
, saying "Permission denied".
How can I fix it please?
Upvotes: 21
Views: 52855
Reputation: 3468
I have googled so hard for an answer. Most solutions don't work for API 29. @ishann 's answer inspired me to search for android:requestLegacyExternalStorage . It turned out that they introduced the concept of scoped storage, which means an app can only access its dedicated folder by default. For example, the folder pattern for Pictures should now be like:
/storage/emulated/0/Android/data/com.myapp.myapp/files/Pictures
Creating files or folders in the global location will fail, even both permissions are granted:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
the following code worked for me:
File files[] = this.getApplicationContext().getExternalFilesDirs(Environment.DIRECTORY_PICTURES);
for(File f : files){
Log.e("debug", f.getAbsolutePath());
File newdir = new File(f.getAbsolutePath(), "/newtest/");
boolean result = newdir.mkdirs();
Log.e("debug", result + " ; " + newdir.exists());
break;
}
relevant documents
https://developer.android.com/training/data-storage#scoped-storage
Upvotes: 1
Reputation: 3918
Recently in API level 29, they have changed the way of accessing external storage. If you are trying to access public folders(i.e. Downloads) it will throw permission denied error.
You need to specify below code in your application tag in Manifest file.
android:requestLegacyExternalStorage="true"
Or you can save files in the root directory to avoid this error.
Upvotes: 35
Reputation: 364
If you are using SDK-23 you need to write permission in manifest file like this
<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE" />
Upvotes: 1
Reputation: 4408
In my case it was due to the Permissions popup required for API 23+, even if u have added permission in the manifest.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* @param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
Call this function when the app launches or when you need the permission.
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Detailed sample code for permissions can be found here.
Upvotes: 41
Reputation: 8872
Do f.mkdirs()
before f.createNewFile()
. You are probably trying to create a new file in a non-existent directory
Upvotes: 10
Reputation: 519
try this:
private void copy() {
File dirOri = new File(Environment.getExternalStorageDirectory() +"/somefolder/somefile");
File dirDest = new File(Environment.getExternalStorageDirectory() + "/yourfolder");
FileChannel src = null;
FileChannel dst = null;
try {
src = new FileInputStream(dirOri).getChannel();
dst = new FileOutputStream(dirDest).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
} catch (Exception e) {}
}
-- EDIT --
Add in manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Upvotes: 2