So I am learning recursion right now and I know how to get the largest file size in a folder that's chosen in JFileChooser.
I just can't for the life of me can't figure out how to get the name of that file after it's found. Here's the method to getting the largestFileSize. How would I go about getting the name of that file?
public static long largestFileSize(File f) {
if (f.isFile()) {
return f.length();
} else {
long largestSoFar = -1;
for (File file : f.listFiles()) {
largestSoFar = Math.max(largestSoFar, largestFileSize(file));
}
return largestSoFar;
}
}
String fileName = file.getName()
Since it's impractical to return both the size of a file and the name, why don't you return the File and then get its size and name from that?
public static File largestFile(File f) {
if (f.isFile()) {
return f;
} else {
File largestFile = null;
for (File file : f.listFiles()) {
// only recurse largestFile once
File possiblyLargeFile = largestFile(file);
if (possiblyLargeFile != null) {
if (largestFile == null || possiblyLargeFile.length() > largestFile.length()) {
largestFile = possiblyLargeFile;
}
}
}
return largestFile;
}
}
And then you can do this:
String largestFileName = largestFile(file).getName();
long largestFileSize = largestFile(file).length();
EDIT: Returns largest File in any of the subdirectories. Returns null if no files exist in the subdirectories.
Just do
public static File largestFile(File f) {
if (f.isFile()) {
return f;
} else {
long largestSoFar = -1;
File largestFile = null;
for (File file : f.listFiles()) {
file = largestFile(file);
if (file != null) {
long newSize = file.length();
if (newSize > largestSoFar) {
largestSoFar = newSize;
largestFile = file;
}
}
}
return largestFile;
}
}
then call:
largestFile(myFile).getName();
Related
new File("C:/Users/jredfox/AppData/Local/Microsoft/WindowsApps/wt.exe").exists() returns false when the exact path copied and pasted to command prompt starts windows terminal. Any ideas of how to get it working?
also tried
File f = new File("C:/Users/jredfox/AppData/Local/Microsoft/WindowsApps");
for(File a : f.listFiles())
{
System.out.println(a + " isSymbolicLink:" + Files.isSymbolicLink(a.toPath()) + " exists:" + Files.exists(a.toPath()));
}
couldn't seem to find an answer but I found a workaround.
private static boolean isWindows = osName.contains("windows");
private static boolean isLinux = osName.contains("linux") || osName.contains("nux") || osName.contains("aix");
private static boolean isMac = osName.contains("mac") && !isLinux || osName.contains("osx") || osName.contains("darwin");
/**
* find executeable from path. support for WUP and macOs apps as well as standard with and without extensions paths
*/
public static String findExe(String name)
{
String ext = isWindows() ? ".exe" : isMac() ? ".app" : "";//TODO: test macOs and confirm functionality on windows
String fname = name.contains(".") ? name : name + ext;
boolean hasF = !ext.isEmpty();
//search the full path of the dir before searching env path
if(name.contains("/"))
{
File path = new File(name);
File fpath = new File(fname);
if(path.canExecute())
return path.getPath();
else if(hasF && isExe(fpath))
return fpath.getPath();
}
for (String dirname : System.getenv("PATH").split(File.pathSeparator))
{
File file = new File(dirname, name);
File ffile = new File(dirname, fname);
//Windows 10 WUP support
if(OSUtil.isWindows())
{
if(dirname.contains("WindowsApps"))
{
File[] files = file.getParentFile().listFiles();
if(FileUtil.containsFile(files, file) && !file.isDirectory())
return file.getPath();
else if(FileUtil.containsFile(files, ffile) && !file.isDirectory())
return ffile.getPath();
}
}
if (isExe(file))
return file.getPath();
else if(hasF && isExe(ffile))
return ffile.getPath();
}
//macOS start here
if(OSUtil.isMac())
{
for(String root : macAppPaths)
{
File app = new File(root, fname);
if(isExe(app))
return app.getPath();
}
}
return null;
}
public static boolean isWindows()
{
return isWindows;
}
public static boolean isMac()
{
return isMac;
}
public static boolean isLinux()
{
return isLinux;
}
public static boolean isExe(File f)
{
return (f.isFile() || f.getName().endsWith(".app")) && f.canExecute();
}
I have a program that should process the files in the directory and if the file size is more than 50 bytes delete it. Otherwise, if the file size is less then 50 bytes program should rename the args[1] file to the allFilesContent.txt(same directory), and write all the files to this file, separated by "n" (110 ASCII code). But instead the program just creates another file and writes to the very first args[1] file. What's the problem?
public class Solution
{
public static void main(String [] args) throws IOException
{
File path = new File(args[0]);
File resultFileAbsolutePath = new File(args[1]);
ArrayList<File> allFiles = new ArrayList<>();
boolean isRenamed = false;
for(File file : path.listFiles())
{
if(file.length() > 50)
{
FileUtils.deleteFile(file);
}
else if(file.length() <= 50)
{
if(!isRenamed)
{
FileUtils.renameFile(resultFileAbsolutePath, new File(resultFileAbsolutePath.getParent()+"\\allFilesContent.txt"));
isRenamed = true;
}
if(!file.getName().equals(resultFileAbsolutePath.getName()))
{
allFiles.add(file);
}
}
}
Collections.sort(allFiles, new Comparator<File>()
{
#Override
public int compare(File o1, File o2)
{
return o1.getName().compareTo(o2.getName());
}
});
FileOutputStream fileOutputStream = new FileOutputStream(resultFileAbsolutePath, true);
for (File file : allFiles)
{
try(FileInputStream fileInputStream = new FileInputStream(file))
{
if(allFiles.indexOf(file) != 0) fileOutputStream.write(110);
int data;
while(fileInputStream.available() > 0)
{
data = fileInputStream.read();
fileOutputStream.write(data);
}
}
}
fileOutputStream.close();
}
public static void deleteFile(File file)
{
if (!file.delete())
{
System.out.println("Can not delete file with name " + file.getName());
}
}
}
And FileUtils class
import java.io.File;
public class FileUtils
{
public static void deleteFile(File file)
{
if (!file.delete())
{
System.out.println("Can not delete file with name " + file.getName());
}
}
public static void renameFile(File source, File destination)
{
if (!source.renameTo(destination))
{
System.out.println("Can not rename file with name " + source.getName());
}
}
}
You have following statement: "FileOutputStream fileOutputStream = new FileOutputStream(resultFileAbsolutePath, true);"
Instead of "true" put "false". It should work.
I want to list all files in resources classpath ,I used the following code but get null exception in fList
String path = request.getSession().getServletContext().getRealPath("/resources/rules");
File directory = new File(path);
File[] fList = directory.listFiles();
for (File file : fList){
if (file.isFile()){
System.out.println(file.getName());
}
}
Here is a working example:
https://github.com/bleujin/aradon/blob/master/src/net/ion/nradon/helpers/ClassloaderResourceHelper.java#L30
public static Iterable<FileEntry> listFilesRelativeToClass(Class<?> clazz, String subdirectory) throws IOException {
ArrayList<FileEntry> list = new ArrayList<FileEntry>();
CodeSource src = clazz.getProtectionDomain().getCodeSource();
if (src == null) {
return list;
}
URL classpathEntry = src.getLocation();
try {
// Check if we're loaded from a folder
File file = new File(new File(classpathEntry.toURI()), subdirectory);
if (file.isDirectory()) {
return fileEntriesFor(file.listFiles());
}
} catch (URISyntaxException e) {
// Should never happen, because we know classpathentry is valid
throw new RuntimeException(e);
}
// We're not in a folder, so we must be in a jar or similar
subdirectory = subdirectory.replace(File.separatorChar, '/');
if (!subdirectory.endsWith("/")) {
subdirectory = subdirectory + "/";
}
ZipInputStream jarStream = new ZipInputStream(classpathEntry.openStream());
ZipEntry zipEntry;
while ((zipEntry = jarStream.getNextEntry()) != null) {
if (isChild(subdirectory, zipEntry.getName())) {
String basename = zipEntry.getName().substring(subdirectory.length());
int indexOfSlash = basename.indexOf('/');
if (indexOfSlash < 0 || indexOfSlash == basename.length() - 1) {
list.add(new FileEntry(basename));
}
}
}
return list;
}
private static boolean isChild(String parent, String name) {
return name.startsWith(parent);
}
public static Iterable<FileEntry> fileEntriesFor(File[] files) {
List<FileEntry> fileEntries = new ArrayList<FileEntry>(files.length);
for (File file : files) {
String filename = file.getName();
if (file.isDirectory()) {
filename += "/";
}
fileEntries.add(new FileEntry(filename));
}
return fileEntries;
}
}
How about this source code?
String[] resoures = srcDir.list( new java.io.FilenameFilter()
{
public boolean accept( File dir, String name )
{
String[] extensions = { ".png", ".jar", ".txt" };
String fileName = name.toLowerCase( Locale.getDefault() );
for ( int i = 0; i < extensions.length; i++ )
{
if ( fileName.endsWith( extensions[i] ) )
{
return true;
}
}
return false;
}
} );
Full source here:
http://code.openhub.net/file?fid=kpl9VrAT-CHXE496rmMP8Jbzo5U&cid=y9kXCqEmUoY&s=List%20all%20files%20in%20resoures%20directory%20in%20java%20project&pp=0&fl=Java&ff=1&projSelected=false&filterChecked,=true&mp,=1&mp=1&ml=1&me=1&md=1#L64
I'm working on implementing the ls method in my program. I need to create a recursive method that will walk through my FileSystem.
Here is my FileSystem implementation right now:
import java.util.ArrayList;
public class FileSystem {
private Directory root;
private Directory wDir;
private ArrayList<File> files = new ArrayList<File>();
// Constructor
public FileSystem() {
}
// Constructor with parameters
public FileSystem(Directory root) {
this.root = root;
wDir = root;
files.add(root);
}
// Returns the FileSystem's files
public ArrayList<File> getFiles() {
return files;
}
// Returns the working directory
public Directory getWDir() {
return wDir;
}
// Sets the working directory
public void setWDir(Directory d) {
wDir = d;
}
// Returns the root file. This will always be / in our program
public File getRoot() {
return root;
}
public File getFile(File f, String name) {
if (f.isDirectory()) {
for (File c : ((Directory) f).getChildren()) {
if (c.getName().equals(name))
return c;
}
}
return null;
}
// Currently only used in cat method, getFile is better
File findFile(File f, String name) {
if (f.getName().equals(name))
return f;
File file = null;
if (f.isDirectory()) {
for (File c : ((Directory) f).getChildren()) {
file = findFile(c, name);
if (file != null)
break;
}
}
return file;
}
// Returns true if file is found
boolean isFile(String name) {
File file = null;
file = getFile(wDir, name);
if (file != null) {
return true;
}
return false;
}
// Creates Directory
public void mkdir(String path) {
files.add(new Directory(path));
int size = files.size();
// Sets the parent
files.get(size - 1).setParent(wDir);
// Sets the child
wDir.addChild(files.get(size - 1));
}
// Changes working directory
public void cd(String s) {
if (s.equals("..")) {
if (wDir != root) {
wDir = wDir.getParent();
}
} else if (s.equals("/")) {
wDir = root;
} else {
wDir = (Directory) getFile(wDir, s);
}
}
// Provides absolute filename
public void pwd() {
if (wDir == root) {
System.out.println("/");
} else {
System.out.println(wDir.getPath());
}
}
// Lists children of current working directory
public void ls() {
ArrayList<File> children = wDir.getChildren();
if (children != null) {
for (int i = 0; i < children.size(); i++) {
String childName = children.get(i).getName();
System.out.print(childName + " ");
}
}
}
// Lists children of file(s) inputted by user
public void ls(File f) {
String name = f.getName();
if (f instanceof TextFile) {
System.out.println(f.getPath());
} else {
ArrayList<File> children = ((Directory) f).getChildren();
if (children != null) {
for (int i = 0; i < children.size(); i++) {
String childName = children.get(i).getName();
System.out.print(childName + " ");
}
}
}
}
// Creates a TextFile or edit's TextFile's content if already exists in the
// tree
public void edit(String name, String content) {
files.add(new TextFile(name, content));
// Setting TextFile parent
files.get(files.size() - 1).setParent(wDir);
// Setting Parent's child
wDir.addChild(files.get(files.size() - 1));
}
// Prints the content of TextFile
public void cat(String name) {
File f = findFile(root, name);
System.out.println(((TextFile) f).getContent());
}
}
As an example of what it needs to do, let's say I have a tree like this:
/
/ \
a b
/ \
x c
/ \
y d
If the user were to enter: ls -r a, my main class would convert that String value using the getFile method, and I would enter that into my recursive function. It would then make use of either ls() or ls(File f), and my main program would output something like this:
a:
x
a/x:
y
a/x/y:
How should I go about creating this method?
Also I should note that I have a Main class, a File class, and a TextFile and Directory class that inherit File.
Any other information that is needed just let me know and I will update this post with it.
You could use something like this:
public void ls(File f) {
System.out.println(f); //or whatever is needed to print the filename
if(f instanceof Directory) {
List<File> fileList = ((Directory)f).getFiles();
//with Java 8
fileList.forEach(subFile -> System.out.println(subFile));
fileList.forEach(subFile -> ls(subFile));
//without Java 8
for(File subFile : fileList) {
System.out.println(subFile);
}
for(File subFile : fileList) {
ls(subFile);
}
System.out.println();
}
}
Basically the first loop is printing all the files in the current directory and the second loop is doing that for all the subdirectories. If the File is not a Directory only it's name is printed. Here I'm assuming that your Directory class has a getFiles() method that returns a List of all Files in the Directory
Here's my goal. I want to be able to pass a parent directory and a filename to a method that searches for that specific file in the directory and any sub-directories. Below is the code I have been working with but can not get it to do exactly what I want. It will find the file I specify but will not return anything.
private static File findFile(File dir, String name) {
String file = "";
File[] dirlist = dir.listFiles();
search:
for(int i = 0; i < dirlist.length; i++) {
if(dirlist[i].isDirectory()) {
findFile(dirlist[i], name);
} else if(dirlist[i].getName().matches(name)) {
file = dirlist[i].toString();
break search;
}
}
return new File(file);
}
I know that when the method finds a directory and calls itself it resets the file variable which is where I am storing the found file. So that is why I am getting a blank return. I am not sure how to accomplish this goal or if it's even possible.
The problem is that you're not returning anything from the recursive call:
if(dirlist[i].isDirectory()) {
findFile(dirlist[i], name); // <-- here
} else if(dirlist[i].getName().matches(name)) {
I would do the following:
private static File findFile(File dir, String name) {
File result = null; // no need to store result as String, you're returning File anyway
File[] dirlist = dir.listFiles();
for(int i = 0; i < dirlist.length; i++) {
if(dirlist[i].isDirectory()) {
result = findFile(dirlist[i], name);
if (result!=null) break; // recursive call found the file; terminate the loop
} else if(dirlist[i].getName().matches(name)) {
return dirlist[i]; // found the file; return it
}
}
return result; // will return null if we didn't find anything
}
In fact there are many solutions to do the job.
I assume that you want to find a unique file (or the first one) found in a directory tree that matches with the fileName.
It is a problem of optimization because there are multiple ways to explore solutions, and we want to find an acceptable solution.
1- Solution using FileUtils.listFiles
public static File searchFileWithFileUtils(final File file, final String fileName) {
File target = null;
if(file.isDirectory()) {
Collection<File> files = FileUtils.listFiles(file, null, true);
for (File currFile : files) {
if (currFile.isFile() && currFile.getName().equals(fileName)) {
target = currFile;
break;
}
}
}
return target;
}
The solution using the library FileUtils is not a suitable solution because the method FileUtils#listFiles() loads all the directory/folder tree (the cost is expensive !).
We don't need to know all the tree, we can choose a better algorithm which stops when the file is found.
2- Recursive Solution
public static File searchFileRecursive(final File file, final String search) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
File target = searchFileRecursive(f, search);
if(target != null) {
return target;
}
}
} else {
if (search.equals(file.getName())) {
return file;
}
}
return null;
}
The algorithm tests if the file exists inside any folder. If not, it tries subfolder of the current folder... recursively. If the file is not found in the current branch it tries another subfolder.
The exploration is deep, and for any file in a deepness of 1 the algorithm will explore the entirety of previous subfolders (previous branches are completely explored !).
This algorithm has the best performances for files in a deep location inside the first branch.
In the majority of cases, the file location is not deep, so let explore another algorithm that works in most of cases.
3- Fastest Solution : exploration by deepness
public static File searchFileByDeepness(final String directoryName, final String fileName) {
File target = null;
if(directoryName != null && fileName != null) {
File directory = new File(directoryName);
if(directory.isDirectory()) {
File file = new File(directoryName, fileName);
if(file.isFile()) {
target = file;
}
else {
List<File> subDirectories = getSubDirectories(directory);
do {
List<File> subSubDirectories = new ArrayList<File>();
for(File subDirectory : subDirectories) {
File fileInSubDirectory = new File(subDirectory, fileName);
if(fileInSubDirectory.isFile()) {
return fileInSubDirectory;
}
subSubDirectories.addAll(getSubDirectories(subDirectory));
}
subDirectories = subSubDirectories;
} while(subDirectories != null && ! subDirectories.isEmpty());
}
}
}
return target;
}
private static List<File> getSubDirectories(final File directory) {
File[] subDirectories = directory.listFiles(new FilenameFilter() {
#Override
public boolean accept(final File current, final String name) {
return new File(current, name).isDirectory();
}
});
return Arrays.asList(subDirectories);
}
For each deepness, the algorithm searches the file inside all folders of the same level. If the file is not found, it tries the next level (deepness++).
Due to the parallel exploration (symmetry), this solution is suitable in most of cases.
Comparison:
public class FileLocationFinder {
public static void main(final String[] args) {
String rootFolder = args[0];
String fileName = args[1];
long start = System.currentTimeMillis();
File target = searchFileWithFileUtils(new File(rootFolder), fileName);
System.out.println(target.getAbsolutePath());
System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
target = searchFileRecursive(new File(rootFolder), fileName);
System.out.println(target.getAbsolutePath());
System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
target = searchFileByDeepness(rootFolder, fileName);
System.out.println(target.getAbsolutePath());
System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms");
}
// Solution with FileUtils#listFiles
//--------------------------------------------
public static File searchFileWithFileUtils(final File file, final String fileName) {
File target = null;
if(file.isDirectory()) {
Collection<File> files = FileUtils.listFiles(file, null, true);
for (File currFile : files) {
if (currFile.isFile() && currFile.getName().equals(fileName)) {
target = currFile;
break;
}
}
}
return target;
}
// Recursive solution
//--------------------------------------------
public static File searchFileRecursive(final File file, final String search) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
File target = searchFileRecursive(f, search);
if(target != null) {
return target;
}
}
} else {
if (search.equals(file.getName())) {
return file;
}
}
return null;
}
// Fastest solution
//--------------------------------------------
public static File searchFileByDeepness(final String directoryName, final String fileName) {
File target = null;
if(directoryName != null && fileName != null) {
File directory = new File(directoryName);
if(directory.isDirectory()) {
File file = new File(directoryName, fileName);
if(file.isFile()) {
target = file;
}
else {
List<File> subDirectories = getSubDirectories(directory);
do {
List<File> subSubDirectories = new ArrayList<File>();
for(File subDirectory : subDirectories) {
File fileInSubDirectory = new File(subDirectory, fileName);
if(fileInSubDirectory.isFile()) {
return fileInSubDirectory;
}
subSubDirectories.addAll(getSubDirectories(subDirectory));
}
subDirectories = subSubDirectories;
} while(subDirectories != null && ! subDirectories.isEmpty());
}
}
}
return target;
}
private static List<File> getSubDirectories(final File directory) {
File[] subDirectories = directory.listFiles(new FilenameFilter() {
#Override
public boolean accept(final File current, final String name) {
return new File(current, name).isDirectory();
}
});
return Arrays.asList(subDirectories);
}
}
Result:
searchFileWithFileUtils: 20186ms | searchFileRecursive: 1134ms | searchFileByDeepness: 16ms
[EDIT]
You can also use Java 8 Files API to do this job :
public static File searchFileJava8(final String rootFolder, final String fileName) {
File target = null;
Path root = Paths.get(rootFolder);
try (Stream<Path> stream = Files.find(root, Integer.MAX_VALUE, (path, attr) ->
path.getFileName().toString().equals(fileName))) {
Optional<Path> path = stream.findFirst();
if(path.isPresent()) {
target = path.get().toFile();
}
}
catch (IOException e) {
}
return target;
}
But the execution time is not better (994ms).