0

I am working on part of a proof of concept program in Java for an antivirus idea I had. Right now I'm still just kicking the idea around and the details aren't important, but I want the program I'm writing to get the file paths of every file within a certain range of each other(say 5 levels apart) in the directory and write them to a text file.

What I have right now(I will include my code below) can do this to a limited extent by checking if there are files in a given folder in the directory and writing their file paths to a text file, and then going down another level and doing it again. I have it set up to do 2 levels in the directory currently and it sort of works. But it only works if there is only one item in the given level of the directory. If there is one text file it will write that filepath to another text file and then terminate. But if there's a text file and folder, it ignores the text file and goes down to the next level of directory and records the file path of whatever text file it finds there. If there are two or more folders it will always choose one in particular over the other or others.

I realize now that it's doing that because I used the wrong conditional. I used if else and should have done something else, but I'm not sure which one I should have used. However I have to do it, I want to fix it so that it branches out with each level. For example, I start the program and give it starting directory C:/Users/"Name"/Desktop/test/. Test has 2 folders and a text file in it. Working the way I want it to, it would then record the file path of the .txt, go down a level into both folders, record any .txts or other files it found there, and then go down another level into each folder it found in those two folders, record what it found there, and so on until it finished the pre-determined number of levels to go through.

EDIT: To clarify confusion over what the problem is, I'll sum it up. I want the program to write the file paths of any files it finds in each level of the directory it goes through in another text file. It will do this, but only if there is one file in a given level of directory. If there is just one .txt for example, it will write the file path of that .txt to the other text file. But if there are multiple files in that level of directory(for example, two .txts) it will only write the file path of one of them and ignore the other. If there's a .txt and a folder, it ignores the .txt and enters the folder to go to the next level of directory. I want it to record all files in a given location and then branch into all the folders in that same location.

EDIT 2: I got the part of my code that gets the file path from this question( Read all files in a folder ) and the section that writes to my other text file from this one( How do I create a file and write to it in Java? )

EDIT 3: How can I edit my code to have recursion, as @horatius pointed out that I need?

EDIT 4: How can I edit my code so that it doesn't need a hard coded starting file path to work, and can instead detect the location of the executable .jar and use that as its starting directory?

Here is my code:

public class ScanFolder {

private static final int LEVELS = 5;

private static final String START_DIR = "C:/Users/Joe/Desktop/Test-Level1/";
private static final String REPORT_FILE = "C:/Users/Joe/Desktop/reports.txt";

public static void main(String[] args) throws IOException {
    try (PrintWriter writer = new PrintWriter(REPORT_FILE, "UTF-8");
            Stream<Path> pathStream = Files.walk(Paths.get(START_DIR), LEVELS)) {

         pathStream.filter(Files::isRegularFile).forEach(writer::println);

       } catch (Exception e) {
         e.printStackTrace(System.err);
       }
     }
   }

Thanks in advance

Community
  • 1
  • 1
  • 3
    Can this be edited any shorter? – Ross Jan 08 '16 at 00:52
  • I'm not sure I understand entirely, what exactly isn't working? – ricky3350 Jan 08 '16 at 00:55
  • You need to use recursion in your program. Your program will not work as it is written currently. – horatius Jan 08 '16 at 01:26
  • @horatius How can I add that? I'm really not experienced with java. I know what I'm doing to some extent but I'm by no means an expert. Many of the more complicated things I've made have been made with a lot of help from the internet, particularly this site. And would adding recursion be all I needed to do? – Adam Cochrane Jan 08 '16 at 01:32
  • Recursion is the concept of a method calling itself over and over again until a certain condition happens that breaks the loop. You cannot solve your problem without recursion. Here's an example of recursion. http://www.danzig.jct.ac.il/java_class/recursion.html – horatius Jan 08 '16 at 01:38

1 Answers1

1

If you are using Files.walk(...) it does all the recursion for you.

Opening and writing to the PrintWriter will truncate your output file each time it is opened/written to, leaving just the last filename written.

I think something like the below is what you are after. As you progress, rather than writing to a file, you may want to put the found Path objects into an ArrayList<Path> or similar for easier later processing, but not clear from your question what requirements you have here.

public class Walk
{
  public static void main(String[] args) throws IOException {
    try (PrintWriter writer = new PrintWriter("C:/Users/Joe/Desktop/reports.txt", "UTF-8")) {
      Files.walk(Paths.get("C:/Users/Joe/Desktop/test")).forEach(filePath -> {
        if (Files.isRegularFile(filePath)) {
          writer.println(filePath);
        }
      });
    }
  }
}

Here is an improved example that you can use to limit depth. It also deals with properly closing the Stream returned by Files.walk(...) that the previous example did not, and is a little more streams/lambda idiomatic:

public class Walk
{
  // Can use Integer.MAX_VALUE for all
  private static final int LEVELS = 2;

  private static final String START_DIR = "C:/Users/Joe/Desktop/test";
  private static final String REPORT_FILE = "C:/Users/Joe/Desktop/reports.txt";

  public static void main(String[] args) {
    try (PrintWriter writer = new PrintWriter(REPORT_FILE, "UTF-8");
         Stream<Path> pathStream = Files.walk(Paths.get(START_DIR), LEVELS)) {

      pathStream.filter(Files::isRegularFile).forEach(writer::println);

    } catch (Exception e) {
      e.printStackTrace(System.err);
    }
  }
}
clstrfsck
  • 14,715
  • 4
  • 44
  • 59
  • A few questions about this, and some clarification of the requirements of the program. Firstly, if I'm correct, I'm fairly sure it needs to write to a file because a second part of this proof of concept thingamajig I'm working on will be another program that takes the information output in the file and uses it for something. Secondly, a question. Do I not need the `else` statement if I change my code to what you posted above? – Adam Cochrane Jan 08 '16 at 02:00
  • Ok, so a file sounds like a convenient way to do things if you are doing this with multiple applications. Secondly, I can't see why you would need the nested `Files.walk(...)` in your sample code. The sample code you have is equivalent to `Files.walk("C:/Users/Joe/Desktop", ...)` due to the use of the `".."` at the end of the path. Assuming you want to scan the `"C:/Users/Joe/Desktop/test"` directory and subdirectories, this not only isn't required, it will give you the wrong results. – clstrfsck Jan 08 '16 at 02:08
  • I hadn't realized that, thanks! I think I mistakenly thought that was a command to go down, probably because I was in a rush. I thought I needed it to go down to the next subdirectory, and I think I thought that because I misunderstood part of my code. Thanks for correcting me – Adam Cochrane Jan 08 '16 at 02:27
  • Just one more question, then I'll have everything I need to know. Is there a way, possibly through a loop and a counter variable or something of that nature, that I can cut if off after a certain number of levels of subdirectories? I intend to run this in sequence with similar programs that will take over from each other after a pre-determined number of levels and I don't want them to overlap – Adam Cochrane Jan 08 '16 at 02:37
  • Yes, there is an overload of `Files.walk(...)` that will let you limit depth. Will post example. – clstrfsck Jan 08 '16 at 06:17
  • When I run that, I get a string of errors like this one: `java.nio.file.NoSuchFileException: C:\Users\Joe\Desktop\test at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)` – Adam Cochrane Jan 08 '16 at 13:58