I am working on an app that list all the audio files from shared internal storage and removable SD card.
Now if the user wants to delete a particular file , it will be deleted from shared internal storage or removable SD card.
The issue I am facing is file.delete does not work , I have used mediastore to get all audio files.
These were the audio file paths i got from media store.
This is from internal shared storage.
/storage/emulated/0/Music/Guitar1.mp3
This is from removable micro SD card.
/storage/BBF8-A8D3/Guitar1.mp3
After getting these paths
File deleteFile = new File(s.getFilepath());
boolean delete = deleteFile.delete();
The delete gives false as delete file is not deleted.
Now I have tried this,
File deleteFile = new File(s.getFilepath());
if(deleteFile.exists()) {
boolean catchdelete = deleteFile.delete();}
Now after creating file from path , if condition fails as delete File does not exist.
So why newly created file does not exist(file is not a directory) does it require file input stream.
My main issue is to delete a file from storage through the app.
This is my method for retreiving audio file paths
public ArrayList<String> getAudiosPath(Activity activity, Context context) {
// Uri uri;
listOfAllAudios = new ArrayList<String>();
Cursor cursor;
final String[] columns = {MediaStore.Audio.Media.DATA, MediaStore.Audio.Media._ID};
final String orderBy = MediaStore.Audio.Media._ID;
//Stores all the audio from the gallery in Cursor
cursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, columns, null,
null, orderBy);
//Total number of audios
int count = cursor.getCount();
//Create an array to store path to all the audios
String[] arrPath = new String[count];
for (int i = 0; i < count; i++) {
cursor.moveToPosition(i);
int dataColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
//Store the path of the audio
arrPath[i] = cursor.getString(dataColumnIndex);
Bitmap b = ((BitmapDrawable) ResourcesCompat.getDrawable(context.getResources(), R.drawable.headphone512, null)).getBitmap();
bitmap.add(b);
Log.i("PATH", arrPath[i]);
listOfAllAudios.add(arrPath[i]);
}
// count_paths=listOfAllAudios.size();
return listOfAllAudios;
}
Now i have applied Apache Commons IO File Utils
File deleteFile = new File(s.getFilepath());
// boolean delete = deleteFile.delete();
try {
FileUtils.forceDelete(FileUtils.getFile(s.getFilepath()));
}
catch (IOException e) {
e.printStackTrace();
}
This Apache Commons file utils does delete the file but issue is when opening the app again i am seeing the file path with file size 0 KB.
In Download Nav drawer
when in Nav drawer i access TA-1032-> Music -> Empty(No File present)
(there is no file which means file gets deleted)
But in Nav drawer i access Audio-> Unknown -> Music -> Guitar.mp3 (file present but file size is 0 and cant be played)
so this is some how getting the path of file.
Try using Apache Commons as a dependency and use their file API for the operation.
FileUtils.forceDelete(FileUtils.getFile(s.getFilepath()));
This piece might work.
Files.deleteIfExists(Paths.get("C:\\Users\\Mayank\\Desktop\\
445.mp3"));
Code snip will be helpful
File directory = new File("c:\\directoryname\\filename.txt");-- give your path where file is located.
try {
FileUtils.forceDelete(directory);
System.out.println("force delete file in java");
}
catch (IOException e) {
e.printStackTrace();
}
This worked for me , the code posted by #dammina deleted the file but still was accessible from media store so the other method will take care of it.
File deleteFile = new File(s.getFilepaths());
try {
FileUtils.forceDelete(FileUtils.getFile(s.getFilepaths()));
// adapterRecycler.notifyDataChanged();
adapterRecycler.notifyDataChanged(sectionHeaders);
}
catch (IOException e) {
e.printStackTrace();
}
deleteFileFromMediaStore(getContentResolver(), deleteFile);
method for deleting from media store because even after deleting file it is still accessible through media store.
public static int deleteFileFromMediaStore(final ContentResolver contentResolver, final File file) {
String canonicalPath;
try {
canonicalPath = file.getCanonicalPath();
} catch (IOException e) {
canonicalPath = file.getAbsolutePath();
}
// MediaStore.Files.FileColumns.DATA
final Uri uri = MediaStore.Files.getContentUri("external");
final int result = contentResolver.delete(uri,
MediaStore.Audio.Media.DATA + "=?", new String[]{canonicalPath});
if (result == 0) {
final String absolutePath = file.getAbsolutePath();
if (!absolutePath.equals(canonicalPath)) {
int deletedRow = contentResolver.delete(uri,
MediaStore.Audio.Media.DATA + "=?", new String[]{absolutePath});
return deletedRow;
}
} else return result;
return result;
}
Related
My requirement is to show directory under Gallery/ Albums,
creating a directory in the following way does not full fill my requirement...
File rootPath = new File(Environment.getExternalStorageDirectory(), "directoryName");
if(!rootPath.exists()) {
rootPath.mkdirs();
}
final File localFile = new File(rootPath,fileName);
by using this code i can see the folder by using "file mangaer" with the path...
"deviceStorage/directoryName" but the folder is not visible under Gallery or Albums
for directory creation i tried the following ways too...
1)File directory = new File(this.getFilesDir()+File.separator+"directoryName");
2)File directory = new File (Environment.getExternalFilesDir(null) + "/directoryName/");
3)File directory = new File(Environment.
getExternalStoragePublicDirectory(
(Environment.DIRECTORY_PICTURES).toString() + "/directoryName");
but no luck, please help me friends
thanks in advance.
check this solution as well:
String path = Environment.getExternalStorageDirectory().toString();
File dir = new File(path, "/appname/media/app images/");
if (!dir.isDirectory()) {
dir.mkdirs();
}
File file = new File(dir, filename + ".jpg");
String imagePath = file.getAbsolutePath();
//scan the image so show up in album
MediaScannerConnection.scanFile(this,
new String[] { imagePath }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
if(Config.LOG_DEBUG_ENABLED) {
Log.d(Config.LOGTAG, "scanned : " + path);
}
}
});
Try this one.
File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + "albums");
boolean rootCreated = false;
if (!root.exists())
rootCreated = root.mkdir();
You can use MediaStore API to save your media files like that:
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "filename")
put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_DCIM}/$directoryName")
put(MediaStore.Images.Media.MIME_TYPE, mimeType)
}
val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val item = context.contentResolver.insert(collection, values) ?: throw IOException("Insert failed")
resolver.openFileDescriptor(item, "w", null)?.use {
writeImage(it.fileDescriptor)
}
This will save the media files to the media collections and make it available to the gallery. Gallery app normally shows your directoryName as an album.
Checked on Samsungs S10 and above with Android 10.
heres the java.nio library way to create directory
Java Code
File targetFile = new File(Environment.getExternalStorageDirectory(), "subDir");
Path sourceFile = Paths.get(targetFile.getAbsolutePath());
Files.createDirectory(sourceFile);
some android phone create .nomedia file inside the created app folder to prevent media from being shown in gallery app so you may check if this hidden file exists and delete it if it exists. set folder and files readable. you may wait quite time before system reflect your created file in your gallery app.
val parentFile = File(Environment.getExternalStorageDirectory(), "MyAppFolder")
if(!parentFile.exists())
parentFile.mkdir()
parentFile.setReadable(true)
// .nomedia file prevents media from being shown in gallery app
var nomedia = File(parentFile, ".nomedia")
if(nomedia.exists()){
nomedia.delete()
}
val file = File(parentFile , "myvideo.mp4")
file.setReadable(true)
input.use { input ->
var output: FileOutputStream? = null
try {
output = FileOutputStream(file)
val buffer = ByteArray(4 * 1024)
var read: Int = input.read(buffer)
while (read != -1) {
output.write(buffer)
read = input.read(buffer)
}
output.flush()
// file written to memory
} catch (ex: Exception) {
ex.printStackTrace()
} finally {
output?.close()
}
}
I recently upgraded the app's target version to API 29. Due to the scoped storage in Android 10, i used MediaStore API to store and retrieve images from app external storage. Earlier, i used getExternalStoragePublicDirectory to store images taken through camera, now i use MediaStore.Images.Media.EXTERNAL_CONTENT_URI to write file to an external storage location.
Issue i am facing now is,
When i open my app and take pictures, it stores under a folder name that i gave 'myapp' and i can retrieve my images through Mediastore cursor and show them in a custom gallery. And when i uninstall my app 'myapp' folder still exists. And when i install my app again and try to read the images from the gallery, cursor is not returning any image. But if i take picture again, then i could load them to my custom gallery. Custom gallery view is just a row of images at the bottom of the screen, so that user doesn't have to browse through the photos folder to load the image to the app.
This is how i store my images in the MediaStore
Content values:
String RELATIVE_PATH = Environment.DIRECTORY_PICTURES + File.separator + "myApp";
final ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, generateImageName(new Date()));
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, RELATIVE_PATH);
Generate Name method:
int sameSecondCount;
protected String generateName(Date now)
{
String result = formatter.format(now);
long nowMillis = now.getTime();
if (nowMillis / 1000 == lastMillis / 1000)
{
sameSecondCount++;
result += "_" + sameSecondCount;
}
else
sameSecondCount = 0;
lastMillis = nowMillis;
return result + PICTURE_EXTENSION_JPG;
}
#WorkerThread
private Uri writePictureToFile(ContentValues contentValues, byte[] bitmapBytes) throws IOException
{
final ContentResolver resolver = getApplication().getContentResolver();
Uri uri = null;
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
try
{
uri = resolver.insert(contentUri, contentValues);
if (uri == null)
throw new IOException("Failed to create new MediaStore record.");
OutputStream stream = resolver.openOutputStream(uri);
if (stream == null)
{
throw new IOException("Failed to get output stream.");
}
stream.write(bitmapBytes);
}
catch (IOException e)
{
// Delete the content from the media store
if (uri != null)
resolver.delete(uri, null, null);
throw e;
}
return uri;
}
Reading images
{
String selectionMimeType = MediaStore.Files.FileColumns.MIME_TYPE + " in (?,?,?)";
String[] args = new String[]{
MimeTypeMap.getSingleton().getMimeTypeFromExtension("jpg"),
MimeTypeMap.getSingleton().getMimeTypeFromExtension("png")};
Cursor cursor = context.getContentResolver()
.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, selectionMimeType, selectionArgs,
orderBy + " DESC");
if (cursor != null)
{
int idColumnIndex = imageCursor.getColumnIndex(MediaStore.Images.Media._ID);
imageCursor.moveToFirst();
int imageCount = imageCursor.getCount();
for (int i = 0; i < imageCount && i < totalCount; i++)
{
final long imageId = imageCursor.getLong(idColumnIndex);
Uri uriImage = Uri.withAppendedPath(uriExternal, "" + imageId);
GalleryData galleryImageData = new GalleryImageData(imageId, uriImage); // Custom class with id and Uri
galleryViewModelList.add(galleryImageData);
imageCursor.moveToNext();
}
imageCursor.close();
}
Why the images that i stored in the folder in Mediastore is not being returned by the above code when i reinstall my App. Is it by design or am i missing something?
These are the columns i am retrieving,
final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID, MediaStore.Images.Media.MIME_TYPE };
final String orderBy = MediaStore.Images.Media.DATE_TAKEN; ```
For unclear reasons, Android 10 considers two app installations separated by time to be separate apps, no different than if those were two completely different apps.
As a result, once your app is uninstalled, it loses access to all files that it created... even if the same app is later reinstalled.
So, you need to treat files from a previous installation of your app the same way as you would treat files from completely unrelated apps: request READ_EXTERNAL_STORAGE to be able to query for them and read their contents. The "read their contents" part requires android:requestLegacyExternalStorage="true" on the <application> in the manifest.
I'm working on an android application and I want to save a screenshot of the application. I can save a single screenshot but it keeps over writing the previous screenshot.
I followed a tutorial and modified it but it does not take more than a single screenshot
Attached here is the code in the button action
case R.id.btn_save:
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
Bitmap bitmap = getScreenShot(rootView);
int i = 0;
File file = new File("ScreenShot"+ i +".PNG");
if(!file.exists()){
store(bitmap, "ScreenShot"+ i +".PNG");
}
else {
store(bitmap, "ScreenShot"+ i++ +".PNG");
}
and the screenshot storing function
public void store(Bitmap bm, String fileName){
String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Screenshots";
File dir = new File(dirPath);
if (!dir.exists()){
dir.mkdirs();
}
File file = new File(dirPath,fileName);
try{
FileOutputStream fos = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 100,fos);
fos.flush();
fos.close();
}catch (Exception e){
e.printStackTrace();
Toast.makeText(this, "Error saving File", Toast.LENGTH_SHORT).show();
}
}
You are declaring i variable inside the button save so you will always start with 0 when button is clicked. To use the way you are trying you should declare that variable outside that scope, but it will restart when you kill and reopen the app.
You can use Shared Preferences to save the following number to use (or the last you used) if you want to use that approach. If not you can use simply
"Screenshot" + System.currentTimeInMillis().toString().
You will also have the time when the screenshot was taken (although in millis). If you want you can format it to be like "user readable" 20191110 for example
Because in that code the file name is always the same- i is always 0. To make it work for one use of the app, i should be a member variable and incremented every screenshot. To make it work more generally, you should generate a random name using File.createTempFile()
case R.id.btn_save:
View rootView getWindow().getDecorView().findViewById(android.R.id.content);
Bitmap bitmap = getScreenShot(rootView);
File dir = new File(Environment.getExternalStorageDirectory(), "Screenshots");
if (!dir.exists())
if ( !dir.mkdirs())
{
Toast ( could not create dir...);
return;
}
int i = 0;
while (++i > 0 )
{
String fileName = "ScreenShot"+ i +".png";
File file = new File(dir, fileName);
if(!file.exists())
{
store(bitmap, file);
break;
}
}
break;
Change the parameter of store(Bitmap bm, String fileName) to store(Bitmap bm, File file)
There you can remove all code before the try block.
I am trying to move files from one directory to another delete that file from source directory after moving.
for (File file : files) {
if (file != null) {
boolean status = moveFile(file, filePath, name, docGroupId);
if (status) {
//some operations....
}
}
}
public static boolean moveFile(final File file, final String filePath, final String groupName, Integer docGroupId) {
// TODO Auto-generated method stub
String selectedDirectory = filePath + File.separator + groupName;
InputStream in = null;
OutputStream out = null;
try {
if (!file.isDirectory()) {
File dir = new File(selectedDirectory);
if (!dir.exists()) {
dir.mkdirs();
}
String newFilString = dir.getAbsolutePath() +
File.separator + file.getName();
File newFile = new File(newFilString);
in = new FileInputStream(file);
out = new FileOutputStream(newFile);
byte[] moveBuff = new byte[1024];
int butesRead;
while ((butesRead = in.read(moveBuff)) > 0) {
out.write(moveBuff, 0, butesRead);
}
}
in.close();
out.close();
if(file.delete())
return true;
} catch (Exception e) {
return false;
}
}
The program works on Linux-Ubuntu and all files are moved to another directory and deleted from source directory, but in Windows system all files are moved but failed to delete one or two files from source directory. Please note that while debugging the program is working fine.
Consider using Files.delete instead of File.delete. The javadoc says:
Note that the Files class defines the delete method to throw an IOException when a file cannot be deleted. This is useful for error reporting and to diagnose why a file cannot be deleted.
This should provide the information necessary to diagnose the problem.
So, if problem comes with delete, possible explanations:
you do file.delete() on every files and directories. How do you know the directory is empty ? If not, it will fail, then what happen to next instructions ?
file deletion is OS-dependant. On Windows, you can have many security issues, depending on which user, which rights, which location. You should check with a file-delete-alone program;
last: files can be locked by other programs (even explorer), it is also OS-dependant.
You don't need any of this if the source and target are in the same file system. Just use File.renameTo().
I'm attempting to save files to my SD but i cannot get it to, I even tried moving the app to the SD to see if I can. I don't really care where it ends up on there but this isn;t working:
String state = Environment.getExternalStorageState();
File filesDir;
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
filesDir = getExternalFilesDir(null);
Log.i(Utils.TAG, "We can read and write the media: " + filesDir.getAbsolutePath()); // This is the local on the phone
} else {
// Load another directory, probably local memory
filesDir = getFilesDir();
Log.i(Utils.TAG, "Load another directory, probably local memory: " + filesDir.getAbsolutePath());
}
try {
// Creates a trace file in the primary external storage space of the
// current application.
// If the file does not exists, it is created.
//File traceFile = new File(((Context)this).getExternalFilesDir(null), "TraceFile.txt"); //This one saves to the internal file folder
File traceFile = new File(filesDir, "TraceFile.txt");
Log.i(Utils.TAG, traceFile.getAbsolutePath());
if (!traceFile.exists())
traceFile.createNewFile();
// Adds a line to the trace file
BufferedWriter writer = new BufferedWriter(new FileWriter(traceFile, true /*append*/));
writer.write("This is a test trace file.");
writer.close();
// Refresh the data so it can seen when the device is plugged in a
// computer. You may have to unplug and replug the device to see the
// latest changes. This is not necessary if the user should not modify
// the files.
MediaScannerConnection.scanFile((Context)(this),
new String[] { traceFile.toString() },
null,
null);
} catch (IOException e) {
Log.i(Utils.TAG, "Unable to write to the TraceFile.txt file.");
}
However, this gave me the SD file but I couldn't write to it:
public HashSet<String> getExternalMounts() {
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
String s = "";
try {
final Process process = new ProcessBuilder().command("mount")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
s = s + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
// parse output
final String[] lines = s.split("\n");
for (String line : lines) {
if (!line.toLowerCase(Locale.US).contains("asec")) {
if (line.matches(reg)) {
String[] parts = line.split(" ");
for (String part : parts) {
if (part.startsWith("/"))
if (!part.toLowerCase(Locale.US).contains("vold"))
out.add(part);
}
}
}
}
return out;
}
Android 4.4+ allows you to write to removable media, but only in select spots obtained by methods like:
getExternalFilesDirs()
getExternalCacheDirs()
getExternalMediaDirs() (this one was added in Android 5.0 IIRC)
Note the plural on those method names. If they return 2+ entries, the second and subsequent ones should be on removable media, in a directory that is unique for your app. You can read and write to those directories without any <uses-permission> element.
You might also consider the Storage Access Framework (ACTION_OPEN_DOCUMENT and kin), to allow the user to choose where to place the file, whether that be on external storage or removable storage or Google Drive or whatever.
Android 4.4 implemented numerous SD card limits, and there were (and still are) a lot of apps which broke during this period, because of issues with write limitations to the SD card. Your code itself seems fine to me, but my believe is that it's Android 4.4's SD Card limits which ensure that it doesn't work. How to fix that (without root access) is beyond me.