6

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;
      } 
 });
Community
  • 1
  • 1
dwwilson66
  • 6,806
  • 27
  • 72
  • 117

3 Answers3

9

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.

jrwren
  • 17,465
  • 8
  • 35
  • 56
Cliff
  • 10,586
  • 7
  • 61
  • 102
  • Wow...thank you, @Cliff. This helps a LOT. THis is my first time using interfaces, and I'm not really clear about the rules surrounding HOW to use them appropriately. One question that's not clear: When you reference `` is that an explicitly coded path in angle brackets? a variable name that represents the path (in this case, `startPath` or is it actually the word `path`. If the latter, are we using the `Files.walkFileTree...` statment to pass `path` to the SimpleFileVisitor method? Just trying to understand what that means and how the value of it moves through various classes/methods. – dwwilson66 Apr 04 '12 at 16:52
  • 1
    The in angle brackets is Java generics syntax. It's used to qualify an instance for a specific type. In other words, everywhere in the Visitor template where you see a generic "T" gets replaced with that type. While Generics means well, it is a truly complicated beast. Let me do a revision without the generics to make it a little simpler. – Cliff Apr 04 '12 at 21:36
  • Thanks, @Cliff. Now I even understand the code! :) I'll wait to delve into generics until I'm less a java newbie...thanks again. – dwwilson66 Apr 05 '12 at 13:56
6

Java interface can not have any implementations (ie code) - only method signatures.

Try changing interface to class:

public class FileVisitor<T> {
    ...
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • @ Bohemian excellent tip. First time seeing interface atually in code... but more errors...revising my initial post right now. – dwwilson66 Apr 04 '12 at 15:59
2

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".

Bohemian
  • 412,405
  • 93
  • 575
  • 722