6.031
6.031 — Software Construction
Spring 2021

Code Examples for Reading 26

Download

You can also download a ZIP file containing this code.

Seems to be necessary to have a triple-backtick block at the start of this page,
otherwise all the pre/code tags below aren't syntax highlighted.
So create a hidden one.

Words1.java

package words;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Words example: familiar Java implementation.
 */
public class Words1 {
    
    /**
     * Find all the files in the filesystem subtree rooted at folder.
     * @param folder root of subtree, requires folder.isDirectory() == true
     * @return list of all ordinary files (not folders) that have folder as
     *         their ancestor
     */
    public static List<File> allFilesIn(File folder) {
        List<File> files = new ArrayList<File>();
        for (File f: folder.listFiles()) {
            if (f.isDirectory()) {
                files.addAll(allFilesIn(f));
            } else if (f.isFile()) {
                files.add(f);
            }
        }
        return files;
    }
    
    /**
     * Filter a list of files to those that end with suffix.
     * @param files list of files (all non-null)
     * @param suffix string to test
     * @return a new list consisting of only those files whose names end with
     *         suffix
     */
    public static List<File> onlyFilesWithSuffix(List<File> files, String suffix) {
        List<File> result = new ArrayList<File>();
        for (File f : files) {
            if (f.getName().endsWith(suffix)) {
                result.add(f);
            }
        }
        return result;
    }
    
    /**
     * Find all the non-word-character-separated words in files.
     * @param files list of files (all non-null)
     * @return list of words from all the files
     * @throws IOException if an error occurs reading a file
     */
    public static List<String> getWords(List<File> files) throws IOException {
        List<String> words = new ArrayList<String>();
        for (File f : files) {
            BufferedReader reader = new BufferedReader(new FileReader(f));
            String line;
            for (line = reader.readLine(); line != null; line = reader.readLine()) {
                // split on \W (non-word characters, like spaces and punctuation)
                for (String word : line.split("\\W+")) {
                    // split can return empty strings, so omit them
                    if ( ! word.isEmpty()) {
                        words.add(word);
                    }
                }
            }
            reader.close();
        }
        return words;
    }
    
    /**
     * Print the words in Java files in the project.
     * @param args unused
     * @throws IOException if error while reading files or folders
     */
    public static void main(String[] args) throws IOException {
        List<File> allFiles = allFilesIn(new File("."));
        List<File> javaFiles = onlyFilesWithSuffix(allFiles, ".java");
        List<String> words = getWords(javaFiles);
        for (String s : words) { System.out.println(s); }
    }
}

Words2.java

package words;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * Words example: Java implementation with map/filter/reduce.
 */
public class Words2 {
    
    /**
     * Find all files in the filesystem subtree rooted at folder.
     * @param folder root of subtree, requires folder.isDirectory() == true
     * @return stream of all ordinary files (not folders) that have folder as
     *         their ancestor
     */
    static Stream<File> allFilesIn(File folder) {
        File[] children = folder.listFiles();
        Stream<File> descendants = Arrays.stream(children)
                                         .filter(File::isDirectory)
                                         .flatMap(Words2::allFilesIn);
        return Stream.concat(descendants,
                             Arrays.stream(children).filter(File::isFile));
    }
    
    /**
     * Make a filename suffix testing predicate.
     * @param suffix string to test
     * @return a predicate that returns true iff the filename ends with suffix.
     */
    static Predicate<File> endsWith(String suffix) {
        return f -> f.getPath().endsWith(suffix);
    }
    
    /**
     * Print the words in Java files in the project.
     * @param args unused
     * @throws IOException if error while reading files or folders
     */
    public static void main(String[] args) throws IOException {
        Stream<File> files = allFilesIn(new File("."))
                              .filter(endsWith(".java"));
        Stream<Path> paths = files.map(File::toPath);
        Stream<List<String>> fileContents = paths.map(path -> {
            try {
                return Files.readAllLines(path);
            } catch (IOException ioe) {
                throw new UncheckedIOException(ioe);
            }
        });
        Stream<String> lines = fileContents.flatMap(List::stream);
        Stream<String> words = lines.flatMap(line -> Arrays.stream(line.split("\\W+"))
                                                     .filter(s -> s.length() > 0));
        words.forEach(System.out::println);
    }
}