I'm trying to search a file in ALL the SD Card with ".apk" extension. I've written this method.
public void scan(File file) {
mFile = file.listFiles();
if(mFile != null) {
for(int i=0;i<mFile.length;i++) {
if(mFile[i] != null) {
if(mFile[i].isDirectory()) {
scan(mFile[i]);
} else {
if(mFile[i].getName().endsWith(".apk")) {
lista.add(mFile[i].getName());
}
}
}
}
}
}
And I passed as parameter
scan(Environment.getExternalStorageDirectory());
The problem is that also if I've some apk files into SD Card the array list size is 0 and no one apk files is detected by this method. Why? My goal is to scan ALL the sd card to search .apk files.
Because mFile is a field, each call to scan does not get its own "copy" of mFile.
What happens when you call scan("/sdcard") is this: (I'm pretending the parameter is filename instead of a File, just to simplify this explanation)
scan("/sdcard") is entered
scan("/sdcard") sets mFile to the list of files in /sdcard. Say {"/sdcard/folder1", "/sdcard/folder2"}.
scan("/sdcard") calls scan("/sdcard/folder1") since that is the first element in mFile.
scan("/sdcard/folder1") sets mFile to the list of files in /sdcard/folder1. Say there are none.
scan("/sdcard/folder1") returns, since mFile.length is 0, k is 0, and 0<0 is not true.
scan("/sdcard") returns, since mFile.length is 0, k is 1, and 1<0 is not true.
Notice how it never got to /sdcard/folder2.
To fix your code, all you should need to do is make mFile a local variable inside scan.
Make mFile a local variable of scan. This is needed for recursion to work.
There's no need for this line in your code:
if(mFile[i] != null) {
Try this:
public void scan(File file) {
mFile = file.listFiles();
if(mFile != null) {
for(int i=0;i<mFile.length;i++) {
if(mFile[i].isDirectory()) {
scan(mFile[i]);
} else {
if(mFile[i].getName().endsWith(".apk")) {
lista.add(mFile[i].getName());
}
}
}
}
}
first Pass dir as "/download" exact location where ur files are stored in.
and then pass whole SD card root path
like searchAPK(new File("/download"));
and code try
private void searchAPK(File dir){
File[] files = dir.listFiles();
Log.i("DIR", "Found " + files.length + " in " + dir.getAbsolutePath());
for (File file : files) {
if(file.isFile() && isAPK(file)){
list.add(file);
Log.i("APK found", file.getName());
}else if(file.isDirectory()){
searchAPK(file.getAbsoluteFile());
}
}
}
private boolean isAPK(File file){
boolean is = false;
if(file.getName().endsWith(".apk") || file.getName().endsWith(".APK")){
is = true;
}
return is;
}
File[] files = dir.listFiles();
file should be local array in your case
Related
I have a project structure like below:
Now, my problem statement is I have to iterate resources folder, and given a key, I have to find that specific folder and its files.
For that, I have written a below code with the recursive approach but I am not getting the output as intended:
public class ConfigFileReader {
public static void main(String[] args) throws Exception {
System.out.println("Print L");
String path = "C:\\...\\ConfigFileReader\\src\\resources\\";
//FileReader reader = new FileReader(path + "\\Encounter\\Encounter.properties");
//Properties p = new Properties();
//p.load(reader);
File[] files = new File(path).listFiles();
String resourceType = "Encounter";
System.out.println(navigateDirectoriesAndFindTheFile(resourceType, files));
}
public static String navigateDirectoriesAndFindTheFile(String inputResourceString, File[] files) {
String entirePathOfTheIntendedFile = "";
for (File file : files) {
if (file.isDirectory()) {
navigateDirectoriesAndFindTheFile(inputResourceString, file.listFiles());
System.out.println("Directory: " + file.getName());
if (file.getName().startsWith(inputResourceString)) {
entirePathOfTheIntendedFile = file.getPath();
}
} else {
System.out.print("Inside...");
entirePathOfTheIntendedFile = file.getPath();
}
}
return entirePathOfTheIntendedFile;
}
}
Output:
The output should return C:\....\Encounter\Encounter.properties as the path.
First of all, if it finds the string while traversing it should return the file inside that folder and without navigating the further part as well as what is the best way to iterate over suppose 1k files because every time I can't follow this method because it doesn't seem an effective way of doing it. So, how can I use an in-memory approach for this problem? Please guide me through it.
You will need to check the output of recursive call and pass that back when a match is found.
Always use File or Path to handle filenames.
Assuming that I've understood the logic of the search, try this which scans for files of form XXX\XXXyyyy
public class ConfigReader
{
public static void main(String[] args) throws Exception {
System.out.println("Print L");
File path = new File(args[0]).getAbsoluteFile();
String resourceType = "Encounter";
System.out.println(navigateDirectoriesAndFindTheFile(resourceType, path));
}
public static File navigateDirectoriesAndFindTheFile(String inputResourceString, File path) {
File[] files = path.listFiles();
File found = null;
for (int i = 0; found == null && files != null && i < files.length; i++) {
File file = files[i];
if (file.isDirectory()) {
found = navigateDirectoriesAndFindTheFile(inputResourceString, file);
} else if (file.getName().startsWith(inputResourceString) && file.getParentFile().getName().equals(inputResourceString)) {
found = file;
}
}
return found;
}
}
If this is slow especially for 1K of files re-write with Files.walkFileTree which would be much faster than File.list() in recursion.
When I'm running this method I immediately get a stack overflow exception so obviously the method keeps recursively calling itself however I'm not sure why. For reference the file structure I'm testing it with is a load of folders and in those folders are files, no other folders
public void files(File[] f)
{
if(f == null){
return;
}
else
{
for(int i = 0; i < f.length; i++)
{
if(f[i].isFile() && (f[i].getName().contains(".mp3") || f[i].getName().contains(".m4a"))) //iterate through files and check if each file matches the required criteria
{
String fullname = f[i].getName();
Log.v("full name", fullname);
String name = null;
if(fullname.contains(".mp3"))
{
name = fullname.substring(0, fullname.lastIndexOf(".mp3"));
}
else if(fullname.contains(".m4a")) //Removing file extensions of music file so they can be displayed using an appropriate name
{
name = fullname.substring(0, fullname.lastIndexOf(".m4a"));
}
list.add(name);
mp3.add(f[i]);
Log.v("added", name);
}
if(f[i].isDirectory())
{
File inner[] = files[i].listFiles();
files(inner);
}
}
}
}
Maybe some of the files are "." and ".." which means , i think, the current folder and back one folder.
So in your isDirectory() part of the if check also check if f[i]!="." and f[i]!=".."
if(f[i].isDirectory() and f[i]!="." and f[i]!="..")
{
File inner[] = files[i].listFiles();
files(inner);
}
EDIT:
As #Jon said, try to add more debug to it and see where it breaks exactly.
LATER EDIT:
For future readers, the problem was here:
//File inner[] = files[i].listFiles();
File inner[] = f[i].listFiles();
So super dumb mistake on my part, when copying the code from a previous non recursive implementation I forgot to change files to f in
if(f[i].isDirectory())
{
File inner[] = files[i].listFiles();
files(inner);
}
I'm trying to write this script that takes an Excel sheet, gets all the names of files from the cells, and moves each of those files to a specific folder. I've already got most of the code done, I just need to be able to search for each file in the source directory using just its title. Another problem is that I'm searching for multiple file types (.txt, .repos, .xlsx, .xls, .pdf, and some files don't have extensions), I only can search by the file name without the extension.
In my findAndMoveFiles method, I've got an ArrayList of each File and a Guava Multimap of XSSFCells to Strings (a cell is one cell from the Excel file and a String is the name of the folder it needs to go into, one to many relationship) as parameters. What I've got right now for the method is this.
public static void findAndMoveFiles(List<File> files, Multimap<XSSFCell, String> innerCells) {
// For each file, get its values (folders), and put that file in each of those folders
for (XSSFCell cell : innerCells.keySet()) {
// find the file in the master directory
//Finder f = new Finder();
//if (f.canBeFound(FOLDER, cell.getStringCellValue())) {
File file = find(FOLDER, cell.getStringCellValue());
//System.out.println(file.getAbsolutePath());
//List<String> values = new ArrayList(innerCells.get(cell));
/*for (String folder : values) {
File copy = file;
if (copy != null) {
System.out.println(folder);
System.out.println(copy.getAbsolutePath());
if (copy.renameTo(new File("C:\\strobell\\" + folder + "\\" + copy.getAbsolutePath()))) {
System.out.println(copy.getName() + " has been moved successfully.");
} else {
System.out.println(copy.getName() + " has failed to move.");
}
}
}*/
//}
}
}
public static File find(File dir, String fileName) {
String files = "";
File[] listOfFiles = dir.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
files = listOfFiles[i].getAbsolutePath();
if (files.equals(fileName)) {
return listOfFiles[i];
}
}
}
return null;
}
I commented out parts because it wasn't working. I was getting NullPointerExceptions because some files were being returned as null. I know that it's returning null, but each file should be found.
If there are any 3rd party libraries that can do this, that would be amazing, I've been racking my brain on how to do this properly.
Instead of
File[] listOfFiles = dir.listFiles();
use
File[] listOfFiles = dir.list(new FileNameFilter() {
public boolean accept(File dir, String name) {
if( /* code to check if file name is ok */ ) {
return true;
}
return false;
}
}););
Then you can code your logic on the file names in the condition.
I have a folder which contains some files that I want to deleted after processing them. The files have the extension .FIR After some googling I found a recursive method that I modified a bit:
void delete(File f) throws IOException {
if (f.isDirectory()) {
for (File c : f.listFiles())
if(f.listFiles().toString().contains(".FIR"))
delete(c);
}
if (!f.delete())
throw new FileNotFoundException("Failed to delete file: " + f);
}
This function will throw an IOException telling me:
07-31 11:02:31.885: E/DELETE:(5694): Failed to delete file: /mnt/sdcard/ExtractedFiles
The folder has been set to RW operations. And in my manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I couldn't find another permission that sounded something like MODIFY_FILES
Any ideas?
try this:
void delete(File f) throws IOException {
if (f.isDirectory()) {
for (File c : f.listFiles()) {
delete(c);
}
} else if (f.getAbsolutePath().endsWith("FIR")) {
if (!f.delete()) {
new FileNotFoundException("Failed to delete file: " + f);
}
}
}
Better use temp files....
File f = File.createTempFile("pattern", ".suffix");
Once the application is closed, the temp files are first closed then deleted.
See this link for more details:
http://www.roseindia.net/java/example/java/io/create-temp-file.shtml
I think the problem is here:
if(f.listFiles().toString().contains(".FIR"))
change this to:
if(c.getName().contains(".FIR"))
And make sure your directory contains files with extension .FIR only, otherwise (if any other extension files are available) it will still fail to delete a non-empty directory
Otherwise use the following method to get it done:
private static boolean delete(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = delete(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return (dir.getName().contains(".FIR"))? dir.delete() : false;
}
check this
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
i was using this code and it;s working:
String root_sd = Environment.getExternalStorageDirectory().toString();
File file = new File(path) ;
File list[] = file.listFiles();
for(File f:list)
{
name = file.getName();
filestv.setText(f.getName());
//add new files name in the list
// delete.setText(name );
}
}
and you can follow the complete tutorials
How can I delete one folder/directory by a non-recursive algorithm in Java? I want to use a non-recursive algorithm in order to avoid StackOverflowErrors when a folder has a very deep path.
Could someone please offer some advise in this area.
In crappy pseudo-code, as I don't have a Java compiler handy to test this:
queue = [ rootDir ]
stack = []
while ( !queue.isEmpty() ) {
currentDir = queue.take()
stack.push( currentDir )
files = currentDir.list()
for ( f : files ) {
if ( f.isDirectory() ) {
queue.add( f )
} else {
f.delete()
}
}
}
while ( !stack.isEmpty() ) {
f = stack.pop()
f.delete()
}
Basically this code should scan a directory, deleting files or queueing subdirectories for further scanning. It places scanned directories in a stack, so that the second while loop deletes them in the correct order (deepest first).
Here's a general way to delete a file/folder :
/**deletes a file/folder recursively, and returns true iff succeeded */
public static boolean deleteQuietly(File file) {
if (file == null || !file.exists())
return true;
if (!file.isDirectory())
return file.delete();
LinkedList<File> dirs = new LinkedList<>();
dirs.add(0, file);
boolean succeededDeletion = true;
while (!dirs.isEmpty()) {
file = dirs.remove(0);
File[] children = file.listFiles();
if (children == null || children.length == 0)
succeededDeletion &= file.delete();
else {
dirs.add(0, file);
for (File child : children)
if (child.isDirectory())
dirs.add(0, child);
else
succeededDeletion &= child.delete();
}
}
return succeededDeletion;
}
this is just a starting point for you to improve on.
The critical part is to find out what's the directories to delete.
This piece of psuedo code should help you to find out all directories under certain directory:
Set<File> allDirectories = new Set<File>();
allDirectories.add(yourStartingDirectory);
while (hasMoreToRead) {
hasMoreToRead = false;
for (File f : allDirectories) {
if (f.isDirectory() && !allDirectories.contains(f)) {
allDirectories.add(f);
hasMoreToRead = true;
}
}
}
This is just a starting point, but you should be able to finish the rest: Avoid revisiting directories in allDirectories that has been processed in previous iterations; Performing delete base on allDirectories; Make the delete more efficient by deleting in "correct" order; etc
// Deletes all files and subdirectories under dir.
// Returns true if all deletions were successful.
// If a deletion fails, the method stops attempting to delete and returns false.
public static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i=0; i<children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// The directory is now empty so delete it
return dir.delete();
}
To remove recursion, you replace the call stack with an explicit stack to hold the items you still need to process. In your case, you keep track of all the parent folders you need to delete after you are done with the current one. Here's an example using a LinkedList as a stack:
public static void rmdir(File dir) {
LinkedList<File> dirs = new LinkedList<File>();
dirs.push(dir);
while (dirs.peek() != null) {
dir = dirs.pop();
File[] contents = dir.listFiles();
if (contents.length == 0) {
dir.delete();
} else {
dirs.push(dir);
for(File content : contents) {
if (content.isDirectory()) {
dirs.push(content);
} else {
content.delete();
}
}
}
}
}
My interpretation of your question is that you want to delete a directory without recursing into the directories within it. In this case, you can implement the deletion using a pretty simple loop...
File directory = new File("c:\\directory_path")
if (!directory.exists()){
return;
}
File[] files = directory.listFiles();
for (int i=0;i<files.length;i++){
if (files[i].isFile()){
boolean deleted = files[i].delete();
if (!deleted){
System.out.println("Problem deleting file " + files[i].getAbsolutePath());
}
}
}
This will list all the Files of the directory in an array, and then loop through them. If the file is a normal file, it will be deleted. Non-normal files, such as directories, will be skipped.
Of course, there are other similar alternatives, such as adding a FileFilter to the listFiles() method so that the array is only populated by normal files, but its effectively pretty similar.
If you want to delete the directory tree, you will have to use some kind of recursion. You could approach it differently though, which might not cause you so many problems, such as building an ArrayList of directories, and then iterating through the ArrayList deleting them one at a time. This would help to reduce the recursion.
public static final void delete(File file) throws IOException
{
if (!file.exists())
throw new IllegalArgumentException("File does not exist: " + file);
if (file.isFile())
{
simpleDelete(file);
return;
}
Deque<File> dirsQueue = new ArrayDeque<File>();
dirsQueue.push(file);
for (File dir; (dir = dirsQueue.peekLast()) != null;)
{
File[] children = dir.listFiles();
if (children == null)
throw new IOException("Unable to read directory: " + dir);
if (children.length == 0)
{
simpleDelete(dir);
dirsQueue.removeLast();
continue;
}
for (File child : children)
{
if (child.isDirectory())
dirsQueue.addLast(child);
else
simpleDelete(child);
}
}
}
private static final void simpleDelete(File file) throws IOException
{
if (!file.delete())
throw new IOException("Unable to delete " + (file.isDirectory() ? "directory" : "file") + ": " + file);
}