I am trying to store my output file in internal memory.but it throws java.io.FileNotFoundException Access is denied
private boolean crop() {
try {
FileOutputStream fos = null;
String filePath = CustomVideoGalleryActivity.videoPath.get(0);
Movie originalMovie = MovieCreator.build(filePath);
Track track = originalMovie.getTracks().get(0);
Movie movie = new Movie();
movie.addTrack(new AppendTrack(new CroppedTrack(track, 200, 800)));
Container out = new DefaultMp4Builder().build(movie);
String outputFilePath = Environment.getDataDirectory()+ "/output_crop.mp4";
fos = new FileOutputStream(new File(outputFilePath)); //throws Exception
out.writeContainer(fos.getChannel());
fos.close();
mProgressDialog.dismiss();
finish();
} catch (Exception e) {
Log.v("ONMESSAGE", e.toString());
e.printStackTrace();
mProgressDialog.dismiss();
return false;
}
return true;
}
You need to ask for write permission in your AndroidManifest.xml. In particular, the following line must be present:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
You shouldn't be looking at the Data Directory. This is a system directory in the phone's storage - usually /data - and your application will never have permission to write to it.
The directory your application should write files to is returned by the Context.getFilesDir() method. It will be something like /data/data/com.yourdomain.YourApp/files.
If you want to write to a file in the phone's storage use the Context.openFileOutput() method.
If you want the path to the SDCard then use Environment.getExternalStorageDirectory() method. To write to the SDCard you'll need to give your application the appropriate permissions by adding the following to your Manifest:
If you're going to write to the SDCard you'll also need to check its state with the getExternalStorageState() method.
If you're storing small files to do with your application then these can go into the phone's storage and not the SD Card, so use the Context.openFileOutput() and Context.openFileInput() methods.
So in your code consider something like:
OutputStream os = openFileOutput("samplefile.txt", MODE_PRIVATE);
BufferedWriter lout = new BufferedWriter(new OutputStreamWriter(os));
Related
I'm trying to copy file from within my application to the SD card, but I get the error eacces (permission denied). The OS is Android M and I have allowed runtime Storage permissions (checked in app info). I have also set the uses-permission in AndroidManifest.xml
<application>...</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Doesn't work if I copy to SD card
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/1032-2568/SomeFolder/
Error: java.io.FileNotFoundException: /storage/1032-2568/SomeFolder/SomeFile.txt: open failed: EACCES (Permission denied)
Works if I copy to internal storage
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/emulated/0/SomeFolder/
Code to copy file from source to destination
/*
* Below are the parameters I have tried
*
* inputPath - data/user/0/com.example.myapp/cache or data/user/0/com.example.myapp/cache/
* inputFile - /SomeFile.txt or SomeFile.txt
* outputPath - /storage/1032-2568/SomeFolder/ or /storage/1032-2568/SomeFolder
*/
public static void copyFile(String inputPath, String inputFile, String outputPath) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File (outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
out = new FileOutputStream(outputPath + inputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
}
catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
}
catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
ES File Explorer
I saw that ES File Explorer also cannot write anything on the SD Card on Redmi devices. Here's a video with solution. Following the steps worked for ES Explorer on my device. Can this be done programmatically?
As suggested by #CommonsWare here we have to use the new Storage Access Framework provided by android and will have to take permission from user to write SD card file as you said this is already written in the File Manager Application ES File Explorer.
Here is the code for Letting the user choose the "SD card" :
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), requestCode);
which will look somewhat like this :
And get the Document path in pickedDirand pass further in your copyFile block
and use this path for writing the file :
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode != RESULT_OK)
return;
else {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
copyFile(sdCard.toString(), "/File.txt", path + "/new", pickedDir);
}
}
public void copyFile(String inputPath, String inputFile, String outputPath, DocumentFile pickedDir) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File(outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
//out = new FileOutputStream(outputPath + inputFile);
DocumentFile file = pickedDir.createFile("//MIME type", outputPath);
out = getContentResolver().openOutputStream(file.getUri());
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
} catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
You need to add permission request run time in Android 6.0 (API Level 23) and up, here is the official docs
This is the code for WRITE_EXTERNAL_STORAGE
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG,"Permission is granted");
return true;
}
Ask for permission else like this
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
I have also got that problem but i solved by use the request the permission in run time and after forcefully give the permission.After the permission in App info of Android device. after declare the permission in manifest =>go to setting of your device => go to app info => go to permission =>
and finally allow the permission . just remember i just talking about after api level 22 means from marshmallow.
Its seems the runtime permission are implemented correctly but the issues seems from the device
If you are using Redmi than you have to manually allow the permission of specific app in Redmi security settings
This link shows how to enable permission in redmi security
After Android 4.3 on some devices, you can't get direct write access to FileSystem on SDcard.
You should use storage access framework for that.
I can see that you are copying the entire content of one file and trying to write the same to another file. I could suggest a better way to do this :
Assuming that you already checked for file existence
StringWriter temp=new StringWriter();
try{
FileInputStream fis=new FileInputStream(inputFile+inputPath);
int i;
while((i=fis.read())!=-1)
{
temp.write((char)i);
}
fis.close();
FileOutputStream fos = new FileOutputStream(outputPath, false); // true or false based on opening mode as appending or writing
fos.write(temp.toString(rs1).getBytes());
fos.close();
}
catch (Exception e){}
This code worked for my app...Let me know if this is working for you or not..
You can't copy or Delete files & Folder on external storage using third party app. like [file explorer].
It's data policy updated after KITKAT Version.
If only allow on system apps. So you can use an original file explorer (Come from ROM).
IF you need to use 3rd party app then ROOT your device. (Root permission is required)
I'm using the openFileOutput() to create a new txt file. I need the file to be visible from other applications (as well as from a PC when the Android device is connected via USB. Ive tried using .setReadable(true); but this does not seem valid. Please advise how I should declare the file is visible / public.
try {
textIncoming.append("saving");
final String STORETEXT = "test.txt";
OutputStreamWriter out = new OutputStreamWriter(openFileOutput(STORETEXT, 0));
out.setReadable(true);
out.write("testing");
out.close();
}
catch (Throwable t) {
textIncoming.append("not saving");
}
Ive changed my program to use getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), but for some reason it returns a path /storage/emulated/0/Documents, and I cant even find this folder on the device. Ive looked at the files on the android device using ES file explorer but cant find the folder or file I'm trying to create (Plus I want these in an documents folder on the SD card, so it seems that its not giving me a pointer to the SD card at all, and not creating the folder, and not creating the file. Following is my updated code, please advise
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString();
File myDir = new File(root + "/Saved_Receipts");
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "DRcpt-" + n + ".xml";
textIncoming.append(root);
File file = new File(myDir, fname);
if (file.exists()) {
file.delete();
}
try {
FileOutputStream out = new FileOutputStream(file);
out.flush();
out.close();
}
catch (Exception e) {
e.printStackTrace();
}
Save it to sdcard if you want anyone to be able to read it.
This android documentation should tell you what you need to do.
https://developer.android.com/guide/topics/data/data-storage.html#filesExternal
openFileOutput() documentation says:
Open a private file
So the file that it creates won't be visible to other apps, unless you copy it to another directory that is visible. In that case, you have to save your data in what's called "external storage" which is shared with other apps. Use the code at this link.
So I'm using the twitter api and I want to tweet with an image I use:
TweetUri = Uri.fromFile(saveIT);
TweetComposer.Builder builder = new TweetComposer.Builder(this)
.text("")
.image(TweetUri);
builder.show();
The original image is a bitmap, so what I did (not sure if this is the optimal way) was save in the internal storage:
private File saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date());
String mImageName="MI_"+ timeStamp +".jpg";
File mypath=new File(directory,mImageName);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try
{
fos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
return mypath;
}
The file it returns will be the "saveIT" in the TweetUri when it does the fromfile method. Of course this will overload the storage so what I plan to do is wipe the internal storage for the app when it is stopped (no other data is saved in the internal storage other than the temp images I save for the tweet):
#Override
protected void onStop() {
super.onStop();
File MSD = this.getApplicationContext().getFilesDir();
File [] lisFiles = MSD.listFiles();
for(int i=0;i<lisFiles.length;i++)
{
boolean deleted = lisFiles[i].delete();
}
}
None of this works... I can't seem to find any of the images when I save them to verify if the deleting is happening. Also, when the user clicks tweet no image is added to the tweet as well. No idea what I'm doing wrong here... In reality I don't want to save the image in the internal storage but I do because the tweet api uses a URI to tweet and not a bitmap.
I switched it to write to external storage and it worked fine. Also I switched it to delete at onDestroy. This is better because, when I invoke the Twitter API it switches activities so the onstop is invoked which would delete the temp picture too early. It's too early becuase if the user clicks cancel at the twitter api, comes back to my api and then invokes the twitter api again the uri will point to nothing since the picture was already deleted. THATS ALL FOLKS :)
Im new to android development and trying to get metadata of image using ExifInterface. I stored the image under drawable and trying to get the metadata but getting null values for all fields(date, imagelength, imagewidth). I tried to access image path as this :
String path = "drawable://" + R.drawable.testimage;
and provided this path to ExifInterface.
ExifInterface exif = new ExifInterface(path);
I dont know if storing image under drawable is correct or not because when I run the app in emulator I get something like this :
E/JHEAD﹕ can't open 'drawable://2130837561'
So if this is wrong then please tell me where should I store the image and how to provide image path to ExifInterface.
Thank you in advance.
To get a drawable, you can you this snippet:
Drawable drawable = getResources().getDrawable(android.R.drawable.your_drawable);
I'm not sure if your way is correct, as I've never seen it like that. Do you really need the path to your image to use it on that ExifInterface class?
Ok, I did some digging and found this question, which led me to this one. As it seems, you can not get an absolute path from a resource inside your apk. A good solution would be for you to save it as a file on the external memory, and then you can get the path you want.
First of all, add this to your AndroidManifest.xml, so your app can write to the cellphone memory:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Ok, to save it you can try this, first create a bitmap from your drawable resource:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.your_drawable);
After that get the path you want to save your images, and put it on a String. More info on that here.
The Android docs have a good example on how to get the path. You can see it here.
To keep it simple, I'll copy and paste the snippet from the docs.
void createExternalStoragePrivateFile() {
// Create a path where we will place our private file on external
// storage.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
try {
// Very simple code to copy a picture from the application's
// resource into the external file. Note that this code does
// no error checking, and assumes the picture is small (does not
// try to copy it in chunks). Note that if external storage is
// not currently mounted this will silently fail.
InputStream is = getResources().openRawResource(R.drawable.balloons);
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
} catch (IOException e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing " + file, e);
}
}
void deleteExternalStoragePrivateFile() {
// Get path for the file on external storage. If external
// storage is not currently mounted this will fail.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
if (file != null) {
file.delete();
}
}
boolean hasExternalStoragePrivateFile() {
// Get path for the file on external storage. If external
// storage is not currently mounted this will fail.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
if (file != null) {
return file.exists();
}
return false;
}
After that, get the path of the file you saved on the external memory, and do as you wish.
I'll keep the old example as well. You can use the method getExternalStorageDirectory() to get the path, or getExternalCacheDir(). After that, you can use File method called getAbsolutePath() to get your String.
String path = (...) // (you can choose where to save here.)
File file = new File(path, "your_drawable.png");
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // You can change the quality from 0 to 100 here, and the format of the file. It can be PNG, JPEG or WEBP.
out.flush();
out.close();
For more info on the Bitmap class, check the docs.
If you need more info, let me know and I'll try to show more samples.
EDIT: I saw your link, and there was this snippet there:
//change with the filename & location of your photo file
String filename = "/sdcard/DSC_3509.JPG";
try {
ExifInterface exif = new ExifInterface(filename);
ShowExif(exif);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Toast.makeText(this, "Error!",
Toast.LENGTH_LONG).show();
}
As you can see, if you really want to see the exif data of a internal image resource, you'll have to save it somewhere else, and then you can try to get the absolute path for that File, then, call the method to show the exif.
While writing file in External SD card I am getting an error EACCESS permission denied. I have set the permission
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
But the when I read the file I am successfully able to read it but not able to write the file. The code that I am using for writing the file in SD card is:
String path="mnt/extsd/Test";
try{
File myFile = new File(path, "Hello.txt"); //device.txt
myFile.createNewFile();
FileOutputStream fOut = new FileOutputStream(myFile);
OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
myOutWriter.append(txtData.getText());
myOutWriter.close();
fOut.close();
Toast.makeText(getBaseContext(),"Done writing SD "+myFile.getPath(),Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.getMessage(),Toast.LENGTH_SHORT).show();
System.out.println("Hello"+e.getMessage());
}
}
The path for the external storage card is mnt/extsd/. Thats why I am not able to use Environment.getExternalStorageDirectory().getAbsolutePath() which is giving me a path mnt/sdcard and this path is for internal storage path in my tablet. Please suggest why this is so n how can I resolve this
As I remember Android got a partial multi-storage support since Honeycomb, and the primary storage (the one you get from Environment.getExternalStorageDirectory, usually part of the internal eMMC card) is still protected by the permission WRITE_EXTERNAL_STORAGE, but the secondary storages (like the real removable SD card) are protected by a new permission android.permission.WRITE_MEDIA_STORAGE, and the protection level is signatureOrSystem, see also the discussion in this article.
If this is the case then it seems impossible for an normal app to write anything to the real sdcard without a platform signature...
From API level 19, Google has added API.
Context.getExternalFilesDirs()
Context.getExternalCacheDirs()
Context.getObbDirs()
Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.
Following is approach to get application specific directory on external SD card with absolute paths.
Context _context = this.getApplicationContext();
File fileList2[] = _context.getExternalFilesDirs(Environment.DIRECTORY_DOWNLOADS);
if(fileList2.length == 1) {
Log.d(TAG, "external device is not mounted.");
return;
} else {
Log.d(TAG, "external device is mounted.");
File extFile = fileList2[1];
String absPath = extFile.getAbsolutePath();
Log.d(TAG, "external device download : "+absPath);
appPath = absPath.split("Download")[0];
Log.d(TAG, "external device app path: "+appPath);
File file = new File(appPath, "DemoFile.png");
try {
// Very simple code to copy a picture from the application's
// resource into the external file. Note that this code does
// no error checking, and assumes the picture is small (does not
// try to copy it in chunks). Note that if external storage is
// not currently mounted this will silently fail.
InputStream is = getResources().openRawResource(R.drawable.ic_launcher);
Log.d(TAG, "file bytes : "+is.available());
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
} catch (IOException e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.d("ExternalStorage", "Error writing " + file, e);
}
}
Log output from above looks like:
context.getExternalFilesDirs() : /storage/extSdCard/Android/data/com.example.remote.services/files/Download
external device is mounted.
external device download : /storage/extSdCard/Android/data/com.example.remote.services/files/Download
external device app path: /storage/extSdCard/Android/data/com.example.remote.services/files/
I solved this problem by removing the android:maxSdkVersion="18" in uses-permission
in manifest file.
I.e. use this:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
instead of:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
Check if user is having external storage permission or not. If not then use cache dir for saving the file.
final boolean extStoragePermission = ContextCompat.checkSelfPermission(
context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED;
if (extStoragePermission &&
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) {
parentFile = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
}
else{
parentFile = new File(context.getCacheDir(), Environment.DIRECTORY_PICTURES);
}