It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I'd like to do a search for folders/directories from java, and go into those folders/directories in java. I guess it's called system utilities? Any tutorials out there, or books on the subject?
Thanks ;)
I use this code to get all ZIP files in a folder. Call this recursively checking for the file object to be a sub directory again and again.
public List<String> getFiles(String folder) {
List<String> list = new ArrayList<String>();
File dir = new File(folder);
if(dir.isDirectory()) {
FileFilter filter = new FileFilter() {
public boolean accept(File file) {
boolean flag = false;
if(file.isFile() && !file.isDirectory()) {
String filename = file.getName();
if(!filename.endsWith(".zip")) {
return true;
}
return false;
}
};
File[] fileNames = dir.listFiles(filter);
for (File file : fileNames) {
list.add(file.getName());
}
return list;
}
You could use Apache Commons FileUtils (see: http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html) and specifically the listFiles method there, which can do this recursively and use filters (so it saves you the writing of the recursion yourself and answers the search you mentioned).
If you want to navigate the file system, take a look at File and the list() method. You'll most likely require some recursive method to navigate down through the hierarchies.
I'd recommend Apache Commons IO utilities.
I don't know of any tutorials or books on that particular subject, but the way to do it is to use the java.io.File class. For example, you can use the list() to get a list of the contents of a directory. Then it's just a matter of using isDirectory() and recursing to search an entire file tree.
You can use java.io.File class to search.
here is another example:
for (File file : File.listRoots()[0].listFiles()) {
System.out.println(file);
}
the same, printing only directories:
FileFilter isDirectory = new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory();
}
};
for (File file : File.listRoots()[0].listFiles(isDirectory)) {
System.out.println(file);
}
Good example:
http://www.leepoint.net/notes-java/io/10file/20recursivelist.html
BTW. I recommend reading the whole thing. http://www.leepoint.net/notes-java/
I used Apache Commons VFS.
Is nice to use it for read contents of a directory, like this:
FileSystemManager fsManager = VFS.getManager();
FileObject path = fsManager.resolveFile( "file:///tmp" );
FileObject[] children = path.getChildren();
System.out.println( "Children of " + path.getName().getURI() );
for ( int i = 0; i < children.length; i++ )
{
System.out.println( children[ i ].getName().getBaseName() );
}
You can check if children is file, folder or something different with getType().
And same code works for reading ZIP or JAR files, FTP, SFTP, ... just changing the URL of resolveFile as you can see here.
Related
I'm using a method from this site to read all the files exist on the system hard drives, it's working fine, but i need to check that a certain file exists while searching.
to make the story short here is the line code which is reading the files
parseAllFiles(f.getAbsolutePath());
how can I assign the output from this method to a string so i can search iniside this string for the file I want, or there any way to add/change to this statement to get the filename directely in a string?
public static void parseAllFiles(String parentDirectory){
File[] filesInDirectory = new File(parentDirectory).listFiles();
if(filesInDirectory != null){
for(File f : filesInDirectory){
if(f.isDirectory()){
parseAllFiles(f.getAbsolutePath()); // get full path
}
System.out.println("Current File -> " + f);
}
}
}
Use objects rather than strings since they tend to offer useful functionality that strings don’t offer. In your case pass a File object or a Path object to your recursive method. I take it that you start out from a string, so have your public method accept a string and construct the first object.
public static void parseAllFiles(String parentDirectory) {
parseAllFiles(new File(parentDirectory));
}
private static void parseAllFiles(File dir) {
File[] filesInDirectory = dir.listFiles();
if (filesInDirectory != null) {
for (File f : filesInDirectory) {
String fileName = f.getName();
String fullPathName = f.getAbsolutePath();
System.out.println("Current File -> " + fileName);
System.out.println("Current path -> " + fullPathName);
if (f.isDirectory()) {
parseAllFiles(f);
}
}
}
}
I didn’t get whether you wanted only the file name or the full path name of the file, but the code shows how to extract each into a string. You may then search inside these two strings for whatever you are looking for.
java.nio since Java 7
I routinely use java.nio.file for file system operations. For everyday purposes I don’t find it better to work with than the older File class, but it does offer a wealth of options that the older class doesn’t offer. #Shahar Rotshtein in a comment mentioned the FileVisitor interface from java.nio.file. Depending on your exact requirements Files.walkFileTree passing your own FileVisitor may be the best option for you. I have not understood your real requirements well enough to offer a code example.
Links
java.nio.file documentation
Section Walking the file tree in the Oracle tutorial: Basic I/O
I have a network associated storage where around 5 million txt files are there related to around 3 million transactions. Size of the total data is around 3.5 TB. I have to search in that location to find if the transaction related file is available or not and have to make two separate reports as CSV file of "available files" and "not available files". We are
still in JAVA 6. The challenge that I am facing since I have to search in the location recursively, it takes me around average 2 mins to search in that location because of huge size. I am using Java I/O API to search recursively like below. Is there any way I can improve the performance?
File searchFile(File location, String fileName) {
if (location.isDirectory()) {
File[] arr = location.listFiles();
for (File f : arr) {
File found = searchFile(f, fileName);
if (found != null)
return found;
}
} else {
if (location.getName().equals(fileName)) {
return location;
}
}
return null;
}
You should take a different approach, rather than walking the entire directory every time you search for a file, you should instead create an index, which is a mapping from filename to file location.
Essentially:
void buildIndex(Map index, File baseDir) {
if (location.isDirectory()) {
File[] arr = location.listFiles();
for (File f : arr) {
buildIndex(index, f);
}
} else {
index.put(f.getName(), f);
}
}
Now that you've got the index, searching for the files becomes trivial.
Now you've got the files in a Map, you can also even use Set operation to find the intersection:
Map index = new HashMap();
buildIndex(index, ...);
Set fileSet = index.keySet();
Set transactionSet = ...;
Set intersection = new HashSet(fileSet);
fileSet.retainAll(transactionSet);
Optionally, if the index itself is too big to keep in memory, you may want to create the index in an SQLite database.
Searching in a Directory or a Network Associated Storage is a
nightmare.It takes lot of time when directory is too big / depth. As you are in Java 6 ,
So you can follow an old fashion approach. List all files in a CSV file like
below.
e.g
find . -type f -name '*.txt' >> test.csv . (if unix)
dir /b/s *.txt > test.csv (if Windows)
Now load this CSV file into a Map to have an index as filename. Loading the file will take some time as it will be huge but once you load then searching in the map ( as it will be file name ) will be much more quick and will reduce your search time drastically.
You can use NIO FileVisitor, available in java 6.
Path findTransactionFile(Path root) {
Path transactionFile = null;
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if (/* todo dir predicate*/ false) {
return FileVisitResult.SKIP_SUBTREE; // optimization
}
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (/* todo file predicate*/ true) {
transactionFile = file;
return FileVisitResult.TERMINATE; // found
}
return FileVisitResult.CONTINUE;
}
});
return transactionFile;
}
I dont know the answer, but from algorithm perspective, your program has the worst complexity. per single look up for single transaction , it iterates all the files (5 million). you have 3 million transactions.
my suggestion is to iterate the files (5 million files) and build up an index based on the file name. then iterate the transactions and search the index instead of full scan.
Or there might be third party free tools that can index a large file system and then that index can be accessed by an external application (in this case your java app). if you can not find that kind of tool, better you invent it (then you can build the index in a optimum way that suits your requirement).
I have a program that needs to read files. I need to check every 10 seconds if there is new files.
To do that, I've made this :
ArrayList<File>oldFiles = new ArrayList<File>();
ArrayList<File>files=new ArrayList<File>();
while(isFinished != true){
files=listFilesForFolder(folder);
if(oldFiles.size() != files.size()){
System.out.println("Here is when a new file(s) is(are) in the folder");
}
Thread.sleep(10000);
}
Basically, the listFilesForFolder is getting a folder destination, and check the files in there.
My problem : My program does every loop my reading function on every file. I want to do my reading function ONLY on new files.
How can I do something like :
new files - old files = my files I want to read.
Rather than your approach why not store the DateTime of the last time that you checked.
Then compare this time to the File.lastModified value
The problem with your appraoch is that the array sizes will be different even in a file is deleted, and will be the same if one file is deleted and one file is added.
Rather than comparing old and new files, why not write a method to just return Last Modified Files.
public static ArrayList<File> listLastModifiedFiles(File folder,
long sleepDuration) throws Exception {
ArrayList<File> newFileList = new ArrayList<File>();
for (File fileEntry : folder.listFiles())
if ((System.currentTimeMillis() - fileEntry.lastModified()) <= sleepDuration)
newFileList.add(fileEntry);
return newFileList;
}
//Sample usage:
long sleepDuration = 10000;
ArrayList<File> newFileList;
int counter = 10;
while (counter-- > 0) {
newFileList = listLastModifiedFiles(folder, sleepDuration);
for (File File : newFileList)
System.out.println(File.getName());
Thread.sleep(sleepDuration);
}
You can use sets. Instead of returning an ArrayList, you could return a set instead.
newFiles.removeAll(oldFiles);
would then give you all the files that are not in the old set. I'm not saying that working with the modification date as Scary Wombat has pointed out is a worse idea, I'm just offering another solution.
Additionally, you have to modify your oldFiles to hold all files you've already encountered. The following example I think does what you're trying to achieve.
private static Set<File> findFilesIn(File directory) {
// Or whatever logic you have for finding files
return new HashSet<File>(Arrays.asList(directory.listFiles()));
}
public static void main(String[] args) throws Throwable {
Set<File> allFiles = new HashSet<File>(); // Renamed from oldFiles
Set<File> newFiles = new HashSet<File>();
File dir = new File("/tmp/stackoverflow/");
while (true) {
allFiles.addAll(newFiles); // Add files from last round to collection of all files
newFiles = findFilesIn(dir);
newFiles.removeAll(allFiles); // Remove all the ones we already know.
System.out.println(String.format("Found %d new files: %s", newFiles.size(), newFiles));
System.out.println("Sleeping...");
Thread.sleep(5000);
}
}
Sets are a more appropiate data storage for your case since you don't need any order in your collection of files and can benefit from faster lookup times (when using a HashSet).
Assuming that you only need to detect new files, not modified ones, and no file will be removed while your code is running:
ArrayList implements removeAll(Collection c), which does exactly what you want:
Removes from this list all of its elements that are contained in the
specified collection.
You might want to consider using the Java WatchService API which uses the low level operating system to notify you of changes to the file system. It's more efficient and faster than listing the files in directory.
There is a tutorial at Watching a Directory for Changes and the API is documented here: Interface WatchService
Before you speculate something like "This guy is asking for homework help", I'll go ahead and clear any doubts you may have and say yes, this is related to homework. However, I hope that does not take away from the learning that this question provides to me and/or anyone who reads this in the future.
Background: We're currently working on recursion and our assignment asks that we write a program that uses command arguments to check a directory and its file contents for a string(that is also a command argument). We must use recursion for this.
-I want to make this clear that I UNDERSTAND WHAT THE ASSIGNMENT IS ASKING
I am simply asking, how would this work recursively because I just don't get it.
We did a problem where we had to find the size of a directory and it made sense, but I don't get how to check if something is a directory or file and based on that we read its contents or go deeper into the directory until we find a file.
Here's what I've currently done. Not too sure how wrong this is as I'm basing entirely off of the 'check the size of a directory' assignment we previously did:
The folder that I'm checking is something like this:
Directory ---> files --inside main directory --->> Two directories ----> files within both of those directories
public class SearchingForStrings {
public static void main(String[] args) {
String path = "."; // default location of this project
File sf = new File(path);
String mysteriesDirectory = args[0];
String keyString = args[1];
countLinesWithString(sf, mysteriesDirectory, keyString);
}
public static int countLinesWithString(File startPath, String mysteriesDirectory, String keyString) {
if(!startPath.exists()) {
throw new IllegalArgumentException("File " + startPath + " does not exist!");
} else if(startPath.isFile()) {
return Integer.parseInt(startPath.getAbsolutePath()); // Just to show where the file is I located the parsing is just to stop an error from flagging on this part; Going to ask professor if it's okay with him
// this is where we would begin reading the contents of the files
} else if(startPath.isDirectory()) {
// This is where our recursion would take place: essentially
// we will be going 'deeper' into the directory until we find a file
//File[] subFiles = startPath.listFiles();
countLinesWithString(startPath, mysteriesDirectory, keyString);
} else {
throw new IllegalStateException("Unknown file type: " + startPath);
}
}
}
In short: Could someone explain how recursion would work if you wanted to go deeper into a director(y/ies)?
I'll give this a try. It's something that is easier to explain than to understand.
The recursive method, on which you have made a decent start, might be documented as follows:
"For a given directory: for each file in the directory, count all the lines which contain a given string; for each directory in the directory, recurse".
The recursion is possible - and useful - because your original target is a container, and one of the types of things it can contain is another container.
So think of the counting method like this:
int countLines(dir, string) // the string could be an instance variable, also, and not passed in
{
var countedLines = 0;
for each item in dir:
if item is file, countedLines += matchedLinesInFile(item, string);
else if item is dir, countedLines += countLines(item, string);
else throw up; // or throw an exception -- your choice
}
then call countLines from an exterior method with the original dir to use, plus the string.
One of the things that trips people up about recursion is that, after you get it written, it doesn't seem possible that it can do all that it does. But think through the above for different scenarios. If the dir passed in has files and no dirs, it will accumulate countedLines for each file in the dir, and return the result. That's what you want.
If the dir does contain other dirs, then for each one of those, you're going to call the routine and start on that contained dir. The call will accumulate countedLines for each file in that dir, and call itself for each dir recursively down the tree, until it reaches a dir that has no dirs in it. And it still counts lines in those, it just doesn't have any further down to recurse.
At the lowest level, it is going to accumulate those lines and return them. Then the second-lowest level will get that total to add to its total, and start the return trips back up the recursion tree.
Does that explain it any better?
Just help you get started with recursion check this :
It will recursively go from base directory printing all the folders and files.
Modify this to your requirements. Try and let us know.
import java.io.File;
public class Test {
public static void getResource(final String resourcePath) {
File file = new File(resourcePath);
if (file.isFile()) {
System.out.println("File Name : " + file.getName());
return;
} else {
File[] listFiles = file.listFiles();
if (listFiles != null) {
for (File resourceInDirectory : listFiles) {
if (!resourceInDirectory.isFile()) {
System.out.println("Folder "
+ resourceInDirectory.getAbsolutePath());
getResource(resourceInDirectory.getAbsolutePath());
} else {
getResource(resourceInDirectory.getAbsolutePath());
}
}
}
}
}
public static void main(String[] args) {
final String folderPath = "C:/Test";
getResource(folderPath);
}
}
Here's my java code:
import java.io.File;
import java.util.Arrays;
public class mainClass {
public static void main(String... args) {
File[] files = new File("%appdata%").listFiles();
showFiles(files);
System.out.println( Arrays.toString( files ) );
if (Arrays.asList(files).contains(".minecraft")) {
System.out.println("Success!");
}
}
public static void showFiles(File[] files) {
}
}
I want code above to check if .minecraft folder exists in %appdata%. I am total N00B to Java. I have worked with PHP, but doesn't seem to help me :) Please help, it annoys me.
-Simon
If you are interested in finding only the ".minecraft" file it would be much easier to:
File appdata = new File("%appdata%");
File minecraft = new File(appdata, ".minecraft");
if (minecraft.exists()) {
System.out.println("Success");
}
EDIT: Based on comment, (and I'm a linux guy mostly), you need to use the correct %APPDATA% location: How do I get the value of Windows' %APPDATA% location variable in Java?
The problem is that .minecraftis a hidden folder. You need to access the folder like this:
File directory = new File("%appdata%");
File[] hiddenFiles = directory.listFiles((FileFilter) HiddenFileFilter.HIDDEN);
for (File hiddenFile: hiddenFiles) {
System.out.println("hidden file: " + hiddenFile.getCanonicalPath());
}
As rolfl mentioned, there is a better way to look for a single file.
That said, your code isn't performing a proper check. You are creating an array of File objects, converting the array to a List, and then checking the list for a String value. The String value will never match a File object.
If you want to find a single file, use rolfl's answer. If you want to fix your code specifically, here's something to get your started:
You need to iterate over the list of files. What do you gain by converting to a List?
You need to find a way to match a File's name with a String name. What method might you call on the File object to get its name?
You need to do a String comparison between the File's name and ".minecraft". What might that comparison look like?
Please note: reference L.Butz answer as well; I haven't accessed hidden files in Java, so it's possible there's an extra step you need to get access to them.
%appdata%is an environment variable and as such it will not be automatically resolved by File. So you need to resolve it before listing it. This is done using System#getenv
#Test
public void dirExistsInAppData() {
Assert.assertTrue(dirExistsInAppData(".minecraft"));
}
private boolean dirExistsInAppData(final String dirname) {
File dir = new File(System.getenv("APPDATA"), dirname);
return dir.exists() && dir.isDirectory();
}