I'm writing a program that does various data analysis functions for use with Excel.
I need a way of returning file names of documents so I can search through them and find the ones I want.
I need to be able to take a string, saved as a variable, and use it to return the name of every document in a folder whose file name contains that string.
This will be used to sift through pre-categorized sections of data. Ideally I would save those documents' file names in a string array for later use within other functions.
private List<String> searchForFileNameContainingSubstring( String substring )
{
//This is assuming you pass in the substring from input.
File file = new File("C:/Users/example/Desktop"); //Change this to the directory you want to search in.
List<String> filesContainingSubstring = new ArrayList<String>();
if( file.exists() && file.isDirectory() )
{
String[] files = file.list(); //get the files in String format.
for( String fileName : files )
{
if( fileName.contains( substring ) )
filesContainingSubstring.add( fileName );
}
}
for( String fileName : filesContainingSubstring )
{
System.out.println( fileName ); //or do other operation
}
return filesContainingSubstring; //return the list of filenames containing substring.
}
Using this method, you could pass in the input from the user as the string you want the filename to contain. The only other thing you need to change is where you want in your directory to start searching for files, and this program only looks in that directory.
You could further look recursively within other directories from the starting point, but I won't add that functionality here. You should definitely look into it though.
This also assumes that you are looking for everything within the directory, including other folders and not just files.
You can get the list of all the files in a directory and then store them in an array. Next, using the java.io.File.getName() method, you can get the names of the files. Now you can simply use the .indexOf() method to check whether the string is a substring of the file name. I assume that all the items in the directory of concern are files and not sub directories.
public static void main(String[] args) throws IOException {
File[] files = new File("X:/").listFiles(); //X is the directory
String s <--- the string you want to check filenames with
for(File f : files){
if(f.getName().toLowerCase().indexOf(s.toLowerCase()) != -1)
System.out.println(f.getName());
}
}
This should display the names of all those files in the directory X:\ whose names include the String s.
References
This question: How do I iterate through the files in a directory in Java?
The java.io.File.getName() method
Statutory edit info
I have edited this answer simply to replace the previous algorithm, for checking the existence of a substring in a string, with the one that is currently used in the code above.
Here is an answer to search the file recursively??
String name; //to hold the search file name
public String listFolder(File dir) {
int flag;
File[] subDirs = dir.listFiles(new FileFilter() {
#Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
System.out.println("File of Directory: " + dir.getAbsolutePath());
flag = Listfile(dir);
if (flag == 0) {
System.out.println("File Found in THe Directory: " + dir.getAbsolutePath());
Speak("File Found in THe Directory: !!" + dir.getAbsolutePath());
return dir.getAbsolutePath();
}
for (File folder : subDirs) {
listFolder(folder);
}
return null;
}
private int Listfile(File dir) {
boolean ch = false;
File[] files = dir.listFiles();
for (File file : files) {
Listfile(file);
if (file.getName().indexOf(name.toLowerCase()) != -1) {//check all in lower case
System.out.println(name + "Found Sucessfully!!");
ch = true;
}
}
if (ch) {
return 1;
} else {
return 0;
}
}
Related
I have written a find function which is like this :
public static List<File> find ( String path, String fName) {
List<File> list = new ArrayList<>() ;
File dir = new File(path) ;
if( dir. isDirectory() ) {
for( String aChild : dir. list()) {
list = find(path + File.separator + aChild, fName) ;
}
}
else {
File[] files = dir. listFiles ( (d, name) -> name. startsWith(fName) && name. endsWith(".txt")) ;
for(File fl : files)
list. add(fl) ;
}
return list;
}
The Directory structure on my Local machine is like C:\Salary with sub directories like January, February etc. Each of the sub directory contains files like 601246_jan_sal.txt or 601246_ feb_sal.txt.
I am calling the find function like
List<File> filePath = Utils. find("C:\\Salary\\", "601246") ;
And then performing operation on each individual file.
The problem is that in the find method dir.listFiles(FileNameFilter) is returning null value.
What am I doing wrong?
Below is basically the same method with the exception that is uses regex along with the String#matches() method to determine a file name match. I used regex so that the ? and * wildcard characters can be used within your file name search criteria, for example:
"601246*.txt"
You may find this useful for other searches you might like to carry out.
There is no returned object with this method, you just need to pass the List to it. Here is an example of how you might use it:
List<File> fileList = new ArrayList<>();
String searchCriteria = "601246*.txt";
searchFolder(new File("C:\\Salary"), searchCriteria, fileList);
// Display found files within the Console Window:
if (!fileList.isEmpty()) {
for (File file : fileList) {
System.out.println(file.getAbsolutePath());
}
}
else {
System.out.println("File name (" + searchCriteria + ") can not be found!");
}
This will search the directory (and all its sub-directories) located at C:\Salary within the local file system for all files that start with 601246 and ends with .txt. Since your files are in the following format:
601246_jan_sal.txt or 601246_ feb_sal.txt
and you happen to want all the files for February Sales, your search criteria might be: *feb?sal.txt.
Here is the searchFolder() method:
/**
* This method navigates through the supplied directory and any
* sub-directories contained within it for the supplied file name search
* criteria. Anything found is placed within the supplied List object.<br>
*
* #param file (File) The starting point directory (folder) in
* the local file system where the file(s) search
* should begin.<br>
*
* #param searchCriteria (String) The name of the file to search for. The
* wildcard characters '?' and '*' can also be used
* within the search criteria. Using an asterisk (*)
* allows you to replace a string of text. This is
* often useful if you know what kind of file you’re
* looking for but don’t know where it is or what
* certain name parts might be. <br><br>
*
* The wildcard '?' lets you use it to replace any character in a search.
* This means that if you’re looking for a file and you’re not sure how it
* is spelled, you can simply substitute '?' for the characters you don’t
* know. In the following example, we search for files that start with
* “img_2” and ends with “.jpg”:<pre>
*
* img_2???.jpg</pre><br>
*
* #param list (List Interface of type File: {#code List<File>})
* This would be the List of File you pass to this
* method. It will be this list that is filled with
* found files objects.<br>
*
* #param ignoreLetterCase (Optional - Boolean) Default is true. The search
* is not letter case sensitive. If false is
* supplied then the search is letter case
* sensitive.
*/
public static void searchFolder(File file, String searchCriteria, List<File> list, boolean... ignoreLetterCase) {
boolean ignoreCase = true;
if (ignoreLetterCase.length > 0) {
ignoreCase = ignoreLetterCase[0];
}
// Convert the supplied criteria string to a Regular Expression
// for the String#matches() method
String regEx = searchCriteria.replace("?", ".").replace("-", ".").replace("*", ".*?");
if (ignoreCase) {
regEx = "(?i)" + regEx;
}
if (file.isDirectory()) {
//System.out.println("Searching directory ... " + file.getAbsoluteFile());
//do you have permission to read this directory?
if (file.canRead()) {
for (File temp : file.listFiles()) {
if (temp.isDirectory()) {
searchFolder(temp, searchCriteria, list, ignoreCase);
}
else {
if (temp.getName().matches(regEx)) {
list.add(temp);
}
}
}
}
else {
System.err.println(file.getAbsoluteFile() + " - PERMISSION DENIED!");
}
}
}
Since you are using recursion, you should pass the list (of files) as a parameter to method find and not create a new list on each invocation. Hence the method find does not need to return a value.
public static void find(String path, String fName, List<File> fileList) {
File dir = new File(path);
if (dir.isDirectory()) {
for (File aChild : dir.listFiles()) {
if (aChild.isDirectory()) {
find(aChild.getAbsolutePath(), fName, fileList);
}
else {
String name = aChild.getName();
if (name.startsWith(fName) && name.endsWith(".txt")) {
fileList.add(aChild);
}
}
}
}
else {
String name = aChild.getName();
if (name.startsWith(fName) && name.endsWith(".txt")) {
fileList.add(aChild);
}
}
}
If method parameter path indicates a directory, then list the files in that directory. For each file in the directory, check whether the name of the file matches your search criteria and if it does then add it to the list. If it doesn't then check if it is itself a directory and if it is then recursively call method find with the new directory.
Initially call method find like so
List<File> list = new ArrayList<File>();
find("C:\\Salary\\", "601246", list);
Now list should contain the list of relevant files. So the following line will print the contents of list
System.out.println(list);
I see a fundamental problem in your logic that answers your question. Here are the key lines along with an explanation:
if( dir.isDirectory() ) {
....
}
else {
File[] files = dir.listFiles(...); // <- "dir" is a file, not a directory
for(File fl : files)
list.add(fl) ;
}
You check if File object dir represents a directory. If that test fails (ie: it's not a directory), then you call dir.listFiles on it and assign the result to files. But if it's not a directory, then by the definition of that function, it will return null. It seems that if the check for a directory fails, you should just add the object to list instead of performing another operation on it.
I think you want this:
if( dir.isDirectory() ) {
....
}
else {
list.add(dir) ;
}
I guess dir isn't really the right name for the variable here, as it isn't always a directory.
Note that the Files.walk() method already does what you're trying to do.
public static List<File> find ( String path, String fName) {
List<File> result = new ArrayList<>();
FileVisitor<Path> visitor = new SimpleFileVisitor() {
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (attrs.isRegularFile()) {
String name = file.getFileName();
if (name.startsWith(fName) && name.endsWith(".txt")) {
result.add(file.toFile());
}
}
return FileVisitResult.CONTINUE;
}
};
Files.walk(Paths.get(path), visitor);
return result;
}
I need to search for a file based on a list of filenames inside a directory that contains 3100+ files and 14 folders but it takes hours to complete the search. Furthermore, I am only talking about 1 list of filenames yet, I still have other list of filenames to search.
After a locating the file to be searched, I need to access it and search for words inside it. And lastly proceed to the next file.
What I currently doing right now is that I used the concept of Breadth-First Search but it also takes hours to complete the search.
Are there any other ways to complete this task much faster?
See comments in the code
public class FileFinderApp {
// Create a list of file names that you want to process
private List<String> fileNames = new ArrayList<String>(Arrays.asList(new String[] {"test.txt","test1.txt","test2.txt"}));
// Create a FolderFilter, this just allows us to find files that are actually folders
private FolderFilter folderFilter = new FolderFilter();
public FileFinderApp() {
// Let the user know we are doing something in case there is no other output
System.out.println("Finding Files");
// Create a File to represent our starting folder
File startFolder = new File("F:\\FileTest");
// Get the list of Files that match our criteria
List<File> foundFiles = findFiles(startFolder, new FileNameFilter());
// loop through our files and do something with them
for (File file : foundFiles) {
// do something with each file
System.out.println(file.toString());
}
// Let the user know we are done.
System.out.println("Done Finding Files");
}
// This filter returns true if the File is a file (not folder, etc.) and matches one of our file names.
class FileNameFilter implements FileFilter {
public boolean accept(File file) {
return fileNames.contains(file.getName()) && file.isFile();
}
}
// This filter only returns folders
class FolderFilter implements FileFilter {
public boolean accept(File file) {
return file.isDirectory();
}
}
// Here's the meat and potatoes
private List<File> findFiles(File folder, FileFilter filter) {
// Create an empty list of Files
List<File> foundFiles = new ArrayList<File>();
// Find all sub-folders
File[] folders = folder.listFiles(folderFilter);
// Find the folders that pass our filter
File[] files = folder.listFiles(filter);
// add the files to our found files
foundFiles.addAll(Arrays.asList(files));
// for (File file : files) {
// System.out.println(file.getAbsolutePath());
// }
// loop through our sub-folders and get any files that match our filter there and add them to our list
// This is recursive and will execute as many levels as there are nested folders
for(File subFolder : folders) {
foundFiles.addAll(findFiles(subFolder, filter));
}
return foundFiles;
}
public static void main(String[] args) {
// don't block the UI
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new FileFinderApp();
}
});
}
}
See comments :
/**
* #param searchIn
* a valid path to any non null file or directory
* #param searchFor
* any non null name of a file or directory
*/
public static File findFile(String searchIn, String searchFor){
return findFile(new File(searchIn), searchFor);
}
/**
* #param searchIn
* not null file or directory
* #param searchFor
* any non null name of a file or directory
*/
public static File findFile(File searchIn, String searchFor){
if(searchIn.getName().equalsIgnoreCase(searchFor)) {
return searchIn;
}
if(searchIn.isDirectory() && (searchIn.listFiles() != null)){
for (File file : searchIn.listFiles() ){
File f = findFile(file, searchFor);
if(f != null) {
return f;
}
}
}
return null;
}
Tested with :
String sourcePath = "C:\\";
String searchFor = "Google Docs.ico";
File f = findFile(sourcePath, searchFor);
Performance measured :
time:13.596946 seconds, directories:17985 files:116837
I am trying to search files from sd card so i can delete multiple and duplicate files.``
private List<String> searchForFileNameContainingSubstring(String substring)
{
path = Environment.getExternalStorageDirectory().getPath() + "/";
//This is assuming you pass in the substring from input.
File file = new File(path); //Change this to the directory you want to search in.
List<String> filesContainingSubstring = new ArrayList<String>();
if (file.exists() && file.isDirectory())
{
String[] files = file.list(); //get the files in String format.
for (String fileName : files)
{
if (fileName.contains(substring))
filesContainingSubstring.add(fileName);
}
}
for (String fileName : filesContainingSubstring)
{
System.out.println(fileName); //or do other operation
}
return filesContainingSubstring; //return the list of filenames containing substring.
}
How can i scan other sub folders from sdcard/ directories
It only shows results from sdcard directories
You can use Apache Common's FileUtils.listFiles method.
You can search recursively throughout a folder by setting the third parameter as true.
Also, you can target specific file extensions by passing in the second argument a String array as seen below. If you want to target any extensions pass null.
Note: the extensions names do not include '.' it's "jpg" and not ".jpg"
String[] extensions = {"png","jpg"};
Collection images = FileUtils.listFiles(new File("dirPath"),extensions, true);
for (Object obj : images){
File file = (File) obj;
// your code logic
}
I am a beginner in Java trying to work with Files and Directories. I wanted to create a program where I could change file names automatically while searching through all the child directories for file names that are not valid. I am actually trying to load a huge amount of files on to a server but the server settings do not allow file names containing special characters. To start with I was able to write the code where if I pass the path to a directory it renames all the files with invalid names in that directory:
public class reNaming {
public static String baseLoc = "C:/Users/Developer/Desktop/.../Data Cleanup";
public static void main(String[] args) {
//LinkedList<File> fileList = new LinkedList<File>();
File obj = new File(baseLoc);
int count = 0;
for (File file: obj.listFiles())
{
String origName = file.getName();
if (origName.contains("&") || origName.contains("#") || origName.contains("#"))
{
System.out.println("Original name: "+origName);
origName = origName.replaceAll("&", "_and_");
origName = origName.replaceAll("#", "_at_");
String newName = origName.replaceAll("#", "_");
System.out.println("New Name: "+newName);
String newLoc = baseLoc+"/"+newName;
File newFile = new File(newLoc);
System.out.println(file.renameTo(newFile));
count++;
}
}
}
}
Now I want to do the same but only this time I want all the files to be reNamed even in the child directories. Can somebody please guide me how I can achieve that?
Recursion is your friend
/**Removes 'invalid' characters (&,#,#) from pathnames in the given folder, and subfolders, and returns the number of files renamed*/
public int renameDirectory(File base){
//LinkedList<File> fileList = new LinkedList<File>();
int count=0;//count the renamed files in this directory + its sub. You wanted to do this?
//Process each file in this folder.
for (File file: base.listFiles()){
String origName = file.getName();
File resultFile=file;
if (origName.contains("&") || origName.contains("#") || origName.contains("#")){
//I would replace the if statement with origName.matches(".*[&##].*") or similar, shorter but more error prone.
System.out.println("Original name: "+origName);
origName = origName.replaceAll("&", "_and_");
origName = origName.replaceAll("#", "_at_");
String newName = origName.replaceAll("#", "_");
System.out.println("New Name: "+newName);
String newLoc = baseLoc+File.separator+newName;//having "/" hardcoded is not cross-platform.
File newFile = new File(newLoc);
System.out.println(file.renameTo(newFile));
count++;
resultFile=newFile;//not sure if you could do file=newFile, tired
}
//if this 'file' in the base folder is a directory, process the directory
if(resultFile.isDirectory()){//or similar function
count+=renameDirectory(resultFile);
}
}
return count;
}
Move the code you have to a utility method (e.g. public void renameAll(File f){}). Have a condition that checks if the file is a directory and recursively call your method with it's contents. After that do what you are currently doing.
public void renameAll(File[] files){
for(File f: files){
if(f.isDirectory){
renameAll(f.listFiles());
}
rename(f);
}
}
public void rename(File f){ }
I'm working with some code and I want it to behave differently depending on the folder name that the file is in. I don't need the absolute path just the final folder. Everything that I have seen so far is using a absolute path that is specified in the file.
This is what you want:
public static String getParentName(File file) {
if(file == null || file.isDirectory()) {
return null;
}
String parent = file.getParent();
parent = parent.substring(parent.lastIndexOf("\\") + 1, parent.length());
return parent;
}
Unfortunately there is no pre-provided method that just returns the name of the last folder in the file's path, so you have to do some String manipulation to get it.
I think java.io.File.getParent() is what you are looking for:
import java.io.File;
public class Demo {
public static void main(String[] args) {
File f = null;
String parent="not found";
f = new File("/tmp/test.txt");
parent = f.getParent();
System.out.print("parent name: "+v);
}
}
Try java.io.File.getParentFile() method.
String getFileParentName(File file) {
if (file != null && file.getParentFile() != null) {
return file.getParentFile().getName();
}
return null; // no parent for file
}
There's
String File.getParent()
There's also
File File.getParentFile()
I don't know what the return in terms of being absolute or relative, but if it's absolute you can always find the last (or second to last, depending) instance of the "\" character (remember to escape it like this "\\") to denote where the lowest folder level is.
For example, if the function returned:
"C:\Users\YourName" is where you'd get the last occurance of "\", and all characters after it would be the folder you want
"C:\Users\YourName\" is where you'd get the second to last occurance of "\", and all characters between that and the last "\" would be the folder you're looking for.
Java File API:
http://docs.oracle.com/javase/7/docs/api/java/io/File.html
String path = "/abc/def"; // path to the directory
try
{
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
for (File file : listOfFiles)
{
if(file.isDirectory())
{
switch(file.getName)
{
case "folder1" : //do something
break
case "folder2" : //do something else
break
}
}
}
}
catch(Exception e)
{
System.out.println("Directory not Found");
}