print directory tree
This is how I did it.
The Code
import java.io.File;
public class FileAssert {
/**
* Pretty print the directory tree and its file names.
*
* @param folder
* must be a folder.
* @return
*/
public static String printDirectoryTree(File folder) {
if (!folder.isDirectory()) {
throw new IllegalArgumentException("folder is not a Directory");
}
int indent = 0;
StringBuilder sb = new StringBuilder();
printDirectoryTree(folder, indent, sb);
return sb.toString();
}
private static void printDirectoryTree(File folder, int indent,
StringBuilder sb) {
if (!folder.isDirectory()) {
throw new IllegalArgumentException("folder is not a Directory");
}
sb.append(getIndentString(indent));
sb.append("+--");
sb.append(folder.getName());
sb.append("/");
sb.append("\n");
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
printDirectoryTree(file, indent + 1, sb);
} else {
printFile(file, indent + 1, sb);
}
}
}
private static void printFile(File file, int indent, StringBuilder sb) {
sb.append(getIndentString(indent));
sb.append("+--");
sb.append(file.getName());
sb.append("\n");
}
private static String getIndentString(int indent) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < indent; i++) {
sb.append("| ");
}
return sb.toString();
}
}
The Result
+--folder1/
| +--a.txt
| +--folder2/
| | +--b1.txt
| | +--b2.txt
| | +--b3.txt
| | +--folder3/
| +--folder4/
The UnitTest
import static org.junit.Assert.*;
import java.io.File;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class FileAssertTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
private File folder1;
@Before
public void setUp() {
folder1 = temporaryFolder.newFolder("folder1");
}
@Test
public void testPrintDirectoryTreeWhenFolderIsEmpty() {
// Invoke
String actual = FileAssert.printDirectoryTree(folder1);
// Verify
assertEquals("+--folder1/\n", actual);
}
private static final String EXPECTED_FCOF = "" + "+--folder1/\n"
+ "| +--a.txt\n";
@Test
public void testPrintDirectoryTreeWhenFolderContainsOneFile()
throws Exception {
// Setup
File aFile = new File(folder1, "a.txt");
assertTrue(aFile.createNewFile());
// Invoke
String actual = FileAssert.printDirectoryTree(folder1);
// Verify
assertEquals(EXPECTED_FCOF, actual);
}
private static final String EXPECTED_COMPLEX = "+--folder1/\n"
+ "| +--a.txt\n" + "| +--folder2/\n" + "| | +--b1.txt\n"
+ "| | +--b2.txt\n" + "| | +--b3.txt\n" + "| | +--folder3/\n"
+ "| +--folder4/\n";
@Test
public void testPrintDirectoryTreeComplex() throws Exception {
// Setup
File aFile = new File(folder1, "a.txt");
assertTrue(aFile.createNewFile());
File folder2 = new File(folder1, "folder2");
assertTrue(folder2.mkdir());
File b1File = new File(folder2, "b1.txt");
assertTrue(b1File.createNewFile());
File b2File = new File(folder2, "b2.txt");
assertTrue(b2File.createNewFile());
File folder3 = new File(folder2, "folder3");
assertTrue(folder3.mkdir());
File b3File = new File(folder2, "b3.txt");
assertTrue(b3File.createNewFile());
File folder4 = new File(folder1, "folder4");
assertTrue(folder4.mkdir());
// Invoke
String actual = FileAssert.printDirectoryTree(folder1);
// Verify
assertEquals(EXPECTED_COMPLEX, actual);
}
}
file directory printing pretty-printing
This is my solution:
(The TreeNode
Class is copied from there.)
public static String renderDirectoryTree(TreeNode<FileInformation> tree) {
List<StringBuilder> lines = renderDirectoryTreeLines(tree);
String newline = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder(lines.size() * 20);
for (StringBuilder line : lines) {
sb.append(line);
sb.append(newline);
}
return sb.toString();
}
public static List<StringBuilder> renderDirectoryTreeLines(TreeNode<FileInformation> tree) {
List<StringBuilder> result = new LinkedList<>();
result.add(new StringBuilder().append(tree.getData().getPath().getFileName()));
Iterator<TreeNode<FileInformation>> iterator = tree.getChildren().iterator();
while (iterator.hasNext()) {
List<StringBuilder> subtree = renderDirectoryTreeLines(iterator.next());
if (iterator.hasNext()) {
addSubtree(result, subtree);
} else {
addLastSubtree(result, subtree);
}
}
return result;
}
private static void addSubtree(List<StringBuilder> result, List<StringBuilder> subtree) {
Iterator<StringBuilder> iterator = subtree.iterator();
//subtree generated by renderDirectoryTreeLines has at least one line which is tree.getData()
result.add(iterator.next().insert(0, "├── "));
while (iterator.hasNext()) {
result.add(iterator.next().insert(0, "│ "));
}
}
private static void addLastSubtree(List<StringBuilder> result, List<StringBuilder> subtree) {
Iterator<StringBuilder> iterator = subtree.iterator();
//subtree generated by renderDirectoryTreeLines has at least one line which is tree.getData()
result.add(iterator.next().insert(0, "└── "));
while (iterator.hasNext()) {
result.add(iterator.next().insert(0, " "));
}
}
with this output:
DirectoryCatalog
├── .git
│ ├── COMMIT_EDITMSG
│ ├── config
│ ├── description
│ ├── HEAD
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── post-commit.sample
│ │ ├── post-receive.sample
│ │ ├── post-update.sample
│ │ ├── pre-applypatch.sample
│ │ ├── pre-commit.sample
│ │ ├── pre-push.sample
│ │ ├── pre-rebase.sample
│ │ ├── prepare-commit-msg.sample
│ │ └── update.sample
│ ├── index
│ ├── info
│ │ └── exclude
│ ├── logs
│ │ ├── HEAD
│ │ └── refs
│ │ ├── heads
│ │ │ └── master
│ │ └── remotes
│ │ └── origin
│ │ └── master
│ ├── objects
│ │ ├── 0b
│ │ │ └── b3fb0a15268c9770220938b1048305429527c7
│ │ ├── 0d
│ │ │ └── e508f20f1cb44ff543cec54ea93a71e5e40d1d
│ │ ├── 10
│ │ │ └── 9c753f3aab08f167f8409e6c9abec27cad6548
│ │ ├── 15
│ │ │ └── 7602556ebd120e656ae8dcd00cb361bfb3ef79
│ │ ├── 16
│ │ │ └── 952a5d1f5f3d15199f3e85b3d895a81990024e
│ │ ├── 1c
│ │ │ └── 5b36cd4d41b9b7d0df46d4184512098186c904
│ │ ├── 20
│ │ │ └── ae5cc82ebbb85f9161d8fd9783905e4cbee72c
│ │ ├── 21
│ │ │ └── e42add0fb2205a75ff621dbeb6d76455816b79
│ │ ├── 23
│ │ │ └── af4eaa4007ca941e562406b7b329c6ba4b395e
│ │ ├── 28
│ │ │ └── 6caf4b7be3ac85a476f3782220fe167a040971
│ │ ├── 2b
│ │ │ └── f6743fb97162e999fb6429510bb8a52114bc31
│ │ ├── 35
│ │ │ └── acd4ab6acb599d4e3244be2a8dc3a0161bcb3c
│ │ ├── 46
│ │ │ └── 1ef7c4db86e0466bb8f1f81dc25f12e3598db6
│ │ ├── 47
│ │ │ └── 4ce7f18330e5295ab1ef2eea66505235819e22
│ │ ├── 4b
│ │ │ └── 825dc642cb6eb9a060e54bf8d69288fbee4904
│ │ ├── 4e
│ │ │ └── 4e047c077c7825a845deebda7f97832cee847b
│ │ ├── 4f
│ │ │ └── 20b118269d71535e469966fdb5fe8a78ae6c9a
│ │ ├── 51
│ │ │ └── 677b295b4cd9931354dd52fb6050015d524fea
│ │ ├── 52
│ │ │ └── 9c34997d8262bd207037f0373703d68d4e1a4e
│ │ ├── 5b
│ │ │ └── 928f45816cc51609861f0930251accbe7de7f9
│ │ ├── 5d
│ │ │ └── 7cdbe029c6eff99c72d09b0a81347b605e77d7
│ │ ├── 61
│ │ │ └── 2b9d86f6ac365ede894e13a6273fd13833f44f
│ │ ├── 67
│ │ │ └── 2209cb240eac0303d6e3b6c7eb04242d661fad
│ │ ├── 6b
│ │ │ ├── c84e19913908f16141677b9d66abdb620350a0
│ │ │ └── d278b63be854ccd3c02b9038ee43366021b1a1
│ │ ├── 6c
│ │ │ └── 9d10e91679988caaee6759d48daf336f28a9a3
│ │ ├── 70
│ │ │ └── 4284c78f1c664c1348af5a784cca55c51fd66a
│ │ ├── 72
│ │ │ └── 1ab5fe4e4226930668048d97331103a92751be
│ │ ├── 78
│ │ │ └── 64a41eaf50f32ae8d2cab1acd200c405215c1a
│ │ ├── 82
│ │ │ └── 36f772feca12b3e301eea50774458a7e77c7fb
│ │ ├── 83
│ │ │ └── bc1e2a1f3187f28d63d7fa334744810d80c20d
│ │ ├── 87
│ │ │ └── 3ce97f624e9a1ae4a1bbf41218d50dc3503d6f
│ │ ├── 8a
│ │ │ └── 0b282aa6885fb573c106b3551f7275c5f17e8e
│ │ ├── 91
│ │ │ └── a7e269e19dfc62e27137a0b57ef3e430cee4fd
│ │ ├── 94
│ │ │ ├── 065a39b0dd7ce05604b96aff84d984493553e2
│ │ │ └── 5cbc994fb2d251437e71edf3a6eb289c5836ec
│ │ ├── 95
│ │ │ └── f481326b62c9adff2a0dad47480e279adb518f
│ │ ├── 9e
│ │ │ └── 1f7de67de38e67479cb8e38ad92d6354838393
│ │ ├── a1
│ │ │ └── e385dff1fb08b7a45ea52af43b22d240f0adab
│ │ ├── a7
│ │ │ └── 8934a5a81d95a85b9c97a3e1c1429186feb83d
│ │ ├── ab
│ │ │ └── 855c3379bdb3e4a22605de58f3438148d6ffe7
│ │ ├── b7
│ │ │ └── 64eafa2ba4e7f8f52a4e96da61b3d77f262d16
│ │ ├── bd
│ │ │ └── 9374662b409bb364779212874e7cf611541c38
│ │ ├── c1
│ │ │ └── f858c163f9c8cb89a145a60e87c9e35c97fb93
│ │ ├── c3
│ │ │ └── 35d07a1078656646ca6e980b468b938106d357
│ │ ├── c5
│ │ │ └── ac562c59d6a0430fa0ccd1fa6318fa5d48604f
│ │ ├── c8
│ │ │ └── f3d9284a65afbff6640da7970664ee2134c85b
│ │ ├── c9
│ │ │ └── 7a8bdb9088d370da7e88784a7a093b971aa23a
│ │ ├── cc
│ │ │ └── a6a5141b614b5e351c7e5b6b677ef09a931786
│ │ ├── d1
│ │ │ └── 76229a9e1d0172f84d060904d171be51f9d0f6
│ │ ├── d3
│ │ │ ├── 2f0a1ba59a0c52d3acc62de1d624fb68423ee3
│ │ │ └── b9dfcb3216a2feab03b1ae96280e3c1c963953
│ │ ├── e0
│ │ │ └── 6d2081865a766a8668acc12878f98b27fc9ea0
│ │ ├── e5
│ │ │ └── 3106578cd8adcd085c5c63c05fc49d5a5a3dbb
│ │ ├── info
│ │ └── pack
│ └── refs
│ ├── heads
│ │ └── master
│ ├── remotes
│ │ └── origin
│ │ └── master
│ └── tags
├── .gitattributes
├── .gitignore
├── .gradle
│ └── 2.2.1
│ └── taskArtifacts
│ ├── cache.properties
│ ├── cache.properties.lock
│ ├── fileHashes.bin
│ ├── fileSnapshots.bin
│ ├── outputFileStates.bin
│ └── taskArtifacts.bin
├── .idea
│ ├── .name
│ ├── compiler.xml
│ ├── copyright
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── libraries
│ │ ├── Gradle__commons_io_commons_io_2_4.xml
│ │ ├── Gradle__junit_junit_4_11.xml
│ │ └── Gradle__org_hamcrest_hamcrest_core_1_3.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── scopes
│ │ └── scope_settings.xml
│ ├── uiDesigner.xml
│ ├── vcs.xml
│ └── workspace.xml
├── app
│ ├── app.iml
│ ├── build
│ │ ├── classes
│ │ │ └── main
│ │ │ └── gq
│ │ │ └── baijie
│ │ │ └── catalog
│ │ │ ├── controllor
│ │ │ │ ├── FilesScanner$MyFileVisitor.class
│ │ │ │ └── FilesScanner.class
│ │ │ ├── entity
│ │ │ │ └── FileInformation.class
│ │ │ ├── Main.class
│ │ │ └── util
│ │ │ ├── FileAssert.class
│ │ │ ├── Hash.class
│ │ │ ├── HEX.class
│ │ │ ├── Printer$1.class
│ │ │ ├── Printer$DirectoryTreeRender.class
│ │ │ ├── Printer.class
│ │ │ └── TreeNode.class
│ │ ├── dependency-cache
│ │ ├── resources
│ │ │ └── main
│ │ └── tmp
│ │ └── compileJava
│ ├── build.gradle
│ └── src
│ ├── main
│ │ └── java
│ │ └── gq
│ │ └── baijie
│ │ └── catalog
│ │ ├── controllor
│ │ │ └── FilesScanner.java
│ │ ├── entity
│ │ │ └── FileInformation.java
│ │ ├── Main.java
│ │ └── util
│ │ ├── FileAssert.java
│ │ ├── Hash.java
│ │ ├── HEX.java
│ │ ├── Printer.java
│ │ └── TreeNode.java
│ └── test
│ └── java
├── DirectoryCatalog.iml
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── LICENSE
├── README.md
├── settings.gradle
└── temp
├── 150110161006.txt
├── 150110173453.txt
├── 150110175353.txt
├── 150111111311.txt
├── 150111112500.txt
├── 150111113411.txt
├── 150111155619.txt
├── 150111161958.txt
├── 150111162230.txt
├── 150111162632.txt
├── 150111163225.txt
├── 150111163330.txt
├── 150111164526.txt
├── 150111205412.txt
├── 150111210322.txt
├── 150111210506.txt
├── 150111210927.txt
├── 150111211249.txt
├── 150111211321.txt
├── 150111220750.txt
├── 150111220822.txt
├── 150111221437.txt
├── 150111221842.txt
├── 150111222437.txt
├── 150111234344.txt
├── 150111234433.txt
└── 150112000034.txt