Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The correct way to use FileVisitor in java

I am trying to step through an entire path and its single layer of sub directories. For each file, I need to read five data fields and output them to a delimited text file. I'm able to read from a single text file and validate my output on screen; after that I'm stuck. I cannot seem to to find the right parameters for FileVisit. Some specific questions are comments in my code posted below. And although I'm no nearly that far yes, I'd like to get some idea for writing to an output file, namely whether the place I wish to put it is the most logical one.

I've reviewed the https://stackoverflow.com/questions/9913/java-file-io-compendium and JavaDocs' info on the File Visitor
http://docs.oracle.com/javase/7/docs/api/index.html?java/nio/file/FileVisitor.html . However, I'm still not able to get FileVisitor working properly.

@Bohemian suggested changing interface to class which I've done.

 import java.nio.files.*;
 public class FileVisitor<T> 
 {
      Path startPath = Paths.get("\\CallGuidesTXT\\");
      Files.walkFileTree(startPath, new SimpleFileVisitor(startPath))
      \\             ^^^^^^    
      \\ errors out, <identifier expected>          
          { 
          @Override
          public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
              throws IOException
          {
              Files.list(file);
              return FileVisitResult.CONTINUE;
          }
        // do my file manipulations here, then write the delimited line 
        // of text to a CSV fle...is this the most appropriate place for that 
        // operation in this sample? 
      }  
 }

SSCCE below...but comments in the version above point to specific questions I'm having.

 import java.nio.*;
 import java.util.*;
 public class FileVisitor<T>
 {
    Path startPath = Paths.get("\\CallGuidesTXT\\");
 }
 Files.walkFileTree(startPath, new SimpleFileVisitor(startPath)  {
      @Override
      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
          throws IOException {
          Files.list(file);
          return FileVisitResult.CONTINUE;
      } 
 });
like image 832
dwwilson66 Avatar asked Apr 04 '12 15:04

dwwilson66


2 Answers

I'm a little rusty in Java but here's a rough idea of where I think you're going:

import java.nio.files.*;
public class MyDirectoryInspector extends Object 
{
    public static void main(String[] args) {
        Path startPath = Paths.get("\\CallGuidesTXT\\");
        Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() { 
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException
            {
                String firstLine = Files.newBufferedReader(file, Charset.defaultCharset()).readLine();
                System.out.println(firstLine);
                return FileVisitResult.CONTINUE;
            }
        }); // <- you were missing a terminating ");"
    }
}

That should walk through the directories and print the first line of each file to std out. I haven't touched Java since 1.6 so the JDK7 stuff is a little new to me too. I think you are getting confused as to what's a class and what's an interface. In my example we start with a basic class called MyDirectoryInspector to avoid confusion. It's enough to give us a program entry point, the main method where we start the inspection. The call to Files.walkFileTree takes 2 parameters, a start path and a file visitor which I have inlined. (I think the inlining can be confusing to some people if you're not used to this style.) This is a way of defining the actual class right in the place where you wish to use it. You could have also defined the SimpleFileVisitor separately and just instantiated it for your call as follows:

import java.nio.files.*;
public class MyDirectoryInspector extends Object 
{
    public static void main(String[] args) {
        Path startPath = Paths.get("\\CallGuidesTXT\\");
        Files.walkFileTree(startPath, new SimpleFileVisitor<Path>());
    }
}

public class SimpleFileVisitor<Path>()) { 
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException
            {
                String firstLine = Files.newBufferedReader(file, Charset.defaultCharset()).readLine();
                System.out.println(firstLine);
                return FileVisitResult.CONTINUE;
            }
        }

It may make more sense, if you are just getting started, to keep things all separated. Define your classes without inlineing, take it one step at a time and make sure you understand each piece in isolation. My 2nd example gives you 2 individual pieces, a custom file visitor that can be used to print the 1st line of each file it visits and a program that uses it with the JDK Files class. Now let's look at another approach that omits the syntax:

import java.nio.files.*;
public class MyDirectoryInspector extends Object 
{
    public static void main(String[] args) {
        Path startPath = Paths.get("\\CallGuidesTXT\\");
        Files.walkFileTree(startPath, new SimpleFileVisitor());
    }
}

public class SimpleFileVisitor()) { 
            @Override
            public FileVisitResult visitFile(Object file, BasicFileAttributes attrs)
                throws IOException
            {
                String firstLine = Files.newBufferedReader((Path)file, Charset.defaultCharset()).readLine();
                System.out.println(firstLine);
                return FileVisitResult.CONTINUE;
            }
        }

With the generics left off you have to declare file parameter as an Object type and cast it later when you choose to use it. In general, you don't want to replace an interface definition with a class definition or confuse the two as they are used for entirely different purposes.

like image 194
Cliff Avatar answered Nov 15 '22 15:11

Cliff


Now to answer your revised post...

You have a bracket in the wrong place:

Files.walkFileTree(startPath, new SimpleFileVisitor(startPath) { 
      @Override
      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
          throws IOException {
          Files.list(file);
          return FileVisitResult.CONTINUE;
      }
  });

I moved the bracket after new SimpleFileVisitor(startPath) to enclose the visitFile method. What you have here is an anonymous class - that's where you provide an implementation "on the fly".

like image 37
Bohemian Avatar answered Nov 15 '22 16:11

Bohemian