I'm writing a quick Java recursion method that, given a root folder and filename, searches your files for said file name.
import Java.io.File;
public static String searchForFile(File currentFolder, String filename)
{
try
{
File[] path = currentFolder.listFiles();
for (int i = 0; i < path.length; i++)
{
if (path[i].isDirectory())
{
System.out.println("Directory: " + path[i].toString());
searchForFile(path[i], filename);
}
else
{
System.out.println("File: " + path[i].toString());
if(path[i].getName().equals(filename))
{
System.out.println("Your file has been found!";
return path[i].toString();
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null; // Omitting this line yields compiling errors, not sure why?
}
public static void main(String[] args)
{
System.out.println("Hello, enter the root folder and file name.");
String rootFolder = "Desktop";
String fileName = "Hello.txt";
File f = new File("C:\\Users\\Me\\" + rootFolder);
searchForFile(f, fileName);
}
The program itself technically works, however searchForFile() keeps iterating even after the requested file is found. For example, I'd get an output such as:
File: C:\Users\Me\Desktop\My Stuff\NotHello.txt
**File: C:\Users\Me\Desktop\My Stuff\Hello.txt**
Your file has been found!
File: C:\Users\Me\Desktop\My Stuff\AlsoNotHello.txt
File: C:\Users\Me\Desktop\My Stuff\StillNotHello.txt
File: C:\Users\Me\Desktop\My Stuff\WhyIsThisMethodStillRunning.txt
I've been scratching my head at this for awhile now. I thought return always exits the method, so why does the recursion continue even after it returns a value? I haven't found any similar questions asked, so any help would be much appreciated!
(Also, how could I edit the method so that it returns a blank "" string if the requested file is not found?)
You are returning from the innermost call, when you've found the file. But when you are scanning a directory, you are not using the return value.
Change this:
searchForFile(path[i], filename);
to:
String result = searchForFile(path[i], filename);
if (result != null) {
return result;
}
The return null; in the bottom of your method is there because all methods needs to return a value. No matter if the file is found or not. If the file is not found within the current directory (or one of its subdirectories), you can return null; to indicate that it wasn't found.
Side suggestion: Use Optional in Java 8 instead of null.
Related
This has been identified as a possible duplicate of another question on here, it is not. I know how to delete the symbolic link and the files. I am trying to keep the file associated with the symbolic link but delete everything else.
My Problem: Delete all files in directory older than 7 days except files associated with symbolic link.
Issue: Symbolic link successfully deleted but remaining older files are not removed.
Details: I am trying to write a simple Java program to delete all of the files and subfolders in a directory older than 7 days which is working but there is one issue. If there is a symbolic link then I need to delete just the link and keep the file that it links to. Other than that case, everything else gets deleted. I know that I am very close... if you have any suggestions let me know please. At the moment I am able to have it delete the symbolic link but the other old files are not being deleted when they should. This could be a simple logic error or maybe I am approaching the problem the wrong way. Thanks in advance!
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class delcache {
public static void main(String[] args) throws IOException
{
String path1="/home/test/cachetest";
recursiveDelete(7, path1);
}
public static void recursiveDelete(int days, String dirPath) throws IOException {
long cutOff = System.currentTimeMillis() - (days * 24 * 60 * 60 * 1000);
Files.list(Paths.get(dirPath))
.forEach(path -> {
if (Files.isDirectory(path)) {
try {
recursiveDelete(days, path.toString());
} catch (IOException e) {
// log
}
} else {
try {
if (Files.getLastModifiedTime(path).to(TimeUnit.MILLISECONDS) < cutOff) {
String pathsave = null;
if(Files.isSymbolicLink(path)) {
pathsave = path.toRealPath().toString();
System.out.println("pathsave: " + pathsave);
System.out.println("delete symlink: " + path);
Files.delete(path);
}
if(!(Files.isSymbolicLink(path))) {
System.out.println("pathsave: " + pathsave);
if(!(path.toString().equals(pathsave))) {
System.out.println("not equal so delete file: " + path);
Files.delete(path);
}
}
//Files.delete(path);
}
} catch (IOException ex) {
// log
}
}
});
}
}
Your logic is flawed, String pathsave persists only for the current loop of the specific path. when the loop gets to actual file the pathsave is always null.
if you want to save the symbolic links path you need to have a list of paths which is outside the function. even then it won't work because you have no guarantee for any order, you may first reach to the symbolic link or first reach the file.
So as I understand it you must first iterate the folder looking for all the symbolic links, save them into global List which is accessible to the method, and then run and delete the files.
side note: notice that if you delete the symboic links, the next time you would run this function, the same files which previously had symlinks will now be deleted
public static void main(String[] args) throws IOException
{
String path1="/home/test/cachetest";
List<Path> symlinks = getAllSymLinks(path1);
recursiveDelete(7, path1, symlinks);
}
public static List<Path> getAllSymLinks(String dirPath) throws IOException {
List<Path> paths = new ArrayList<>();
Files.list(Paths.get(dirPath))
.forEach(path -> {
if (Files.isDirectory(path)) {
try {
paths.addAll(recursiveDelete(days, path.toString()));
} catch (IOException e) {
// log
}
} else {
try {
if(Files.isSymbolicLink(path)) {
paths.add(path.toRealPath());
}
} catch (IOException ex) {
// log
}
}
});
return paths;
}
public static void recursiveDelete(int days, String dirPath, List<path> symlinks) throws IOException {
long cutOff = System.currentTimeMillis() - (days * 24 * 60 * 60 * 1000);
Files.list(Paths.get(dirPath))
.forEach(path -> {
if (Files.isDirectory(path)) {
try {
recursiveDelete(days, path.toString(), symlinks);
} catch (IOException e) {
// log
}
}
else {
try {
if (Files.getLastModifiedTime(path).to(TimeUnit.MILLISECONDS) < cutOff &&
!Files.isSymbolicLink(path) &&
!symlinks.contains(path))
{
Files.delete(path);
}
} catch (IOException ex) {
// log
}
}
});
You could use this method:
Use Process process = Runtime.getRuntime.exec("ls -l") to list all contents of the directory.
Read the InputStream of process line by line.
If the first character is 'd', the file in the line is a directory. Recurse.
If the first character is '-', delete.
If the first character is 'l', it is a symbolic link. Skip the file.
You can get the filename from the same line. For example, if the line is in a variable 'str', the the filename is str.split("\\s+")[8]
You can additionally use the filenames for any other checks you require.
EDIT
Untested method using grep:
String getLinkedFile(file) {
// Input: A Symbolic link file
// Output: Name of file pointed to by the symlink
Process p = Runtime.getRuntime.exec("ls -l | grep -e \"->\"");
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = reader.readLine()) != null) {
String []tokens = line.split("\\s+");
String linkFile = tokens[8];
if(linkFile.equals(file.getName()))
return tokens[10];
}
return null;
}
You may need to modify this function based on file paths.
I am trying to output a list of files within a directory recursively (not including the name of the name of the directory that I am starting with (just the contents of it and all files recursing down the tree after that)
here is what I have at the minute. It Might have errors here and there, but the idea is that it will print all the names of every file in the tree recursively. My problem is that I don't want it to print the name of the directory in which they live.
I think my problem is that I am using System.out.println at the start of the recursive method, which means it gets used every time. Which is desirable behavior for every directory BELOW the first one. Its an annoying little problem that I could use some help on. Thanks in advance.
public static void listFiles(String path)
{
File basedir = new File(path);
System.out.println(path.getName());
try
{
File[] files = basedir.listFiles();
for (File file : files)
{
// If Dealing with a directory, call recursively to the function
if (file.isDirectory())
{
listFiles(file.getPath());
}
else
{
System.out.println(file.getName());
}
}
}
catch(IOException ex)
{
System.out.println(ex);
}
}
public static void listFiles(String path, boolean firstCall)
{
File basedir = new File(path);
if(!firstCall)
{
System.out.println(path.getName());
}
try
{
File[] files = basedir.listFiles();
for (File file : files)
{
// If Dealing with a directory, call recursively to the function
if (file.isDirectory())
{
listFiles(file.getPath(), false); //false here because it is not the first call
}
else
{
System.out.println(file.getName());
}
}
}
catch(IOException ex)
{
System.out.println(ex);
}
}
Add a boolean parameter that specifies if it is the first call. When you call the method pass true to the parameter. Also path.getName() is not valid String doesn't have a function getName() maybe you meant basedir.getName()...also remove try catch block IOException can't occur there.
This should be easy. This question (Java - Search for files in a directory) seemed to take me 99% of the way to where I needed to be, but that missing 1% is being a real SOB.
I need to find a specific file in a directory and return the full path and filename as a string. If there's more than one matching file, that's fine, I just need the first match.
The code below works inasmuch as it will recursively traverse a directory structure and return all matches -- I can see it happening when I put sysouts into the various parts of the method -- but I can't for the life of me make it stop when it finds a match and return me the value of the match.
I've tried substituting the FOR statement with a WHILE statement controlled by the the value of the foundfile variable as well as half a dozen other approaches but they all come down to the same end; when I find the matching file and set it to the foundfile variable in the "else if" clause, the for loop just keeps on iterating and overwrites the value of the foundfile variable with the "" value on the next loop. I would have thought that calling the setOutput method from within the "if else" clause would have set the value successfully until the list array was empty, but evidently not.
Clearly there is something about recursion and the persistence of parameters that I'm fundamentally misunderstanding. Can anyone illuminate?
package app;
import java.io.*;
import java.util.*;
class FindFile {
public String setOutput(String name, File file, String fileloc) {
String foundfile = fileloc;
File[] list = file.listFiles();
if (list != null)
for (File fil : list) {
if (fil.isDirectory()) {
setOutput(name, fil, foundfile);
} else if (fil.getName().contains(name)) {
foundfile = (fil.getParentFile() + "\\" + fil.getName());
setOutput(name, fil, foundfile);
}
}
return foundfile;
}
public static void main(String[] args) {
FindFile ff = new FindFile();
String thisstring = ff.setOutput(".jar", new File("/Temp/df384b41-198d-4fee-8704-70952d28cbde"), "");
System.out.println("output: " + thisstring);
}
}
You can return the file path when you find it. No need to check the other files if you are only interested in the first match:
Here is an example (not tested):
public String setOutput(String name, File file) {
File[] list = file.listFiles();
if (list != null) {
for (File fil : list) {
String path = null;
if (fil.isDirectory()) {
path = setOutput(name, fil);
if (path != null) {
return path;
}
} else if (fil.getName().contains(name)) {
path =fil.getAbsolutePath();
if (path != null) {
return path;
}
}
}
}
return null; // nothing found
}
I cannot for the life of me figure out what i am missing here. I am getting an error with the else block. I have tried all variation of brackets but cannot seem to get it to work. I need some fresh eyes to spot my mistake! Any ideas?
public static void makeCopies (File srcFolder, File destDirectory)throws Exception
{
if (srcFolder.isDirectory())
{
destDirectory.mkdir();
System.out.println("Directory copied from" +srcFolder + " to " +destDirectory);
}
String files[] = srcFolder.list();
for (String file : files)
{
File srcFile = new File(srcFolder, file);
File destFile = new File(destDirectory, file);
//recursive copy
makeCopies(srcFolder, destDirectory);
}
else {
FileInputStream sourceStream = new FileInputStream(srcFolder);
FileOutputStream destStream = new FileOutputStream(destDirectory);
// use an integer to transfer data between files
int transfer;
// tell the user what is happening
System.out.println("begining file copy:");
System.out.println("\tcopying " + srcFolder);
System.out.println("\tto " + destDirectory);
// read a byte, checking for end of file (-1 is returned by read at EOF)
while ((transfer = sourceStream.read()) != -1) {
// write a byte
destStream.write(transfer);
} // end while
// close file streams
sourceStream.close();
destStream.close();
System.out.println("File copy complete.");
}
you have all this chunk of code between the end of your if block and else block:
if
{
...
}
String files[] = srcFolder.list();
for (String file : files)
{
File srcFile = new File(srcFolder, file);
File destFile = new File(destDirectory, file);
//recursive copy
makeCopies(srcFolder, destDirectory);
}
else
{
...
}
this is not the right structure for if statement in java (or any C-like language for that matter).
it has to be this way:
if(condition) {
....
} else {
....
}
You're not closing your braces on the else block nor on the method block.
Your else isn't attached to any if. Assuming it's supposed to be the else for the if at the top of the method, just move the else { line up, immediately after you end your if block.
if (srcFolder.isDirectory())
{
destDirectory.mkdir();
System.out.println("Directory copied from" +srcFolder + " to " +destDirectory);
}
else { // Move it here
String files[] = srcFolder.list();
Or, if the code starting with String files[] = srcFolder.list(); (immediately after the current end if the if block) is meant to be part of the if, then move the closing if } down to the else.
Your for loop is outside of your if block, so the else you've written is seemingly part of the for loop instead. You're also missing a closing } for the else block.
What you have now:
if(){
}
for(){
}
else{
// this isn't attached to the if block...
}
what you should have:
if(){
// for loop can go here
}else{
// or here
}
This question already has answers here:
How to open a file with the default associated program
(4 answers)
Closed 9 years ago.
I have a files list. Lets say it looks:
String[] lst = new String[] {
"C:\\Folder\\file.txt",
"C:\\Another folder\\another file.pdf"
};
I need some method to open these files with default program for them, lets say "file.txt" with Notepad, "another file.pdf" with AdobeReader and so on.
Does anyone knows how?
There is a method to do this:
java.awt.Desktop.getDesktop().open(file);
JavaDoc:
Launches the associated application to open the file.
If the specified file is a directory, the file manager of the current platform is launched to open it.
The Desktop class allows a Java application to launch associated applications registered on the native desktop to handle a URI or a file.
If you are using J2SE 1.4 o Java SE 5, the best option is:
for(int i = 0; i < lst.length; i++) {
String path = lst[i];
if (path.indexOf(' ') > 0) {
// Path with spaces
Runtime.getRuntime().exec("explorer \"" + lst[i] + "\"");
} else {
// Path without spaces
Runtime.getRuntime().exec("explorer " + lst[i]);
}
}
Just make sure the file is in the right location, and this should work fine.
try
{
File dir = new File(System.getenv("APPDATA"), "data");
if (!dir.exists()) dir.mkdirs();
File file = new File(dir"file.txt");
if (!file.exists()) System.out.println("File doesn't exist");
else Desktop.getDesktop().open(file);
} catch (Exception e)
{
e.printStackTrace();
}
I didn't know you have a String array now. So, this one uses regex to process the file list in the format you specified before. Ignore if not required.
If the file list is huge and you would prefer that the files open one by one cmd works great. If you want them to open all at once use explorer. Works only on Windows but then on almost all JVM versions. So, there's a trade-off to consider here.
public class FilesOpenWith {
static String listOfFiles = "{\"C:\\Setup.log\", \"C:\\Users\\XYZ\\Documents\\Downloads\\A B C.pdf\"}";
public static void main(String[] args) {
if (args != null && args.length == 1) {
if (args[0].matches("{\"[^\"]+\"(,\\s?\"[^\"]+\")*}")) {
listOfFiles = args[0];
} else {
usage();
return;
}
}
openFiles();
}
private static void openFiles() {
Matcher m = Pattern.compile("\"([^\"]+)\"").matcher(listOfFiles);
while (m.find()) {
try {
Runtime.getRuntime().exec("cmd /c \"" + m.group(1) + "\"");
// Runtime.getRuntime().exec("explorer \"" + m.group(1) + "\"");
} catch (IOException e) {
System.out.println("Bad Input: " + e.getMessage());
e.printStackTrace(System.err);
}
}
}
private static void usage() {
System.out.println("Input filelist format = {\"file1\", \"file2\", ...}");
}
}