I have an android 4.3 device and often connect it to my PC via USB so that I can view files created by one of my apps. Strangely though, it seems that not all files on the android file system are visible. After much searching I came across this page which (correct me if I'm wrong) suggests that if I call MediaScannerConnection.scanFile, with the path I'm interested in, then it would make all files in those directories visible. I have implemented the code as follows:
void make_files_in_directory_visible_on_pc(String directory)
{
Log.i("xx","make_files_in_directory_visible_on_pc: dir=["+directory+"]");
MediaScannerConnection.scanFile(
getApplicationContext(),
new String[]{ directory }, // array of paths
null, // mime types
new OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri)
{
Log.i("xx","file " + path + " was scanned successfully: " + uri);
}
});
}
My app saves its files in Environment.getExternalStorageDirectory().getAbsolutePath() which, on my device, is "/storage/emulated/0".
When I execute this from my app I see the following in the logs:
file /storage/emulated/0 was scanned successfully: content://media/external/file/2552
After the code has run there is no change to the list of files visible from my PC, many files are still missing.
Any ideas?
EDIT: FYI, I do not have a file called "2552" on that directory, or anywhere else on my device.
EDIT: If I execute the following:
MediaScannerConnection.scanFile(this, new String[] {Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+name_of_individual_file}, null, null);
Then that single file does indeed become visible, but I want to achieve this for all files in the directory.
I've worked it out...
void make_files_in_directory_visible_on_pc(String path)
{
File f = new File(path);
File file[] = f.listFiles();
for (int i=0; i < file.length; i++)
{
MediaScannerConnection.scanFile(this, new String[] {file[i].getAbsolutePath()}, null, null);
}
}
Related
In my android-app I have created a folder on the internal storage of my device.
When I browse the internal storage I can see the folder and its content.
When I connect the device to my pc and open the internal storage, the folder is missing. All other folders are available, but not the folder I created from my app.
I tried to turn on "show invisible files" for my windows, but the folder is still missing. Any suggestions?
I tried to use MediaScannerConnection.scanFile from Vijai's answere. After this, i can see the file, but is not displayed as a directorie. Nothing happens with double click on it.
The folder itself is beeing created by my databasemanager. Its an extensionclass of the SQLiteOpenHelper-class.
private DatabaseManager(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); //DATABASE_NAME = Environment.getExternalStorageDirectory() + File.separator + "[Name of my directorie]" + File.separator + "[Name of my db].DB";
mContext = context;
getWritableDatabase();
}
This was working fine for so long. I was able to see the directory in the past. Since my customer changed his phone to android 6.0.1, the file is no more visible.
To scan all the files in a folder, you can build a String array containing the file paths and pass it to the mediascanner's scanFile() method.
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) {
File dir = new File(Environment.getExternalStorageDirectory(), "yourdirectory");
// Create empty directory and its missing parent directories
dir.mkdirs();
if (dir.exists())
MediaScannerConnection.scanFile(this, buildFilePaths(dir), null, null);
}
private String[] buildFilePaths(File directory){
File[] files = directory.listFiles();
ArrayList<String> filePaths = new ArrayList();
for (File file : files)
filePaths.add(file.getAbsolutePath());
return filePaths.toArray(new String[filePaths.size()]);
}
-----Original answer-----
You have to rescan the storage to show the directory (android does a whole system media scan at intervals or during boot)
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) {
File dir = new File(Environment.getExternalStorageDirectory(), "yourdirectory");
// Create empty directory and its missing parent directories
dir.mkdirs();
if (dir.exists())
MediaScannerConnection.scanFile(this, new String[] {dir.toString()}, null, null);
}
p.s: MTP mode sucks!
My android-application writes a bunch of csv-files and jpg-files to the internal storage of the device. I am using MediaScannerConnection.scanFile() to make the files accessable from my windows-system without rebooting the android-device.
private void scanFiles() {
File targetDirectory = new File(Environment.getExternalStorageDirectory(), "DIR_OF_MY_APP");
if (targetDirectory.exists()) {
List<File> filesToScan = getFiles(targetDirectory);
List<String> filePathsToScan = new ArrayList<>();
for(File file : filesToScan) {
filePathsToScan.add(file.getPath());
}
MediaScannerConnection.scanFile(this, filePathsToScan.toArray(new String[0]), null, new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
Log.d("OK", "Path: " + path);
Log.d("OK", "Uri : " + uri);
}
});
}
}
In my Logcat i can see every file is getting scanned. The new ones and the old ones.
My problem is when my app is adding new lines to an existing csv-file and the file is getting scanned, The new lines do not appear in the csv-file when its opend from my pc. How can i fix this problem?
I already tried to rename all the files from filename to tmp_filename, rescann all the files and rename them back from tmp_filename to filename and rescann them again. After this, i have can see the oldfilename-file and the tmp_oldfilename-file on my windows-computer. The tmp_oldfilename-file can not be opend (Unknown error on [memory-adress]). The oldfilename-file shows the not updated csv-file.
I also tried to use a intent to scan the files, since some questions on so say its going to update them:
for(File file : filesToScan) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
Log.d("OK", "File: " + file.getName() + " scanned...");
}
here i can see the files getting scanned too, but they do not show up updated on my windows-computer.
Okay the only solution i came up with, is to set the usb-mode to load-only (this must be done by hand from the user) before performing the MediaScannerConnection.scanFile();. After this is done, the user can set the usb-mode back to mtp and than the csv-files will show up with the new added lines.
This is a really bad workarround, but still better than rebooting the device. If someone has an better solution, pls share.
I have a directory structure of files in external storage. They don't show up in the Android File Transfer app, so I think it's a media scanner problem.
I'm creating them with a FileOutputStream in a directory based on Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).
I have the following method, called from an activity, so context is an activity (forget that this blocks the main thread for now!):
public void scan(Context context, File base) {
File[] files = base.listFiles();
if (files == null) {
return;
} else {
for (File file : files) {
if (file.isFile()) {
String path = file.getAbsolutePath();
MediaScannerConnection.scanFile(context, new String[]{path}, null, null);
Log.e("Langstroth", path);
} else if (file.isDirectory()) {
this.scan(context, file);
}
}
}
}
public void scan(Context context) {
this.scan(context, this.baseDir);
}
}
The output of the log is as expected:
E/MyApp﹕ /storage/emulated/0/Documents/Langstroth/sample/5000/1430576404874.wav
E/MyApp﹕ /storage/emulated/0/Documents/Langstroth/sample/5000/1430577209491.wav
And then lots of:
E/MyApp﹕ Scan completed path /storage/emulated/0/Documents/Langstroth/sample/5000/1430576404874.wav uri content://media/external/audio/media/7836
E/MyApp﹕ Scan completed path /storage/emulated/0/Documents/Langstroth/sample/5000/1430577209491.wav uri content://media/external/audio/media/7838
This proves that the files exist. They don't show up in the Android File Transfer though.
Here's the strange thing. Another method:
public void otherDemo(Context context, File baseDir) {
String newPath = baseDir.getAbsolutePath() + "/some/random/dirs";
Log.e("Langstroth", "New path " + newPath);
File dir = new File(newPath);
dir.mkdirs();
Log.e("Langstroth", dir.exists() ? "Dir exists": "Dir does not exist");
File f = new File(dir, "myfile.txt");
try {
new BufferedOutputStream(new FileOutputStream(f)).close();
} catch (IOException e) {
e.printStackTrace();
}
Log.e("Langstroth", f.exists() ? "File exists": "File does not exist");
MediaScannerConnection.scanFile(context, new String[]{f.getAbsolutePath()}, null, null);
}
and the log output:
E/MyApp﹕ New path /storage/emulated/0/Documents/Langstroth/some/random/other/dirs
E/MyApp﹕ Dir exists
E/MyApp﹕ File exists
E/MyApp﹕ File: /storage/emulated/0/Documents/Langstroth/some/random/other/dirs/myfile.txt
E/MyApp﹕ Other scan completed path /storage/emulated/0/Documents/Langstroth/some/random/other/dirs/myfile.txt uri content://media/external/file/7842
One test file shows up, the others don't
Proof:
Where are the other files?
Generally speaking, before you let another process work with a file, you want to ensure all bytes are flushed to disk, via getFD().sync(). In particular, this seems to help with the whole media scanning thing.
the files shows up in a .listFiles(), and .exist(), and the callback for the MediaScanner says that it completed correctly. Surely an extant (if empty) file should show up?
The ways of the media scanner are mysterious. :-) IOW, beats me.
Bear in mind that there are multiple moving parts here: your app, the media scanner, the MTP daemon on Android, and your MTP client. The breakdown could be at any stage. If you unplug and re-plug in the device, and now the files show up in your MTP client, my guess would be that the MTP client is working off of a slightly stale cache.
I have a small app that when I run it make a folder in my SD then save some Videos inside the folder
The thing is the app does the work and make the folder and save the files and I still can see it in SD using file manager or from my PC when I connect it via USB
But for e.g when I start Whatsup or my Gallery I can't see the folder or the videos !
I still can see the folder and videos that stored in the SD using File Manager
so what's wrong ? why I can't see the folder and videos in the Gallery or other programs when I want to attach the video ..
I used the same code link for my App to create the folder and check :
File folder = new File(Environment.getExternalStorageDirectory() + "/TollCulator");
boolean success = true;
if (!folder.exists()) {
success = folder.mkdir();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
The Gallery works off of MediaStore, and WhatsApp may as well. Use MediaScannerConnection and its scanFile() static method to arrange to have your file(s) be indexed and available through the MediaStore, and see if that helps.
You need to Tell the media scanner about the new file so that it is immediately available to the user.
For example
MediaScannerConnection.scanFile(this,
new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
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
e.g /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!!! ;-)