I'm trying to copy a file that is located in the External storage directory into a directory that is in my SD Card. However, when I check to see if the file has successfully been copied, the file is not even created in the SD Card.
Am I missing something? Here is the code I have:
String sourcePath = Environment.getExternalStorageDirectory().getPath() + newFileName;
File source = new File(Environment.getExternalStorageDirectory().getPath(), newFileName);
String destinationPath = "/storage/external_SD";
File destination = new File(destinationPath, newFileName);
try {
if(!destination.exists()){
destination.mkdir();
}
FileUtils.copyFile(source, destination);
} catch (IOException e) {
e.printStackTrace();
}
The copyFile method is from an Apache library. Here is the link for it: https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/FileUtils.html
However, when I check to see if the file has successfully been copied, the file is not even created in the sd Card.
You do not have arbitrary filesystem-level access to removable storage on Android 4.4+.
Is there a work around for this?
That depends on what your objective is.
If you insist that you must be able to write to that specific path on arbitrary user devices... then, no, there is no supported workaround. After all, there is no /storage/external_SD on the vast majority of Android devices. Where and how device manufacturers choose to mount removable media is up to them and is an implementation detail that will vary.
If you relax that restriction, but insist that you must be able to write a file to the root directory of removable storage on arbitrary user devices... then, no, there is no supported workaround today. The N Developer Preview has a "Scoped Directory Access" feature that should allow this, but it will be several years before you can assume that an arbitrary user device will be running that version of Android or higher. Also, you do not get actual filesystem access, but rather a Uri (see the Storage Access Framework option, below).
Now, if you are more flexible about the precise location, you have other options:
You can use getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs(), all methods on Context. Note the plural form. If those return 2+ entries, the second and subsequent ones are locations on removable storage that you can read from and write to, no permissions required. However, you do not get to choose the exact path. And if the device has 2+ removable storage volumes, I'm not quite certain how you would help the user tell them apart.
You can use the Storage Access Framework and let the user choose where to put the file. The user is welcome to choose removable storage... or not. You get a Uri back, which you can use with ContentResolver and openOutputStream() to write your content. You can also take persistable Uri permissions so you can work with that file again in the future, assuming the user doesn't move or delete it behind your back.
If you want to copy to external storage then you need
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The destinationPath you mentioned may not be accessible as it may belong to the private system folders or some other application folders. You can however use public folders like Pictures,Music, Videos,Downloads,etc. or create sub folders inside them -
String sourcePath = Environment.getExternalStorageDirectory().getPath() + newFileName;
File source = new File(Environment.getExternalStorageDirectory().getPath(), newFileName);
File destinationPath = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS, "/external_SD");
try {
if(!destinationPath.exists()){
destinationPath.mkdir();
}
File destination = new File(destinationPath, newFileName);
FileUtils.copyFile(source, destination);
} catch (IOException e) {
e.printStackTrace();
}
Related
I’m trying to copy media contents created by my App (under DCIM folder in internal storage (/storage/emulated/0/DCIM/MyApp) to a folder inside my SD card.
So I’d like to check if DCIM folder exist inside sd card, if not create the folder and copy the directory and all its contents to SD card. Since this would be a long operation I was thinking of doing it inside an asynctask.
For the life of me, I can’t seem to be able to do anything on SD card. I see that for whatever reason google decided to change SD access framework with every major iteration. So I started looking into StorageManager since that seems to be the most up to date way.
However, it seems that I’d need to manage it inside an activity and potentially I’d like to do this inside an AsyncTask, would there be a way of doing this inside AsyncTask?
I’m bit confused about how to use StorageManager in this manner, and to be honest I don’t even know it can be done so I was wondering if you have any idea of how to go around doing this?
I’d really appreciate a sample code snippet for copying a folder from Internal storage to SD card.
Thanks!
EDIT: below is a snippet of code how I was trying to copy the folders from internal storage to the apps own storage inside the sdcard:
#Override
protected Void doInBackground(String... args) {
String[] storageDirs = getExternalStorageDirectories();
Log.d(TAG, Arrays.toString(storageDirs));
File[] externalDirs = m_context.getExternalFilesDirs(null);
Log.d(TAG, Arrays.toString(externalDirs));
File internalDir = new File("/storage/emulated/0/DCIM/myApp/"); // /storage/emulated/0/DCIM/myApp/
File sdcardDir = new File(m_context.getExternalFilesDirs(null)[1] + "/TEST/");
Long totalSize = dirSize(internalDir);
Log.d(TAG, "Source Directory Size: " + totalSize);
try {
FileUtils.copyDirectory(internalDir, sdcardDir);
} catch (Exception e) {
Log.e(TAG, "Error while copying directories! Aborting file transfer!");
e.printStackTrace();
}
return null;
}
Before It gets brought up about my question already being asked, I would like to state that I have tried around 5 other options and possible solutions with no result.
Here is a snippet of my code. This is just a snippet. Upon testing the results of my code currently, a file is being saved in the main directory, /ScoutingApp. However, I would like to files to save in a folder /ScoutingApp/ on the MicroSD card so I can eject data more quickly.
if (Environment.MEDIA_MOUNTED.equals(state)) {
File root = Environment.getExternalStorageDirectory();
File Dir = new File(root.getAbsolutePath() + "/ScoutingApp");
if (!Dir.exists()) {
Dir.mkdir();
} else {
filename = UUID.randomUUID().toString() + ".sql";
File file = new File(Dir, filename);
If the Android that your Fire OS is based on is Android 4.4+, you can try getExternalFilesDirs() on any Context (such as an Activity). Note the plural form — if this method returns 2+ items, the second and subsequent ones are on removable storage. Those locations will be specific for your app, and you can read from and write to those locations without permissions.
Note, though, that Fire OS is not completely compliant with the Play ecosystem's compatibility requirements, and so YMMV.
I want to store a list of strings in a file.
I need to create it just one time, and after that i will read and write on it programmaticlly.
My question is where in the file system should i create the file (manually) so that it will best for reading and writing ?
Thanks.
You can create your file in your app's directory so no one can access it but your app
getApplicationContext().getFilesDir().getAbsolutePath();
or on sd card
File externalStorage = Environment.getExternalStorageDirectory();
if you want others to access it and, maybe, if your file is very big
If you intent to create your file manually then I think SD card is the only option unless you have a rooted phone or working with the emulator.
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
//SDcard is there
File f=new File("/sdcard/YOURFILE.txt");
if (!f.exists())
{
//File created only for first time
f.createNewFile();
//create inputstream and write it to your file
OutputStream out=new FileOutputStream(f);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0)
out.write(buf,0,len);
out.close();
inputStream.close();
System.out.println("\nData Written");
}
else { // read/ write SECOND TIME }
}
It really depends.
The problem with creating the file on the SDCard is that a special permission is required in order to access it. If the app is only for yourself, that's cool. If you want to distribute it through Google MarketPlay (or whatever it is called these days), please know that some people (myself included) tend to look at the permissions and ask "why would an app doing X require permission to do Y?", and sometimes not install the app because of it.
If the manual part is done by the app's user, by all means, store it on the sdcard. It's the only place a standard, none-root user even has access to.
Generally speaking, however, a better place to store data is in /data/data/packagename. See Android's data storage for more details.
Shachar
Add file in assets folder, then it will be clearly after new install
I have just written a function in an android app that deletes a file using the standard 'File' class in Java. i.e:
String fileName= "/mnt/Gallery/Img001.jpg";
File file = new File(fileName);
file.delete();
While the above procedure is simple enough, I have been wondering if there is any advantage to doing the same via a 'ContentResolver'. Any advice would be appreciated.
------------------------------------------ EDIT ----------------------------------------
Here's an example of deleting a file via the Content Resolver. This example assumes the file being deleted is an image and that its 'id' is known.
long mediaId = 155; // NOTE: You would normally obtain this from the content provider!
Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Uri itemUri = ContentUris.withAppendedId(contentUri, mediaId);
int rows = getContentResolver().delete(itemUri, null, null);
String path = itemUri.getEncodedPath();
if(rows == 0)
{
Log.e("Example Code:","Could not delete "+path+" :(");
}
else
{
Log.d("Example Code:","Deleted "+path+ " ^_^");
}
Android's content provider framework has certain added advantages when compared to directly manipulating data.
You can think on the lines of 'Where does the file reside and who may be deleting it'.
Scenario 1
File resides on SD card (a path accessible by your app) and you app is deleting it.
Solution : Since the path is accessible to you, the java approach will work with a file Uri like:
file://mnt/sdcard/downloads/image.jpeg
Scenario 2
File resides in another app (say dropbox) and your app needs to delete the file.
Solution : This means that the file actually resides in the private storage of another app. A file: Uri will the above approach will give you access denied. So, your app will need to fetch a content Uri from the app containing the file and call into its content provider to delete.
fileUri = Uri.parse ("content : // " + packageContainingTheFile " + fileId); // replace this with Uri obtained from the app.
getContext().getContentResolver().delete (fileUri, null, null);
Scenario 3
File resides in your app's package directory i.e, under data/data/com.yourpackage/yourfolder/yourfile.xxx and your app is the only one deleting it.
Solution : Here, either of the above approaches will work since you have the access to delete the file.
Uri will look like:
file://data/data/yourpackage/folder/file.ext
The prime advantage of using content provider here is that you automatically gain the observer model. Content provider callbacks are a well defined entry point from where data is modified. Hence, its a desired place to notify others of changes using:
getContext().getContentResolver().notify(uri, null)
Assume you have views that show a listing of such file items. As soon as the delete is done, your can be notified.
Scenario 4
File resides in your app's package directory i.e, under data/data/com.yourpackage/yourfolder/yourfile.xxx and you want to expose the delete functionality to other apps.
Solution : This is similar to Scenario 1, just the other way round. Other apps cannot delete the file in your private storage with a Uri like
file://data/data/yourpackage/folder/file.ext // works just for your app
They will need to call in your content provider to do this with a Uri like.
content://providerAuthority/delete/id
which your content provider will need to map to file.ext absolute path.
Summary
To conclude, the use of content provider is necessary is some scenarios while optional in others. It largely depends on your app requirements. If you have views, CursorLoaders in place and want to be informed about updates or wish to expose deletion of your app data to other apps, content provider is the cleanest approach.
I am trying to read a pdf file from internal memory of the device my code is here:
File pdfFile;
pdfFile=new File("data/data/com.myapp.main/app_c"+md+"/c"+md+".pdf");
if(pdfFile.exists())
{
try{
FileOutputStream fileOutput = openFileOutput(pdfFile.toString(), Context.MODE_WORLD_READABLE);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
Uri path = Uri.fromFile(pdfFile);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
{
startActivity(pdfIntent);
}
catch(ActivityNotFoundException e)
{
Toast.makeText(ChTable.this, "No Application available to view pdf", Toast.LENGTH_LONG).show();
}
But the Pdf reader shows an Error -File not supported-Or File Not found .But I have checked that file is there at this location.I have also changed the permission to the file ,but still the same result. Would Someone help me detect and solve my problem ?
you can use PDFBox library to read data from pdf -
http://pdfbox.apache.org/
data/data/com.myapp.main/app_c"+md+"/c"+md+".pdf"
Is this path correct?
I am guessing the path should be like below.
data/data/com/myapp/main/app_c"+md+"/c"+md+".pdf"
You should be using one of the apis to get the application's files directory rather than assuming what the path will be.
Your actual problem however is most likely that any file you create there is probably private to the owning application, so the PDF reader app lacks permission to access it.
Solutions to that would be to change the file mode to world readable, or more commonly to put the file on the external storage (ie, "sdcard") rather than the internal memory, as that does not (to date) have a concept of permissions. Though it's worth remembering that a device isn't guaranteed to have an external storage, or for it to be accessible at any given point in time even if it exists.