menu sluiten
Contact

Antwerpen
Veldkant 33B, 2550 Kontich
België +32 (0)3 444 11 08

Breda
Rithmeesterpark 50-A1, 4838GZ Breda
Nederland +32 (0)3 444 11 08

info@jstack.eu

28 February 2016

Lambda in the files API

In this blog, I would like to show you how Lambdas changed the way we write our code in the File API. First I will demonstrate how you can walk down a path, find and filter files, depending on their name, access time, modified time, etc…
Second I’ll show you some examples of how to read from a file, and perform some action on the lines, or characters you read. In the examples that follow, we’ll use the following directory structure :
/u2/dir1
– file1.txt
– file2.txt
– file3.txt
/u2/dir2
– file4.txt
– file5.txt
– file6.txt
/u2/dir3 (containing no files)

Files.list

The list method returns a list of files in the path, and is not recursive.
The signature of the method is :

Stream list (Path dir) throws IOException

1
2
Path path = Paths.get("/u02");
Files.list(path).map(p -> p.getFileName()).forEach(a -> System.out.println(a));

Results in following output :
>dir1
>dir2
>dir3

You can see 3 steps are used here :

  • The list returns a stream of Path objects.
  • The map method, takes a Function, meaning give me something and all give something back, in this case, Path goes in and the filename of the path comes out
  • Foreach method takes a Consumer, meaning, give me something and I’ll do something with it, in this case filename is given, and is printed out.

Files.walk

Files class contains 2 method’s to walk down a path :

static Stream walk (Path path, FileVisitOption… options)
static Stream walk (Path path, int maxDepth, FileVisitOption… options)

where FileVisitOption can only have value FOLLOW_LINKS, meaning that symbolic links are also followed when walking down a path.
Here’s an example that illustrate this method:

1
2
Path path = Paths.get("/u02");
Files.walk(path,2).map(p -> p.getFileName()+" with uri  "+p.toUri()).forEach(System.out::println);

Results in the following output :
>u02 with uri file:///u02/
>dir1 with uri file:///u02/dir1/
>file1.txt with uri file:///u02/dir1/file1.txt
>file2.txt with uri file:///u02/dir1/file2.txt
>file3.txt with uri file:///u02/dir1/file3.txt
>dir2 with uri file:///u02/dir2/
>file4.txt with uri file:///u02/dir2/file4.txt
>file5.txt with uri file:///u02/dir2/file5.txt
>file6.txt with uri file:///u02/dir2/file6.txt
>dir3 with uri file:///u02/dir3/

Again 3 steps are used here :

  • The walk method returns a stream of Path objects. The ‘2’ indicates we go two levels deep.
  • The map method, takes a Function, meaning “give me something and all give something back”, where in this case, Path is the input and the filename of the path + “ with uri “ + uri of the path comes out
  • Foreach method takes a Consumer, meaning, “give me something and I’ll do something with it”, in this case filename is given, and is printed out.

Files.find

The signature of find looks as follows :

Stream find (Path start, int maxDepth, BiPredicate matcher, FileVisitOption… options) throws IOException

The find method enables us to find a file, starting from a path, going x-levels deep. A BiPredicate interface will determine which files are returned and which not. The BiPredicate’s abstract method has the following signature :
boolean test(T t, U u)
If the file complies with the test, it will be returned, otherwise not. So let’s look at an example:

1
2
3
4
Path start = new File("/u02").toPath();
BiPredicate topicDirectoriesMatcher = (path, basicFileAttributes) -> basicFileAttributes.isRegularFile() && path.toString().contains("1");
Stream pathStream = Files.find(start, 2, topicDirectoriesMatcher);
pathStream.sorted().forEach(System.out::println);

results in :
>/u02/dir1/file1.txt
>/u02/dir1/file2.txt
>/u02/dir1/file3.tx
t
The key here is the BiPredicate object ‘topicDirectoriesMatcher’. Path and basicFileAttributes are the parameters of the Test method, and the implementation is :
basicFileAttributes.isRegularFile() && path.toString().contains(“1”);
Meaning : only return me the regular files, not the directories, and the path should contain the character ‘1’. If we would replace .isRegularFile() by isDirectory() we would only get the result :
>/u02/dir1

Files.lines

The lines method returns the lines of a file as a Stream.
Following signatures are possible :

static Stream lines (Path path)
static Stream lines (Path path, Charset cs)

Let’s suppose that the file /u2/dir2/file4.txt contains the following lines:
>This is the first line.
>This is the second line.
>This is the third line.
>This is the last line.

The following will filter the lines that have ‘last’ in it:

1
2
Path pathFile = new File("/u02/dir2/file4.txt").toPath();
Files.lines(pathFile).filter(l -> l.contains("last")).forEach(System.out::println);

You can see 3 steps happening here :

  • The lines method converts the file to a Stream of lines.
  • The filter method takes a Predicate that indicates which line should be filtered out.
  • Then, every filtered out line is printed with the foreach method.

So it will print :
>This is the last line.

Now we can also convert a file to a List of Strings containing the lines of the file.

1
2
3
Path pathFile = new File("/u02/dir2/file4.txt").toPath(); 
List list = Files.lines(pathFile).collect(Collectors.toList());
list.stream().forEach(System.out::println);

The lines method returns every line of the file as a single element in a stream. The collect method ‘collects’ these elements and puts them in a List.Then we print them producing the following result :
>This is the first line.
>This is the second line.
>This is the third line.
>This is the last line.

With this blog I have shown you how Lambdas can help you when handling directories and files.
Hope you enjoyed it and let me know what you think!

Meer weten?

Neem contact op met Rick. Hij denkt graag met u mee in een persoonlijk gesprek.

info@jstack.eu +31 (0)85-888 33 31

Interessant? Deel dit artikel met een vriend(in) of collega!

Vragen over dit onderwerp?

Onze experts denken graag met u mee


    Gerelateerde berichten