Search code examples
javafileio

File Tree. Visualization


I beg you for help. This is my task.

File Tree Description

Build a String representation of directory hierarchy under a given path

Details

Implement tree method in FileTreeImpl class.

Input parameter is a path.

If a given path does not exist, return an empty Optional.

If a given path refers to a file, return a String with its name and size like this:

some-file.txt 128 bytes 

IF a given path refers to a directory, return a String with its name, total size and its full hierarchy:

some-dir 100 bytes
├─ some-inner-dir 50 bytes
│  ├─ some-file.txt 20 bytes    
│  └─ some-other-file.txt 30 bytes
└─ some-one-more-file.txt 50 bytes

Use pseudo graphic symbols to format output. Compute directory size as a sum of all its contents.

Sort content in following way: directories go first, directories and files are sorted in lexicographic order (case-insensitive).

This is my implementation.

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class FileTreeImpl implements FileTree {

    @Override
    public Optional<String> tree(Path path) {
        File file = new File(String.valueOf(path));
        if ( !file.exists()) return Optional.empty();
        if ( file.isFile()) {
            return Optional.of(file.getName() + " " + file.length() + " bytes");
        }
        if (file.isDirectory()) {
            return Optional.of(directoryTree(file, 0, false));
        }
        return Optional.empty();
    }
    private String directoryTree(File folder, int depth, boolean lastFolder) {
        String directory = folder.getName() + " " + folderSize(folder);
        if (depth != 0) directory = ((!lastFolder) ? "├─ " : "└─ ") + directory;
        File[] files = folder.listFiles();
        int count = files.length;
        files = sortFiles(files);
        for (int i = 0; i < count; i++) {
            directory += "\n";
            if (depth != 0) directory += "│  ";
            if (files[i].isFile()) {
                directory += (lastFolder ? "   " : "│  ") + (i + 1 == count ? "└" : "├") + "─ " +
                        files[i].getName() + " " + files[i].length() + " bytes";
            } else {
                directory += directoryTree(files[i], depth + 1, i + 1 == numberOfFolders(files));
            }
        }
        System.out.println(directory);
        return directory;
    }
    private long getFolderSize(File folder) {
        long size = 0;
        File[] files = folder.listFiles();

        int count = files.length;

        for (int i = 0; i < count; i++) {
            if (files[i].isFile()) {
                size += files[i].length();
            } else {
                size += getFolderSize(files[i]);
            }
        }
        return size;
    }
    private String folderSize(File folder) {
        return getFolderSize(folder) + " bytes";
    }
    private File[] sortFiles(File[] folder) {
      
        Arrays.sort(folder);
        List<File> sorted = new ArrayList<>();
    
        for (int i = 0; i < folder.length; i++) {
            if (folder[i].isDirectory()) sorted.add(folder[i]);
        }
        
        for (int i = 0; i < folder.length; i++) {
            if (folder[i].isFile()) sorted.add(folder[i]);
        }
        return sorted.toArray(new File[sorted.size()]);
    }
    private int numberOfFolders(File[] files) {
        int folders = 0;
        for (File file : files)
            if (file.isDirectory()) folders++;
        return folders;
    }
}

code of tests you can see here: https://github.com/npogoncuk/file-tree

expected and actual:

https://i.sstatic.net/N8ftB.png

Please, help me change the code or, please, give me a piece of advice about new algorithm.


Solution

  • Here is the solution.

    import java.io.File;
    import java.nio.file.Path;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Optional;
    
    public class FileTreeImpl implements FileTree {
    
        @Override
        public Optional<String> tree(Path path) {
            File file = new File(String.valueOf(path));
            if ( !file.exists()) return Optional.empty();
            if ( file.isFile()) {
                return Optional.of(file.getName() + " " + file.length() + " bytes");
            }
            if (file.isDirectory()) {
               
                return Optional.of(directoryTree(file, new ArrayList<>()));
            }
            return Optional.empty();
        }
        private String directoryTree(File folder, List<Boolean> lastFolders) {
            String directory = "";
            if (lastFolders.size() != 0)
                directory += (!(lastFolders.get(lastFolders.size() -1 )) ? "├─ " : "└─ ");
            directory += folder.getName() + " " + folderSize(folder);
    
            File[] files = folder.listFiles();
            int count = files.length;
            files = sortFiles(files);
            for (int i = 0; i < count; i++) {
                directory += "\n";
                for (Boolean lastFolder : lastFolders) {
                    if (lastFolder) {
                        directory += "   ";
                    } else {
                        directory += "│  ";
                    }
                }
                if (files[i].isFile()) {
                    directory += (i + 1 == count ? "└" : "├") + "─ " +
                            files[i].getName() + " " + files[i].length() + " bytes";
                } else {
                    ArrayList<Boolean> list = new ArrayList<>(lastFolders);
                    list.add(i+1 == count);
                    directory += directoryTree(files[i], list);
                }
            }
            return directory;
        }
        private long getFolderSize(File folder) {
            long size = 0;
            File[] files = folder.listFiles();
    
            int count = files.length;
    
            for (int i = 0; i < count; i++) {
                if (files[i].isFile()) {
                    size += files[i].length();
                } else {
                    size += getFolderSize(files[i]);
                }
            }
            return size;
        }
        private String folderSize(File folder) {
            return getFolderSize(folder) + " bytes";
        }
        private File[] sortFiles(File[] folder) {
    
            Arrays.sort(folder);
            List<File> sorted = new ArrayList<>();
    
            for (int i = 0; i < folder.length; i++) {
                if (folder[i].isDirectory()) sorted.add(folder[i]);
            }
    
            for (int i = 0; i < folder.length; i++) {
                if (folder[i].isFile()) sorted.add(folder[i]);
            }
            return sorted.toArray(new File[sorted.size()]);
        }
    }
    

    Example of output

    test3 0 bytes
    ├─ a 0 bytes
    │  ├─ aa 0 bytes
    │  │  ├─ a.txt 0 bytes
    │  │  ├─ b.txt 0 bytes
    │  │  ├─ c.txt 0 bytes
    │  │  └─ d.txt 0 bytes
    │  └─ BA 0 bytes
    │     ├─ A.txt 0 bytes
    │     ├─ b.txt 0 bytes
    │     ├─ C.txt 0 bytes
    │     └─ d.txt 0 bytes
    ├─ b 0 bytes
    │  ├─ AB 0 bytes
    │  │  ├─ a.txt 0 bytes
    │  │  ├─ b.txt 0 bytes
    │  │  ├─ c.txt 0 bytes
    │  │  └─ d.txt 0 bytes
    │  └─ bb 0 bytes
    │     ├─ A.txt 0 bytes
    │     ├─ b.txt 0 bytes
    │     ├─ C.txt 0 bytes
    │     └─ d.txt 0 bytes
    ├─ c 0 bytes
    │  ├─ aa 0 bytes
    │  │  ├─ a.txt 0 bytes
    │  │  ├─ b.txt 0 bytes
    │  │  ├─ c.txt 0 bytes
    │  │  └─ d.txt 0 bytes
    │  ├─ BA 0 bytes
    │  │  ├─ A.txt 0 bytes
    │  │  ├─ b.txt 0 bytes
    │  │  ├─ C.txt 0 bytes
    │  │  └─ d.txt 0 bytes
    │  ├─ a.txt 0 bytes
    │  ├─ b.txt 0 bytes
    │  ├─ c.txt 0 bytes
    │  └─ d.txt 0 bytes
    └─ d 0 bytes
       ├─ aa 0 bytes
       │  ├─ a.txt 0 bytes
       │  ├─ b.txt 0 bytes
       │  ├─ c.txt 0 bytes
       │  └─ d.txt 0 bytes
       └─ bb 0 bytes
          ├─ A.txt 0 bytes
          ├─ b.txt 0 bytes
          ├─ C.txt 0 bytes
          └─ d.txt 0 bytes