I am developing an app. In which I am uploading different file types (e.g. docx, pdf, zip) to a WAMP Server. Below is path of file to my internal Storage.
/storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt
I have added and allowed storage permission in Manifest file and also on runtime for reading a file. However there is no Internal Storage Permission request available.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
and also for Android 10 I was using this attribute also
android:requestLegacyExternalStorage="true"
But I am getting this error on Android 11 OS a.k.a Android R onboard Samsung Galaxy when I am reading file from Internal Storage for uploading.
java.io.FileNotFoundException: /storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt: open failed: EACCES (Permission denied)
On An Android 11 device your app only has access to its own files.
And to general mediafies in public directories.
Try to list the files in that whatsapp directory and you will see that
they are not listed.
You have two options to read the file.
Let the user pick the file with ACTION_OPEN_DOCUMENT. Request
MANAGE_EXTERNAL_STORAGE in manifest and let the user confirm.
Ordinary request is not working for the MANAGE_EXTERNAL_STORAGE permission. This permission must be set in Android setting by user.
You can try to use the android:preserveLegacyExternalStorage="true" tag in the manifest file in the application tag. This tag is used to access the storage in the android 11 devices. And for more detail follow this link it will explain you more as per your requirement.
I search a lot of time and get the solution that adds <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> in the manifest file and try to get the file access permission in the android 11 phones. Then you will open and read the file from the storage.
But the thing is that the play store does not allow you to use of the MANAGE_EXTERNAL_STORAGE permission in your app. it will take time to give access to the developer to use it to access all the files.
Here the link is
For Android 11 or above use the code below on the onCreate() of the activity. It will run once and ask for permission.
if (Build.VERSION.SDK_INT >= 30){
if (!Environment.isExternalStorageManager()){
Intent getpermission = new Intent();
getpermission.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(getpermission);
}
}
Next declare the MANAGE_EXTERNAL_STORAGE permission in the manifest.
However, the problem with this method is that you cannot upload it to play store if you don't have a good reason on why you need access to all files.
On An Android 11 device your app only has access to its own files.
And to general mediafies in public directories.
Try to list the files in that whatsapp directory and you will see that they are not listed.
You have two options to read the file.
Let the user pick the file with ACTION_OPEN_DOCUMENT.
Request MANAGE_EXTERNAL_STORAGE in manifest and let the user confirm.
Try to get path with this method.....
public static String getDriveFile(Context context, Uri uri) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getCacheDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
I worked on Android application based on Cordova and I had to change the version the application was focused on to save files in the device.
I change the API Level version to 28 and works correctly. This change is used to avoid the scoped storage feature added on Android 10.
This information is extracted from this page:
https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage
I hope this information is helpful.
First, check whether you have implemented scoped storage logic in-app.
You can also use android:requestLegacyExternalStorage="true"
But this legacyStoragePermission is limited to version 10.
You need to implement scoped logic.
Also, check whether your targetSDKVersion value is 30 or greater or not,
this is needed if you are using the app in Device android version 30 or more.
I spent a week getting the info on how to read files from External storage on Android 11 API 29 and Later.
You still need Manifest permission READ_EXTERNAL_STORAGE.
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// Open a specific media item using ParcelFileDescriptor.
ContentResolver resolver = getApplicationContext()
.getContentResolver();
// "rw" for read-and-write;
// "rwt" for truncating or overwriting existing file contents.
String readOnlyMode = "r";
// uri - I have got from onActivityResult
//uri = data.getData();
ParcelFileDescriptor parcelFile = resolver.openFileDescriptor(uri, readOnlyMode);
FileReader fileReader = new FileReader(parcelFile.getFileDescriptor());
BufferedReader reader = new BufferedReader(fileReader);
String line;
while ((line = reader.readLine()) != null) {
//Your action here!!!
}
reader.close();
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
Read this: Open a media file.
from android 10, it is not possible to access all the files through your app,
so while saving data for example image , use following code and then you can read it normally. getExternalFilesDir is important
File file=new File(getActivity().getApplicationContext().getExternalFilesDir(null),"/scantempo"+"/Image_" + System.currentTimeMillis() + ".jpg");
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
Uri uri=Uri.fromFile(file);
return uri;
After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag.
For read files from external storage following codes:
fun startFilePicker(activity: Activity, requestCode: Int) {
val pickIntent: Intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
type = "*/*"
}
activity.startActivityForResult(pickIntent, requestCode)
}
override fun onActivityResult(requestCode : Int , resultCode : Int , data : Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val fileUri=data.data
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(
fileUri,
takeFlags
)
}
Create temp file
fun createTempFileForUpload(context:Context,fileUri:Uri){
val docFile = DocumentFile.fromSingleUri(context, fileUri)
val fileName: String = if (docFile == null || docFile.name.isNullOrBlank()) {
FilenameUtils.getName(fileUri.path)
} else {
docFile.name!!
}
val tempFile = File.createTempFile("tempFile", "tmp")
val ins: InputStream = context.contentResolver.openInputStream(fileUri)!!
val out: OutputStream = FileOutputStream(tempFile)
val buf = ByteArray(1024)
var len: Int = ins.read(buf)
while (len > 0) {
out.write(buf, 0, len)
len = ins.read(buf)
}
out.close()
ins.close()
tempFile.mkdirs()
}
Then you can upload temp file .
You can change allowBackup from true to false in Manifest's application part. It worked for me.
android:allowBackup="false"
I have finished my Chess UI application and now want to load a chess engine to test if my UI truly is UCI-compatible. The chess engine is inside the Download folder of the Android device ('/storage/emulated/0/Download'). This is the code that is run:
try {
File f = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String path = f.getAbsolutePath();
String stockfishPath = path + "/Stockfish-9-armv64v8";
engineProcess = Runtime.getRuntime().exec(stockfishPath);
processReader = new BufferedReader(new InputStreamReader(
engineProcess.getInputStream()));
String sCurrentLine;
ArrayList<String> output = new ArrayList<>();
while ((sCurrentLine = processReader.readLine()) != null) {
output.add(sCurrentLine);
}
processWriter = new OutputStreamWriter(
engineProcess.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
When I run this it fails on the exec() method because it claims it cannot find the file, even though the file exists on the Android device. I tried running the "ls" command on the exec() method, but the folder inside "emulated" is empty. The obvious reason for this is probably because I do not have permission to view/access these files, but I need to know how I can do that (despite adding the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE in the manifest file).
Is it maybe possible to embed the engine somewhere in the project (in resources?) and somehow adb-shell into that?
you cannot do that, simply because the SD card is being mounted with -noexec flag.
using the internal storage with chmod +x would be the only option available.
I'm trying to decompress RAR archive on my Android device from the sd card but I got an error:
java.io.FileNotFoundException: /mnt/sdcard: open failed: EISDIR (Is a directory)
I chose a rar-file and try to decompress it in my sd-card.
Error says that it's not directory but it is. I have no idea how I can fix it.
My code:
public static void unrar(File srcRarFile, String destPath, String password) throws IOException {
if (null == srcRarFile || !srcRarFile.exists()) {
throw new IOException(".");
}
if (!destPath.endsWith(SEPARATOR)) {
destPath += SEPARATOR;
}
Archive archive = null;
OutputStream unOut = null;
try {
archive = new Archive(srcRarFile, password, false);
FileHeader fileHeader = archive.nextFileHeader();
while(null != fileHeader) {
if (!fileHeader.isDirectory())
{
// 1 destDirName destFileName
String destFileName = "";
String destDirName = "";
destFileName = (destPath + fileHeader.getFileNameW()).replaceAll("/", "\\\\");
destDirName = destFileName.substring(0, destFileName.lastIndexOf("\\"));
// 2
File dir = new File(destDirName);
if (!dir.exists() || !dir.isDirectory()) {
dir.mkdirs();
}
//
// ERROR:
unOut = new FileOutputStream(dir);
archive.extractFile(fileHeader, unOut);
unOut.flush();
unOut.close();
}
fileHeader = archive.nextFileHeader();
}
archive.close();
} catch (RarException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(unOut);
}
}
Clear thing. You first create the directory /mnt/sdcard (variable dir is equal to destDirName in your code) and then you try to create a file with the same same. This will not work. Use a name like /mnt/sdcard/abc.rar and it might work. Here is how you create the corresponding File object:
File file = new File(dir, "abc.rar");
Btw: creating a directory called /mnt/sdcard will probably not work due to a lack of permissions. If it's an SD card, Android will do this job for you anyway. If it isn't an SD card, its not a good idea to create a directory with this name.
PS2: After further reviewing your code I see things which are not good style:
You are using the separater variable and indexOf/substring to find the parent directory.
You replace "/" (the android path separator) by "\" which is only used in Windows
You swap between File and string
You can simply get rid of all this by using File.getParent()/File.getParentFile()
Check if you have set permissions in your manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I want to programmatically access a specific file which will be included in my project folder. Is there a way to do this? If so, where in my project folder do I put the file, and what is some simple code to get its file path?
private void saveFileToDrive() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
java.io.File spreadsheet = new java.io.File("Untitled spreadsheet.xlsx");
String filePath = spreadsheet.getAbsolutePath();
System.out.println("file path is"+filePath);
URL fileURL = getClass().getClassLoader().getResource("Untitled spreadsheet.xlsx");
String filePath2 = fileURL.getPath();
System.out.println("file path2 is"+filePath2);
java.io.File fileContent = new java.io.File(filePath);
FileContent mediaContent = new FileContent("application/vnd.ms-excel", fileContent);
File body = new File();
body.setTitle(fileContent.getName());
body.setMimeType("application/vnd.ms-excel");
File file = service.files().insert(body, mediaContent).setConvert(true).execute();
if (file != null) {
showToast("File uploaded: " + file.getTitle());
}
else
;
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
}
Put the file in root folder of your project. Then get the File URL, Path and other details as:
File file = new File("test.txt");
String filePath = file.getAbsolutePath();
EDIT: Alternate way (if the file is in your classpath e.g. put the file in "src" folder, and make sure its moved in "bin" or "classes" folder after compilation):
URL fileURL = getClass().getClassLoader().getResource(fileName);
String fileName = fileURL.getFile();
String filePath = fileURL.getPath();
This depends a lot on what type of file you want to access. You can put the file in either assets or an appropriate subdirectory of res (see Difference between /res and /assets directories).
So you want to access a file internal to your app; and you want to do so directly, rather, that is, from an Android Context (and then with a [android.|<package_name>.]R.<resource_type>.<resource_name>).
You have two choices as to location: the res/raw folder or assets/ folder (outside of the res parent).
To choose between the two note from https://developer.android.com/guide/topics/resources/providing-resources.html
Arbitrary files to save in their raw form. To open these resources with a raw InputStream, call Resources.openRawResource() with the resource ID, which is R.raw.filename.
However, if you need access to original file names and file hierarchy, you might consider saving some resources in the assets/ directory (instead of res/raw/). Files in assets/ aren't given a resource ID, so you can read them only using AssetManager.
To access a file in res/raw/ directly rather, that is, from an Android Context (and then with a [android.|<package_name>.]R.<resource_type>.<resource_name>) you can do something like this:
File file = new File("app/src/main/res/raw/country_data_from_world_bank.xml");
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
I'm sorry for a rather green question, but I could not find solution yet.
I am trying to restore a database from a back up on SD Card. The following code (a slight modified version of one provided here in SO)
try {
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
if (sd.canWrite()) {
String currentDBPath =
"\\data\\com.dg\\databases\\" + com.dg.Constants.db_Table;
String backupDBPath = "com.dg";
File currentDB = new File(data, currentDBPath);
File backupDB = new File(sd, backupDBPath);
if (currentDB.exists()) {
FileChannel dst = new FileInputStream(currentDB).getChannel();
FileChannel src = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
}
line4.setText("Successful Import");
}
} catch (Exception e) {
line4.setText(e.toString());
}
Throws NonWriteableChannelException even though the database file is not open.
Your data is GENERALLY in
/data/data/com.dg/databases
You need to get rid of the double \ in the path.
Also, you're using Environment.getDataDirectory() as the parent directory, then "\data\com.dg\databases\"(etc) as the file name. That's totally wrong.
The easy way to go might be 'getDatabasePath' in Context (or Activity). Give it the name of your DB and it should give you a File reference to it. However, I don't know what it would do if that File didn't exist yet.
http://developer.android.com/reference/android/content/Context.html#getDatabasePath(java.lang.String)
You may also try simple 'getDir("databases", MODE_PRIVATE)'. That would hopefully return the database dir.
Final try for the database dir, really dirty:
File dbDir = new File(getFilesDir().getParentFile(), "databases");
Does your user / app have permissions to //database? (If not, then THIS IS THE ANSWER.)
Perhaps this might tell you why permission is denied:
IOException: Permission Denied
Bill Mote (from the above link) also pointed out the following permission setting:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />