001package Torello.Java; 002 003import java.util.*; 004import java.util.function.*; 005import java.util.stream.*; 006import java.io.*; 007 008import Torello.Java.VariableReturnType.*; 009 010/** 011 * One of the <I>flagship classes</I> of Java HTML, {@code FileNode} loads a directory or 012 * directory-tree from a File-System into memory, and provides a thorough API for listing and 013 * analyzing its contents. 014 * 015 * <EMBED CLASS='external-html' DATA-FILE-ID=FN> 016 */ 017public final class FileNode 018 implements CharSequence, Comparable<FileNode>, java.io.Serializable, Cloneable 019{ 020 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 021 public static final long serialVersionUID = 1; 022 023 /** 024 * When this variable is {@code TRUE} debug and status information will be sent to 025 * Standard-Output. 026 */ 027 public static boolean VERBOSE = false; 028 029 /** The name of the file or directory is saved/stored here */ 030 public final String name; 031 032 /** 033 * If {@code 'this'} class-instance represents a directory in the BASH/UNIX or MS-DOS file 034 * system, this variable will be {@code TRUE}. When this field is set to {@code FALSE}, it 035 * means that {@code 'this'} instance is a file. 036 */ 037 public final boolean isDirectory; 038 039 /** 040 * The parent/container {@code 'FileNode'} directory is saved here - like a <I>pointer 041 * "tree"</I>. 042 */ 043 protected FileNode parent; 044 045 /** 046 * When a tree is loaded into memory, the size of each file is saved in this variable. It can 047 * be retrieved (and even changed). 048 */ 049 public final long fileSize; 050 051 /** 052 * When a tree is loaded into memory, the file-date of the file is saved in this variable. It 053 * can be retrieved. If the {@code SecurityManager.checkRead(fileName)} denies read access to 054 * the file, this field will equal zero. 055 * 056 * <BR /><BR /><B CLASS=JDDescLabel>Time in Milli-Seconds:</B> 057 * 058 * <BR />This field is a Java simple-type {@code 'long'} which represents the time the file was 059 * last modified, measured in Milli-Seconds since the epoch 060 * {@code (00:00:00 GMT, January 1, 1970)} 061 */ 062 public final long lastModified; 063 064 /** 065 * This variable remains null for all instances of this class which represent 'files' on the 066 * underlying Operating-System, rather than 'directories.' 067 * 068 * <BR /><BR />On the other hand, if {@code 'this'} instance of {@code FileNode} represents an 069 * MS-DOS, Unix, or Apple File-System directory, then this field will be constructed / 070 * instantiated and hold all file and sub-directory {@code FileNode}-instances which contained 071 * by this directory. 072 */ 073 protected final Vector<FileNode> children; 074 075 076 // ******************************************************************************************** 077 // ******************************************************************************************** 078 // FileNode Constructors 079 // ******************************************************************************************** 080 // ******************************************************************************************** 081 082 083 /** 084 * This constructor builds a {@code FileNode} object - which <I>must be a 085 * {@code FileNode}-Directory instance</I> and may not be a {@code FileNode}-File instance. 086 * 087 * <BR /><BR /><B CLASS=JDDescLabel>{@code FileNode}-Directory:</B> 088 * 089 * <BR />This instance will have a {@link #fileSize} field whose value equals {@code '0'}, and 090 * an {@link #isDirectory} value set to {@code FALSE}. 091 * 092 * <BR /><BR />Directory-Name validity checks are not performed here. This constructor has a 093 * {@code 'protected'} access level, and is only called internally when a directory has been 094 * found by getter-calls to {@code java.io.File} (and therefore are extremely unlikely to be 095 * invalid). 096 * 097 * @param name The name of {@code 'this' FileNode}. 098 * 099 * @param parent This is the parent or "container-directory" of {@code 'this' FileNode}. If a 100 * {@code FileNode} that is not a directory itself is passed as the parent, then an exception 101 * will be thrown. 102 * 103 * @param lastModified This must be a {@code long} value indicating when the file was last 104 * modified - according to the Operating-System. This value may be {@code '0'}, and if so, it 105 * indicates that this information was either not available, or a read of the value was not 106 * allowed by the Operating-System Security-Manager. 107 * 108 * <DIV CLASS=COMPLETE>{@code 109 * this.name = name; 110 * this.parent = parent; 111 * this.isDirectory = true; 112 * this.fileSize = 0; 113 * this.lastModified = lastModified; 114 * this.children = new Vector<>(); 115 * }</DIV> 116 */ 117 protected FileNode(String name, FileNode parent, long lastModified) 118 { 119 this.name = name; 120 this.parent = parent; 121 this.isDirectory = true; 122 this.fileSize = 0; 123 this.lastModified = lastModified; 124 this.children = new Vector<>(); 125 } 126 127 /** 128 * This constructor builds a {@code FileNode} object which <I>must be a {@code FileNode}-File 129 * instance</I> - and may not be a {@code FileNode}-Directory instance. 130 * 131 * <BR /><BR /><B CLASS=JDDescLabel>{@code FileNode}-File:</B> 132 * 133 * <BR /><BR /><B>SPECIFICALLY:</B> The node that is instantiated will have a 134 * {@link #isDirectory} value of {@code FALSE}. 135 * 136 * <BR /><BR />File-Name validity checks are not performed here. This constructor has a 137 * {@code 'protected'} access level, and is only called internally when a file has been found 138 * by getter-calls to {@code java.io.File} (and therefore are extremely unlikely to be 139 * invalid). 140 * 141 * @param name The name of {@code 'this' FileNode} 142 * 143 * @param parent This is the parent or "container-directory" of {@code 'this' FileNode}. 144 * If a {@code FileNode} that is not a directory itself is passed as the parent, then an 145 * exception will be thrown. 146 * 147 * @param fileSize The size of this file - in bytes. 148 * 149 * @param lastModified This must be a long value indicating when the file was last modified - 150 * according to the Operating-System. This value may be {@code '0'}, and if so, it indicates 151 * that this information was either not available, or a read of the value was not allowed by 152 * the Operating-System security manager. 153 * 154 * <DIV CLASS="COMPLETE">{@code 155 * this.name = name; 156 * this.parent = parent; 157 * this.isDirectory = false; 158 * this.fileSize = fileSize; 159 * this.lastModified = lastModified; 160 * this.children = null; 161 * }</DIV> 162 */ 163 protected FileNode(String name, FileNode parent, long fileSize, long lastModified) 164 { 165 this.name = name; 166 this.parent = parent; 167 this.isDirectory = false; 168 this.fileSize = fileSize; 169 this.lastModified = lastModified; 170 this.children = null; 171 } 172 173 /** 174 * This constructor builds a {@code 'ROOT' FileNode} instance. These instances are 175 * {@code FileNode}-Directories, but they do not have a parent / container {@code FileNode}. 176 * 177 * <BR /><BR />They function indentically to Directory-{@code FileNode's} in all other aspects. 178 * 179 * @param name The name of {@code 'this' FileNode} 180 */ 181 protected FileNode(String name) 182 { 183 if (name.contains("\n")) throw new IllegalArgumentException 184 ("File & Directory names may not contain newlines:\n" + name); 185 186 // NOTE: The first if-statement below is a newer (May, 2022) issue that happened. 187 // The Google Cloud Server UNIX Shell Root Directory is named "/" 188 // That haddn't been tested before. 189 190 if (! name.equals(File.separator)) 191 192 // All other directories on the File-System are stored with their 'name' field saved 193 // with the ending / trailing File.Separator 194 195 if (name.endsWith(File.separator) || name.endsWith("\'")) 196 name = name.substring(0, name.length() - 1); 197 198 long lastModified = 0; 199 200 // Make sure this is a directory. If not, this exception throws since this constructor is 201 // the one used by the "createRoot(String)" method. A "Root FileNode" must always be a 202 // directory 203 204 try 205 { 206 File f = new File(name); 207 208 if (! f.isDirectory()) throw new IllegalArgumentException( 209 "You have attempted to create a new Root Directory - but the filename passed " + 210 "isn't a valid Directory Name: [" + name + ']' 211 ); 212 213 lastModified = f.lastModified(); 214 } 215 216 catch (SecurityException se) 217 { 218 throw new IllegalArgumentException( 219 "You have attempted to create a new Root FileNode instance - but a Security " + 220 "Exception is preventing this. See this exception's Throwable.getCause() for " + 221 "more details.", 222 se 223 ); 224 } 225 226 this.name = name; 227 this.parent = null; 228 this.isDirectory = true; 229 this.fileSize = 0; 230 this.lastModified = lastModified; 231 this.children = new Vector<>(); 232 } 233 234 /** 235 * This is the <B>"Factory Method"</B> for this class. The {@code String name} parameter is 236 * intended to be the root directory-name from which the Complete {@code FileNode}-Tree should 237 * be built / constructed. 238 * 239 * <BR /><BR />The {@code 'name'} parameter passed to this method must be the actual name of 240 * an actual directory on the File-System. 241 * 242 * <BR /><BR /><B CLASS=JDDescLabel>Load-Tree Methods:</B> 243 * 244 * <BR />Once this Root-Node for a tree has been built (by invoking this method), the next 245 * thing to do is read any / all files & directories that reside on the File-System inside 246 * the directory into memory. This class provides several methods for both total and partial 247 * reads of a directory's contents. 248 * 249 * <BR /><BR />In the example below, the standard Tree-Loading method {@link #loadTree()} is 250 * invoked in order to to read the entire contents of the specified File-System Directory into 251 * a {@code FileNode}-Tree in Java Memory. 252 * 253 * <DIV CLASS="EXAMPLE">{@code 254 * FileNode fn = FileNode 255 * .createRoot("etc/MyDataFiles/user123/") 256 * .loadTree(); 257 * 258 * }</DIV> 259 * 260 * @return An instance of this class from which a {@code FileNode} tree may be instantiated. 261 */ 262 public static FileNode createRoot(String name) 263 { return new FileNode(name); } 264 265 266 // ******************************************************************************************** 267 // ******************************************************************************************** 268 // retrieve operations 269 // ******************************************************************************************** 270 // ******************************************************************************************** 271 272 273 /** 274 * Convenience Method. 275 * <BR />Invokes: {@link #pollDir(String, boolean)} 276 * <BR />Does <B>NOT</B> ignore case 277 */ 278 public FileNode pollDir(String dirName) { return pollDir(dirName, false); } 279 280 /** 281 * Retrieves the sub-directory {@code FileNode} instance named by parameter {@code 'dirName'} 282 * if there is a {@code FileNode} that is a <B>Direct Descendant</B> of {@code 'this'} 283 * instance of {@code FileNode}. 284 * 285 * <EMBED CLASS='external-html' DATA-KIND=dir DATA-NAME=directory DATA-FILE-ID=FN_POLL_DIRFILE> 286 * 287 * @param dirName This is the name of any directory. 288 * 289 * <BR /><BR /><B STYLE="color: red">IMPORTANT:</B> This must be the <I><B>name-only</I></B> 290 * leaving out all parent-directory or drive-letter text. 291 * 292 * <BR /><BR /><B STYLE="color: red">FURTHERMORE:</B> The forward slash ({@code '/'}) or the 293 * back-slash ({@code '\'}) character that sometimes is appended to a directory-name 294 * <B><I>may not</I></B> be included in this name (unless a forward-slash or back-slash is 295 * a part of the name of the directory). 296 * 297 * <BR /><BR /><B STYLE="color: red">FINALLY:</B> When this directory is extracted, none 298 * of the child pointers contained by this directory-instance of {@code FileNode} will be 299 * modified. In essence, the entire sub-tree - <I>starting at the directory that was 300 * specified</I> - will be extracted from the parent-tree. Any / all contents of the 301 * sub-tree shall be in the same state as they were prior to the extraction. 302 * 303 * @param ignoreCase For some files and directories, on some operating systems (Microsoft 304 * Windows, for instance) File-System name case is not considered relevant when matching 305 * directory names. If this parameter is passed {@code TRUE}, then name comparisons will use 306 * a case-insensitive comparison mechanism. 307 * 308 * @return The child {@code FileNode} (sub-directory) of {@code 'this'} directory whose name 309 * matches the name provided by parameter {@code 'dirName'}. It's {@code 'parent'} field 310 * will be null, and the parent {@code FileNode} instance will not have a pointer to the 311 * instance that is returned. 312 * 313 * <BR /><BR />If no matching directory is found, then this method shall return null. 314 * 315 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is a file, 316 * not a directory, then this exception shall throw. Only directories can contain other 317 * instances of {@code FileNode}. 318 * 319 * @see #dir(String, boolean) 320 * @see #children 321 */ 322 public FileNode pollDir(String dirName, boolean ignoreCase) 323 { 324 FileNode ret = dir(dirName, ignoreCase); 325 326 if (ret != null) 327 { 328 children.remove(ret); 329 ret.parent = null; 330 } 331 332 return ret; 333 } 334 335 /** 336 * Convenience Method. 337 * <BR />Invokes: {@link #dir(String, boolean)} 338 * <BR />Does <B>NOT</B> ignore case 339 */ 340 public FileNode dir(String dirName) { return dir(dirName, false); } 341 342 /** 343 * Retrieves the sub-directory {@code FileNode} instance named by parameter {@code 'dirName'} 344 * if there is a {@code FileNode} that is a <I>direct descendant</I> of {@code 'this'} instance 345 * of {@code FileNode}. 346 * 347 * @param dirName This is the name of any directory. 348 * 349 * <BR /><BR /><B STYLE="color: red">IMPORTANT:</B> This must be the <I><B>name-only</I></B> 350 * leaving out all parent-directory or drive-letter text. 351 * 352 * <BR /><BR /><B STYLE="color: red">FURTHERMORE:</B> The forward slash ({@code '/'}) or the 353 * back-slash ({@code '\'}) character that sometimes is appended to a directory-name 354 * <B><I>may not</I></B> be included in this name (unless a forward-slash or back-slash is 355 * a part of the name of the directory). 356 * 357 * @param ignoreCase For some files and directories, on some operating systems (Microsoft 358 * Windows, for instance) File-System name case is not considered relevant when matching 359 * directory names. If this parameter is passed {@code TRUE}, then name comparisons will use 360 * a case-insensitive comparison mechanism. 361 * 362 * @return The child {@code FileNode} (sub-directory) of this directory whose name matches 363 * the name provided by parameter {@code 'dirName'}. 364 * 365 * <BR /><BR />If no matching directory is found, then this method shall return null. 366 * 367 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is a file, 368 * not a directory, then this exception shall throw. Only directories can contain other 369 * instances of {@code FileNode}. 370 * 371 * @see #children 372 * @see #isDirectory 373 * @see #name 374 */ 375 public FileNode dir(String dirName, boolean ignoreCase) 376 { 377 // Only directories may contain other instances of FileNode 378 DirExpectedException.check(this); 379 380 // We are looking for a directory named 'dirName' 381 // 382 // IMPORTANT: The outer squiqgly-braces are MANDATORY. Without them, there is 383 // "deceptive indentation," because the 'else' is paired with the second-if, 384 // not the first! 385 386 if (ignoreCase) 387 { 388 for (FileNode fn : children) 389 if (fn.isDirectory && fn.name.equalsIgnoreCase(dirName)) return fn; 390 } 391 392 else 393 { 394 for (FileNode fn2 : children) 395 if (fn2.isDirectory && fn2.name.equals(dirName)) return fn2; 396 } 397 398 // Not found, return null. 399 return null; 400 } 401 402 /** 403 * Convenience Method. 404 * <BR />Invokes: {@link #pollFile(String, boolean)} 405 * <BR />Does <B>NOT</B> ignore case 406 */ 407 public FileNode pollFile(String fileName) { return pollFile(fileName, false); } 408 409 /** 410 * Retrieves a {@code FileNode} instance named by parameter {@code 'fileName'} if there is 411 * a {@code FileNode} that is a <B>Direct Descendant</B> of {@code 'this'} instance 412 * of {@code FileNode}, <B><I>and</I></B> that instance is a file (not a directory) whose 413 * name matches parameter {@code 'fileName'}. 414 * 415 * <EMBED CLASS='external-html' DATA-KIND=file DATA-NAME=file DATA-FILE-ID=FN_POLL_DIRFILE> 416 * 417 * @param fileName This is the name of any file. 418 * 419 * <BR /><BR /><B STYLE="color: red">IMPORTANT:</B> This must be the <I><B>name-only</I></B> 420 * leaving out all parent-directory or drive-letter text. 421 * 422 * @param ignoreCase For some files and directories, on some operating systems (Microsoft 423 * Windows, for instance) File-System name case is not considered relevant when matching 424 * file-names. If this parameter is passed {@code TRUE}, then name comparisons will use 425 * a case-insensitive comparison mechanism. 426 * 427 * @return The child {@code FileNode} of {@code 'this'} directory whose name matches the 428 * name provided by parameter {@code 'fileName'}. It's {@code 'parent'} field 429 * will be null, and the parent {@code FileNode} instance will not have a pointer to the 430 * instance that is returned. 431 * 432 * <BR /><BR />If no matching file is found, then this method shall return null. 433 * 434 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is a file, 435 * not a directory, then this exception shall throw. Only directories can contain other 436 * instances of {@code FileNode}. 437 * 438 * @see #file(String, boolean) 439 */ 440 public FileNode pollFile(String fileName, boolean ignoreCase) 441 { 442 FileNode ret = file(fileName, ignoreCase); 443 444 if (ret != null) 445 { 446 children.remove(ret); 447 ret.parent = null; 448 } 449 450 return ret; 451 } 452 453 /** 454 * Convenience Method. 455 * <BR />Invokes: {@link #file(String, boolean)} 456 * <BR />Does <B>NOT</B> ignore case 457 */ 458 public FileNode file(String fileName) { return file(fileName, false); } 459 460 /** 461 * Retrieves a {@code FileNode} named by parameter {@code 'fileName'} if there is a 462 * {@code FileNode} instance that is a <I>direct descendant</I> of {@code 'this' FileNode} 463 * that is, itself, a file and not a directory. 464 * 465 * @param fileName This is the name of any file. 466 * 467 * <BR /><BR /><B STYLE="color: red">IMPORTANT:</B> This must be the <I><B>name-only</I></B> 468 * leaving out all parent-directory or drive-letter text. 469 * 470 * @param ignoreCase For some files and directories, on some operating systems (Microsoft 471 * Windows, for instance) file-name case is not considered relevant when matching file 472 * names. If this parameter is passed {@code TRUE}, then file-name comparisons will use 473 * a case-insensitive comparison mechanism. 474 * 475 * @return An instance of {@code FileNode} that is a <I>direct-descendant</I> of 476 * {@code 'this'} directory - and whose name matches the name provided by parameter 477 * {@code 'fileName'}. 478 * 479 * <BR /><BR />If no matching file is found, then this method shall return null. 480 * 481 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is a file, 482 * not a directory, then this exception shall throw. Only directories can contain other 483 * instances of {@code FileNode}. 484 * 485 * @see #children 486 * @see #isDirectory 487 * @see #name 488 */ 489 public FileNode file(String fileName, boolean ignoreCase) 490 { 491 // Only directories may contain other instances of FileNode 492 DirExpectedException.check(this); 493 494 // We are looking for a file named 'fileName' 495 // 496 // IMPORTANT: The outer squiqly-braces are MANDATORY. Without them, there is 497 // "deceptive indentation," because the 'else' is paired with the second-if, 498 // not the first! 499 500 if (ignoreCase) 501 { 502 for (FileNode fn : children) 503 if ((! fn.isDirectory) && fn.name.equalsIgnoreCase(fileName)) return fn; 504 } 505 506 else 507 { 508 for (FileNode fn2 : children) 509 if ((! fn2.isDirectory) && fn2.name.equals(fileName)) return fn2; 510 } 511 512 // Not found, return null. 513 return null; 514 } 515 516 517 // ******************************************************************************************** 518 // ******************************************************************************************** 519 // These methods satisfy the Cloneable, Comparable, CharSequence Interfaces 520 // ******************************************************************************************** 521 // ******************************************************************************************** 522 523 524 /** 525 * This satisfies Java's "hash-code" method requirement. This can facilitate saving instances 526 * of this class into tables, maps, lists, etc. 527 * 528 * @return A hash-code to be used by a hash-algorithm with likely few crashes. Note that the 529 * hash from Java's {@code java.lang.String} is simply reused. 530 */ 531 public int hashCode() { return toString().hashCode(); } 532 533 /* 534 * Java's {@code equals(Object o)} method requirements. 535 * 536 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 537 * 538 * <BR />This method is final, and cannot be modified by sub-classes. 539 * 540 * @param o This may be any {@code java.lang.Object}, but only ones of {@code 'this'} type 541 * whose internal-values are identical will cause this method to return {@code TRUE}. 542 * 543 * @return {@code TRUE} If {@code 'this'} instance' internal-fields are equal to the 544 * internal-fields another {@code FileNode} instance. 545 * 546 * <BR /><BR /><B><SPAN STYLE='color: red;">DEEP-EQUALS:</B></SPAN> Due to how Java's 547 * {@code class Vector} has implemented it's {@code Vector.equals(other)} method - which is 548 * how the child tree-branches of a directory {@code FileNode} stores it's directory 549 * branches - this method <I>does, indeed, perform a 'Deep Equals'</I>. 550 * 551 * @see FileNode#name 552 * @see FileNode#parent 553 * @see FileNode#isDirectory 554 * @see FileNode#children 555 */ 556 public final boolean equals(Object o) 557 { 558 FileNode other; 559 560 return (this == o) 561 || ((o != null) 562 && (this.getClass().equals(o.getClass())) 563 && ((other = (FileNode) o).name.equals(this.name)) 564 && (this.parent == other.parent) // NOTE: A "Reference Comparison" 565 && (this.isDirectory == other.isDirectory) 566 && (this.fileSize == other.fileSize) 567 && (this.lastModified == other.lastModified) 568 && this.name.equals(other.name) 569 && ( ((this.children == null) && (other.children == null)) 570 || (this.children.equals(other.children))) 571 ); 572 } 573 574 /** 575 * Java's {@code interface Cloneable} requirements. This instantiates a new {@code FileNode} 576 * with identical fields. The field {@code Vector<FileNode> 'children'} shall be cloned too. 577 * 578 * @return A new {@code FileNode} whose internal fields are identical to this one. 579 * 580 * <BR /><BR /><B><SPAN STYLE="color: red;">IMPORTANT (DEEP-CLONE) NOTE:</SPAN></B> This 581 * <B>does not</B> perform a deep-tree-traversal clone. Instead, {@code 'this'} instance is 582 * merely copied, and it's child nodes have references inserted into the internal list of 583 * child-nodes. 584 * 585 * @see FileNode#name 586 * @see FileNode#parent 587 * @see FileNode#isDirectory 588 */ 589 public FileNode clone() 590 { 591 if (this.isDirectory) 592 { 593 FileNode ret = new FileNode(this.name, this.parent, this.lastModified); 594 ret.children.addAll(this.children); 595 return ret; 596 } 597 598 else 599 return new FileNode(this.name, this.parent, this.fileSize, this.lastModified); 600 } 601 602 /** 603 * Java's {@code Comparable<T>} Interface-Requirements. This does a very simple comparison 604 * using the results to a call of method {@link #getFullPathName()} 605 * 606 * @param fn Any other {@code FileNode} to be compared to {@code 'this' FileNode}. The file 607 * or directories {@code getFullPathName()} is used to perform a "String" comparison. 608 * 609 * @return An integer that fulfils Java's {@code interface Comparable<T> public boolean 610 * compareTo(T t)} method requirements. 611 * 612 * @see #getFullPathName() 613 */ 614 public final int compareTo(FileNode fn) 615 { return this.getFullPathName().compareTo(fn.getFullPathName()); } 616 617 /** 618 * This is an "alternative Comparitor" that can be used for sorting instances of this class. 619 * It should work with the {@code Collections.sort(List, Comparator)} method in the standard 620 * JDK package {@code java.util.*;} 621 * 622 * <BR /><BR /><B CLASS=JDDescLabel>Comparison Heuristic:</B> 623 * 624 * <BR />This version utilizes the standard JDK {@code String.compareToIgnoreCase(String)} 625 * method. 626 * 627 * @see #getFullPathName() 628 */ 629 public static final Comparator<FileNode> comp2 = (FileNode fn1, FileNode fn2) -> 630 fn1.getFullPathName().compareToIgnoreCase(fn2.getFullPathName()); 631 632 /** 633 * Converts {@code 'this' FileNode} to a {@code String}. 634 * 635 * @return The complete-full path-name of this file or directory. 636 */ 637 public String toString() { return this.getFullPathName(); } 638 639 /** 640 * Returns the {@code char} value at the specified index of the results to a call of method 641 * {@link #getFullPathName()}. An index ranges from {@code zero} to {@code length() - 1}. The 642 * first {@code char} value of the sequence is at index {@code zero}, the next at index 643 * {@code one}, and so on and so forth - as per array indexing. 644 * 645 * <BR /><BR /><B CLASS=JDDescLabel>Character Surrogates:</B> 646 * 647 * <BR />If the {@code char} value specified by the index is a surrogate, 648 * the surrogate value is returned. 649 * 650 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 651 * 652 * <BR />This method is final, and cannot be modified by sub-classes. 653 * 654 * @param index The index of the {@code char} value to be returned 655 * 656 * @return The specified {@code char} value 657 * 658 * @see #getFullPathName() 659 */ 660 public final char charAt(int index) { return this.getFullPathName().charAt(index); } 661 662 /** 663 * Returns the length of the {@code String} returned by {@code public String getFullPathName()} 664 * The length is the number of 16-bit characters in the sequence. 665 * 666 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 667 * 668 * <BR />This method is final, and cannot be modified by sub-classes. 669 * 670 * @return the number of characters in the "Full Path Name" for {@code 'this'} file or\ 671 * directory. 672 * 673 * @see #getFullPathName() 674 */ 675 public final int length() { return this.getFullPathName().length(); } 676 677 /** 678 * Returns a {@code java.lang.CharSequence} that is a subsequence of the results to a call of 679 * method {@link #getFullPathName()} 680 * 681 * <BR /><BR /> The subsequence starts with the {@code char} value at the specified index and 682 * ends with the {@code char} value at index {@code 'end - 1'}. The length (in characters) of 683 * the returned sequence is {@code 'end - start'}, so in the case where 684 * {@code 'start == end'} then an empty sequence is returned. 685 * 686 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 687 * 688 * <BR />This method is final, and cannot be modified by sub-classes. 689 * 690 * @param start The start index, inclusive 691 * @param end The end index, exclusive 692 * 693 * @return The specified subsequence 694 * @see #getFullPathName() 695 */ 696 public final CharSequence subSequence(int start, int end) 697 { return this.getFullPathName().substring(start, end); } 698 699 700 // ******************************************************************************************** 701 // ******************************************************************************************** 702 // Basic Methods 703 // ******************************************************************************************** 704 // ******************************************************************************************** 705 706 707 /** 708 * This returns the name of the file, but leaves off the "extension" 709 * @return Returns the name <I>without the file-extension</I> 710 * 711 * @throws FileExpectedException Since only files may have extensions, if {@code 'this'} 712 * instance of {@code FileNode} is a directory, the {@code FileExpectedException} will throw. 713 */ 714 public String nameNoExt() 715 { 716 FileExpectedException.check(this); // Directories do not have extensions 717 718 int pos = name.lastIndexOf('.'); 719 720 if (pos == -1) return name; 721 722 return name.substring(0, pos); 723 } 724 725 /** 726 * This returns the extension of the file. If this file does not have an extension, 727 * then null shall be returned. 728 * 729 * @param includeTheDot if the user would like to have the {@code '.'} included in the 730 * return {@code String}, then {@code TRUE} should be passed to this parameter. 731 * 732 * @return Returns this file's extension 733 * 734 * @throws FileExpectedException Since only files may have extensions, if {@code 'this'} 735 * instance of {@code FileNode} is a directory, the {@code FileExpectedException} will throw. 736 */ 737 public String ext(boolean includeTheDot) 738 { 739 FileExpectedException.check(this); // Directories do not have extensions 740 741 int pos = name.lastIndexOf('.'); 742 743 if (pos == -1) return null; 744 745 return includeTheDot ? name.substring(pos) : name.substring(pos+1); 746 } 747 748 /** 749 * Invokes the input Java {@code Consumer<FileNode>} on each element in {@code 'this'} 750 * {@code FileNode}-Tree. Note that if {@code 'this'} instance of is a file, not a directory, 751 * then the passed {@code Consumer} shall only be invoked once (on {@code 'this'} instance, 752 * since files do not have sub-directories). 753 * 754 * @param c This is any java {@code Consumer<FileNode>} 755 */ 756 public void forEach(Consumer<FileNode> c) 757 { 758 c.accept(this); 759 if (children != null) children.forEach((FileNode fn) -> fn.forEach(c)); 760 } 761 762 763 // ******************************************************************************************** 764 // ******************************************************************************************** 765 // Deep-Tree Traversal 766 // ******************************************************************************************** 767 // ******************************************************************************************** 768 769 770 /** 771 * Whereas the standard Java {@code clone()} method in this class returns a new, cloned, 772 * instance of {@code FileNode}, if {@code 'this'} instance of {@code FileNode} is a directory, 773 * the tree-branch represented by {@code 'this' FileNode} instance would not be copied by an 774 * invocation of {@code 'clone'}. However, if using this method, {@code 'deepClone'}, on a 775 * directory-{@code FileNode} instance, <B><I>the entire tree-branch represented by 776 * {@code 'this' FileNode} instance is copied.</I></B>. 777 * 778 * <BR /><BR /><B CLASS=JDDescLabel>Deep-Clone:</B> 779 * 780 * <BR />The method's {@code clone()} and {@code deepClone()} shall return identical results 781 * when used on an instance of {@code FileNode} that represents a file, rather than a directory 782 * (<I>and, therefore, does not have any tree-branch information associated with it.</I>). 783 * 784 * @return a <B>"Deep Clone"</B> of {@code 'this' FileNode} instance. If {@code 'this'} 785 * instance of {@code FileNode} represents a file, not a directory, the results of this method 786 * shall be identical to the results of an invocation of the standard {@code 'clone()'} method. 787 * If {@code 'this' FileNode} represents an operation-system directory (not a file), then 788 * each and every child of this tree-branch shall also be copied / cloned by this method. 789 */ 790 public FileNode deepClone() 791 { 792 if (this.isDirectory) 793 { 794 FileNode ret = new FileNode(this.name, this.parent, this.lastModified); 795 for (FileNode child : children) ret.children.add(child.deepClone()); 796 return ret; 797 } 798 799 else return this.clone(); 800 } 801 802 /* 803 ****************************************************************** 804 * JAVA'S Vector.equals ALREADY DOES A DEEP EQUALS ON IT'S CONTENTS 805 ****************************************************************** 806 * 807 * Performs a complete tree traversal to ensure that {@code 'this'} instance of 808 * {@code FileNode} represents precisely the same files from the File-System as input 809 * parameter {@code 'other'} 810 * 811 * @param other Another instance of {@code FileNode} 812 * 813 * @return {@code TRUE} if and only if every file incorporated by {@code 'this'} instance has a 814 * one-to-one mapping with an identical tree {@code 'other'}. 815 * 816 * <BR /><BR /><B><SPAN STYLE='color: red;'>NOTE:</B></SPAN> If {@code 'this'} instance 817 * {@code '.isDirectory'} value is {@code FALSE} (because {@code 'this'} instance of 818 * {@code FileNode} represents a file, not a directory), then this method shall simply 819 * return the results of an invocation to the standard {@code equals(other)} method. If 820 * {@code 'this'} is a file (not a directory), then there are no tree-branch nodes to 821 * test or traverse. 822 823 public boolean deepEquals(FileNode other) 824 { 825 if (! this.isDirectory) return this.equals(other); 826 if (! this.equals(other)) return false; 827 828 for (FileNode child : children) 829 { 830 int pos; 831 832 if ((pos = other.children.indexOf(child)) == -1) return false; 833 834 FileNode otherChild; 835 836 if ((otherChild = other.children.elementAt(pos)).isDirectory) 837 { if (! otherChild.deepEquals(child)) return false; } 838 else 839 { if (! otherChild.equals(child)) return false; } 840 } 841 842 return true; 843 } 844 845 public static void main(String[] argv) 846 { 847 FileNode fn = FileNode.createRoot("Torello").loadTree(); 848 FileNode fn2 = FileNode.createRoot("Torello/Java").loadTree(); 849 FileNode copy = fn.deepClone(); 850 851 System.out.println("fn.deepEquals(copy):\t" + fn.deepEquals(copy)); 852 System.out.println("fn.deepEquals(fn2):\t" + fn.deepEquals(fn2)); 853 } 854 */ 855 856 857 // ******************************************************************************************** 858 // ******************************************************************************************** 859 // Load the contents of the MS-DOS or UNIX File-System into this tree-data-structure 860 // ******************************************************************************************** 861 // ******************************************************************************************** 862 863 864 /** 865 * Convenience Method. 866 * <BR />Invokes: {@link #loadTree(int, FilenameFilter, FileFilter)} 867 * <BR />Passes: All Tree-Branches requested ({@code '-1'}) 868 * <BR />And-Passes: null-filters (Requests no filtering be applied). 869 */ 870 public FileNode loadTree() { return loadTree(-1, null, null); } 871 872 /** 873 * Convenience Method. 874 * <BR />Invokes: {@link #loadTree(int, FilenameFilter, FileFilter)} 875 * <BR />Passes: {@code 'includeFiles'} as a {@code Predicate} to parameter 876 * {@code 'fileFilter'} 877 * <BR />Passes: {@code 'includeDirectories'} (as {@code Predicate}) to 878 * {@code 'directoryFilter'} 879 * <BR />Throws: {@code IllegalArgumentException} If both boolean parameters are {@code FALSE} 880 */ 881 public FileNode loadTree(final boolean includeFiles, final boolean includeDirectories) 882 { 883 if ((! includeFiles) && (! includeDirectories)) throw new IllegalArgumentException( 884 "loadTree(boolean, boolean) has been invoked with both search criteria booleans set " + 885 "to FALSE. This means that there is nothing for the method to do." 886 ); 887 888 return loadTree 889 (-1, (File dir, String name) -> includeFiles, (File file) -> includeDirectories); 890 } 891 892 /** 893 * Convenience Method. 894 * <BR />Invokes: {@link #loadTree(int, FilenameFilter, FileFilter)} 895 * <BR />Passes: <B>'Always False'</B> {@code Predicate} to parameter {@code 'fileFilter'} 896 * <BR />Accepts: A {@code 'directoryFilter'} and {@code 'maxTreeDepth'} 897 */ 898 public FileNode loadTreeJustDirs(int maxTreeDepth, FileFilter directoryFilter) 899 { 900 // Set the return value of the 'fileFilter' predicate to ALWAYS return FALSE. 901 return loadTree(maxTreeDepth, (File dir, String name) -> false, directoryFilter); 902 } 903 904 /** 905 * This populates {@code 'this' FileNode} tree with the contents of the File-System 906 * directory represented by {@code 'this'}. 907 * 908 * <BR /><BR /><B CLASS=JDDescLabel>Directory-FileNode:</B> 909 * 910 * <BR />This method can only be invoked on an instance of {@code 'FileNode'} which represents 911 * a directory on the UNIX or MS-DOS File-System. A {@code DirExpectedException} shall throw 912 * if this method is invoked on a {@code FileNode} instance that represents a file. 913 * 914 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=FN_LOAD_TREE> 915 * 916 * @param maxTreeDepth <EMBED CLASS='external-html' DATA-FILE-ID=FN_MAX_TREE_DEPTH> 917 * @param fileFilter <EMBED CLASS='external-html' DATA-FILE-ID=FN_LOAD_T_FILE_FILT> 918 * @param directoryFilter <EMBED CLASS='external-html' DATA-FILE-ID=FN_LOAD_T_DIR_FILT> 919 * 920 * @return a reference to {@code 'this' FileNode}, for convenience only. It's tree branches 921 * (directories) and leaf nodes (files) will be populated, as per the above parameter 922 * specification-criteria. 923 * 924 * @throws DirExpectedException This method will only execute if the instance of {@code 'this'} 925 * is a directory. Files on the File-System are leaves, not branches - so they do not 926 * have contents to load. 927 * 928 * @throws SecurityException The method <B>{@code java.io.File.listFiles()}</B> is used to 929 * retrieve the list of files for each directory. That method asserts that the Java 930 * Security Managaer {@code java.lang.SecurityManager} may throw this exception if a 931 * restricted directory is accessed by {@code 'listFiles()'}. 932 * 933 * <BR /><BR /><B STYLE='color: red;'>BY-PASS NOTE:</B> Those most common behavior for 934 * restricted directories has been for the {@code listFiles()} to simply return null, which 935 * is handled easily by this code. If this exception is throwing, one may use the internal 936 * <B><I>({@code static} flag)</I></B> {@link #SKIP_DIR_ON_SECURITY_EXCEPTION}. When this 937 * <B><I>{@code static-flag}</I></B> is used, {@code SecurityExceptions} are caught, and the 938 * contents of those directories will simply be ignored and eliminated from the tree. 939 * 940 * @see #loadTree() 941 * @see DirExpectedException#check(FileNode) 942 * @see #SKIP_DIR_ON_SECURITY_EXCEPTION 943 */ 944 public FileNode loadTree 945 (int maxTreeDepth, FilenameFilter fileFilter, FileFilter directoryFilter) 946 { 947 DirExpectedException.check(this); 948 949 loadTreeINTERNAL(maxTreeDepth, fileFilter, directoryFilter); 950 951 return this; 952 } 953 954 /** 955 * Directories on a UNIX platform that were inaccessible didn't seem to throw a 956 * {@code SecurityException}, instead, a null-array was returned. However, in the case that 957 * Java's {@code java.lang.SecurityManager} is catching attempts to access restricted 958 * dirtectories and throwing exceptions (which is likely a rare case) - this {@code boolean} 959 * flag can inform the internal directory-scanner logic to catch these 960 * {@code SecurityException's}. 961 * 962 * <BR /><BR />If "catching and skipping" exceptions has been choosen, then any directory 963 * that is scanned and would throw an exception, instead is left empty by this class' 964 * tree-loading logic. 965 * 966 * <BR /><BR /><B CLASS=JDDescLabel>Thread-Safety:</B> 967 * 968 * <BR />This flag is a non-{@code Thread}-Safe feature, because it is a 969 * <B>{@code static}-Field Flag</B> that is applied to <I>all instances</I> of class 970 * {@code FileNode} 971 */ 972 public static boolean SKIP_DIR_ON_SECURITY_EXCEPTION = false; 973 974 // NOTE: 'this' instance of FileNode will always be a Directory, never File 975 private void loadTreeINTERNAL 976 (int maxTreeDepth, FilenameFilter fileFilter, FileFilter directoryFilter) 977 { 978 File f = getJavaIOFile(); 979 980 if (VERBOSE) System.out.println(f.getPath()); 981 982 // TRICKY! Added: 2019.05.16 - if we are "re-loading" the tree, this line is imperative 983 this.children.removeAllElements(); 984 985 File[] subFilesAndDirs = null; 986 987 // ADDED: 2022.05.18 - The SecurityManager didn't seem to throw a SecurityException for 988 // UNIX directories that could not be accessed. Instead, it just returned a null-pointer, 989 // and this code just threw a NullPointerException. 990 // 991 // NOW: This checks for the "SecurityManager" case (which didn't seem to catch it anyway), 992 // and allows the user whether to skip the directory completely, or throw an exception 993 // when "null" is unceremoniously returned, below. 994 995 try 996 { subFilesAndDirs = f.listFiles(); } 997 998 catch (SecurityException e) 999 { 1000 if (SKIP_DIR_ON_SECURITY_EXCEPTION) return; 1001 else throw e; 1002 } 1003 1004 // RECENT-OCCURENCE: (Never Needed the Google-Cloud-Shell Root Directory) 1005 // A directory that is denied access, seems to return null. The Java-Doc for it says it 1006 // should be throwing a java.lang.SecurityException 1007 1008 if (subFilesAndDirs == null) 1009 { 1010 if (VERBOSE) System.out.println("DIR IS RESTRICTED: " + f.getAbsolutePath()); 1011 return; 1012 } 1013 1014 for (File sub : subFilesAndDirs) 1015 1016 if (sub.isDirectory()) 1017 { 1018 if (VERBOSE) System.out.println("TESTING DIR: " + sub.getAbsolutePath()); 1019 1020 if (directoryFilter != null) if (! directoryFilter.accept(sub)) continue; 1021 1022 long lastModified = 0; 1023 1024 try { lastModified = sub.lastModified(); } catch (SecurityException se) { } 1025 1026 FileNode newSubDir = new FileNode(sub.getName(), this, lastModified); 1027 1028 children.addElement(newSubDir); 1029 1030 if (VERBOSE) System.out.println("ADDED DIR: " + newSubDir.getFullPathName()); 1031 1032 if (maxTreeDepth != 0) 1033 newSubDir.loadTreeINTERNAL(maxTreeDepth - 1, fileFilter, directoryFilter); 1034 1035 } 1036 1037 else /* sub is a file, not a directory */ 1038 { 1039 if (fileFilter != null) 1040 if (! fileFilter.accept(sub.getParentFile(), sub.getName())) 1041 continue; 1042 1043 long lastModified = 0; 1044 1045 try { lastModified = sub.lastModified(); } catch (SecurityException se) { } 1046 1047 children.addElement(new FileNode(sub.getName(), this, sub.length(), lastModified)); 1048 1049 if (VERBOSE) System.out.println 1050 ("ADDED FILE: " + sub.getPath() + "\t\t[" + sub.length() + "]"); 1051 } 1052 } 1053 1054 1055 // ******************************************************************************************** 1056 // ******************************************************************************************** 1057 // Returns information about the contents of the "children Vector<FileNode>" 1058 // ******************************************************************************************** 1059 // ******************************************************************************************** 1060 1061 1062 /** 1063 * This returns the number of Child-Nodes in {@code 'this'} instance of {@code FileNode}. 1064 * 1065 * <BR /><BR /><B CLASS=JDDescLabel>Non-Recursive Check:</B> 1066 * 1067 * <BR />This method is not 'recursive', which means that the integer returned by this method 1068 * is only a count of the number of <B><I>direct-descendants</I></B> of {@code 'this'} 1069 * instance. 1070 * 1071 * <BR /><BR />Another way of saying this is that all it returns is the size of the internal 1072 * {@link #children} {@code Vector}. It doesn't actually enter any sub-directories to perform 1073 * this count. 1074 * 1075 * @see #numDirChildren() 1076 * @see #numFileChildren() 1077 * @see #children 1078 * 1079 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is not a 1080 * directory, but rather a file, then this exception is thrown. (Files <I>may not</I> have 1081 * child-nodes, only directories may have them). 1082 */ 1083 public int numChildren() { DirExpectedException.check(this); return children.size(); } 1084 1085 /** 1086 * This returns the exact number of Child-Nodes of {@code 'this'} instance of {@code FileNode} 1087 * which are <B>directories</B>. 1088 * 1089 * <BR /><BR /><B CLASS=JDDescLabel>Non-Recursive Check:</B> 1090 * 1091 * <BR />This method is not 'recursive', which means that the integer returned by this method 1092 * is only a count of the number of <B><I>direct-descendants</I></B> of {@code 'this'} 1093 * instance. 1094 * 1095 * <BR /><BR />This method performs a count on the elements of the internal {@link #children} 1096 * {@code Vector} to see how many elements have an {@link #isDirectory} field set to 1097 * {@code TRUE}. 1098 * 1099 * @see #numFileChildren() 1100 * @see #numChildren() 1101 * @see #children 1102 * 1103 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is not a 1104 * directory, but rather a file, then this exception is thrown. (Files <I>may not</I> have 1105 * child-nodes, only directories may have them). 1106 */ 1107 public int numDirChildren() 1108 { 1109 DirExpectedException.check(this); 1110 1111 int dirCount = 0; 1112 1113 for (int i=0; i < children.size(); i++) if (children.elementAt(i).isDirectory) dirCount++; 1114 1115 return dirCount; 1116 } 1117 1118 /** 1119 * This returns the exact number of Child-Nodes of {@code 'this'} instance of {@code FileNode} 1120 * which are <B>files</B>. 1121 * 1122 * <BR /><BR /><B CLASS=JDDescLabel>Non-Recursive Check:</B> 1123 * 1124 * <BR />This method is not 'recursive', which means that the integer returned by this method 1125 * is only a count of the number of <B><I>direct-descendants</I></B> of {@code 'this'} 1126 * instance. 1127 * 1128 * <BR /><BR />This method performs a count on the elements of the internal {@link #children} 1129 * {@code Vector} to see how many elements have an {@link #isDirectory} field set to 1130 * {@code FALSE}. 1131 * 1132 * @see #numDirChildren() 1133 * @see #numChildren() 1134 * @see #isDirectory 1135 * @see #children 1136 * 1137 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is not a 1138 * directory, but rather a file, then this exception is thrown. (Files <I>may not</I> have 1139 * child-nodes, only directories may have them). 1140 */ 1141 public int numFileChildren() 1142 { 1143 DirExpectedException.check(this); 1144 1145 int fileCount = 0; 1146 1147 for (int i=0; i < children.size(); i++) 1148 if (! children.elementAt(i).isDirectory) 1149 fileCount++; 1150 1151 return fileCount; 1152 } 1153 1154 1155 // ******************************************************************************************** 1156 // ******************************************************************************************** 1157 // Print Tree - self explanatory 1158 // ******************************************************************************************** 1159 // ******************************************************************************************** 1160 1161 1162 /** 1163 * Convenience Method. 1164 * <BR />Passes: {@code System.out} to {@code Appendable}, and nulls 1165 * <BR />Invokes: {@link #printTree(Appendable, boolean, FileNodeFilter, FileNodeFilter)} 1166 * <BR />Catches: {@code Appendable's IOException}. Prints Stack Trace. 1167 */ 1168 public void printTree() 1169 { 1170 try 1171 { printTree(System.out, false, null, null); } 1172 1173 catch (IOException e) 1174 { e.printStackTrace(); } 1175 } 1176 1177 /** 1178 * Convenience Method. 1179 * <BR />Passes: 'null' to {@code Appendable} parameter (uses {@code System.out}) 1180 * <BR />Invokes: {@link #printTree(Appendable, boolean, FileNodeFilter, FileNodeFilter)} 1181 * <BR />Catches: {@code Appendable's IOException} 1182 */ 1183 public void printTreeNOIOE 1184 (boolean showSizes, FileNodeFilter fileTest, FileNodeFilter directoryTest) 1185 { try { printTree(null, showSizes, fileTest, directoryTest); } catch (IOException ioe) { } } 1186 1187 /** 1188 * This will print the directory tree to the {@code java.lang.Appendable} passed as a 1189 * parameter. Specific Test-{@code Predicate's} may be sent to this method to identify which 1190 * branches of the File-System Directory-Tree should be printed. 1191 * 1192 * @param a If this is null, then {@code System.out} is used. If it is not null, then 1193 * information is printed to this Java {@code java.lang.Appendable}. 1194 * 1195 * <EMBED CLASS='external-html' DATA-FILE-ID=APPENDABLE> 1196 * 1197 * @param showSizes If this is true, then "file-size" information will also be printed with the 1198 * file. 1199 * 1200 * @param fileTest If this is null, then it is ignored, and all <B>files</B> in the 1201 * {@code FileNode} Directory-Tree pass (are accepted). 1202 * 1203 * <BR /><BR />If this parameter is not null, then each {@code FileNode} that is not a 1204 * directory is run through this {@code Predicate's} test method. If the test returns 1205 * {@code FALSE}, then this file is not printed to the output. 1206 * 1207 * @param directoryTest If this is null, then it is ignored, and all <B>directories</B> in 1208 * the {@code FileNode} Directory-Tree pass (are accepted). 1209 * 1210 * <BR /><BR />If this parameter is not null, then each {@code FileNode} that is a directory is 1211 * run through this {@code Predicate's} test method, and any directories that fail this 1212 * {@code Predicate's test()} method (when {@code directoryTest.test(dir)} returns 1213 * {@code FALSE}), that directory will not be printed to the output. 1214 * 1215 * @throws IOException Java's {@code interface Appendable} mandates that the unchecked Java 1216 * {@code IOException} must be caught when using this interface. 1217 * 1218 * @see #printTree() 1219 * @see #getDirContentsFiles() 1220 * @see #getDirContentsDirs() 1221 * @see #fileSize 1222 * @see #getFullPathName 1223 */ 1224 public void printTree 1225 (Appendable a, boolean showSizes, FileNodeFilter fileTest, FileNodeFilter directoryTest) 1226 throws IOException 1227 { 1228 if (a == null) a = System.out; 1229 1230 for (FileNode file : getDirContentsFiles(fileTest)) 1231 a.append((showSizes ? (file.fileSize + ",\t") : "") + file.getFullPathName() + '\n'); 1232 1233 for (FileNode dir : getDirContentsDirs(directoryTest)) 1234 { 1235 a.append(dir.getFullPathName() + '\n'); 1236 dir.printTree(a, showSizes, fileTest, directoryTest); 1237 } 1238 } 1239 1240 1241 // ******************************************************************************************** 1242 // ******************************************************************************************** 1243 // These check the size of a directory's contents. The perform the sums using recursion 1244 // ******************************************************************************************** 1245 // ******************************************************************************************** 1246 1247 1248 /** 1249 * Convenience Method. 1250 * <BR />Invokes: {@link #getDirContentsSize(FileNodeFilter)} 1251 * <BR />Passes: null to filter-parameter {@code 'fileTest'}. (All file-sizes are counted) 1252 */ 1253 public long getDirContentsSize() 1254 { return getDirContentsSize(null); } 1255 1256 /** 1257 * This sums the file-sizes of each file <B>in the current directory, not sub-directories</B> 1258 * that pass the requirements of the {@code Predicate<FileNode>} here. If 1259 * {@code p.test(fileNode)} fails, then the size of a {@code FileNode} is not counted in the 1260 * total sum. 1261 * 1262 * <BR /><BR /><B CLASS=JDDescLabel>Non-Recursive Method:</B> 1263 * 1264 * <BR />This only retrieves the contents of {@code 'this'} directory - and does not expand or 1265 * visit any sub-directories - when computing the total size of the files! 1266 * 1267 * @param fileTest Any Java Lambda-Expression that satisfies the requirement of having a 1268 * {@code public boolean test(FileNode); } method. An instance of the interface 1269 * {@code 'FileNodeFilter'} will also work. 1270 * 1271 * <BR /><BR />This is used to "test" whether to include the files in a directory' 1272 * {@link #fileSize} in the summed return value. When {@code TRUE} is returned by the 1273 * {@code Predicate test(...)} method, a file's size will be included in the sum-total 1274 * directory-size. When the {@code Predicate test(...)} method returns {@code FALSE}, the 1275 * tested file's size will be ignored and not included in the total. 1276 * 1277 * <BR /><BR />This may be null, and if it is, it is ignored. This means that file-sizes for 1278 * all files in the directory will count towards the total-size returned by this method. 1279 * 1280 * @return The sum of file-sizes for each file which passes the {@code Predicate} test in this 1281 * directory. 1282 * 1283 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is not a 1284 * directory, but rather a file, then this exception is thrown. (Files <I>may not</I> have 1285 * child-nodes, only directories). 1286 * 1287 * @see #fileSize 1288 * @see #children 1289 * @see #isDirectory 1290 */ 1291 public long getDirContentsSize(FileNodeFilter fileTest) 1292 { 1293 DirExpectedException.check(this); 1294 1295 long size=0; 1296 1297 for (FileNode f : children) 1298 if (! f.isDirectory) 1299 if ((fileTest == null) || fileTest.test(f)) 1300 size += f.fileSize; 1301 1302 return size; 1303 } 1304 1305 /** 1306 * Convenience Method. 1307 * <BR />Invokes: {@link #getDirTotalContentsSize(FileNodeFilter, FileNodeFilter)} 1308 * <BR />Passes: null to both-filters (all file-sizes counted, no directories skipped) 1309 */ 1310 public long getDirTotalContentsSize() 1311 { return getDirTotalContentsSize(null, null); } 1312 1313 /** 1314 * This sums the file contents in the current directory - and all sub-directories as well. 1315 * Only files that pass the {@code Predicate 'fileTest'} parameter are counted. Furthermore, 1316 * only directories that pass the {@code Predicate 'directoryTest'} will be traversed and 1317 * inspected. 1318 * 1319 * <BR /><BR /><B CLASS=JDDescLabel>Recursive Method:</B> 1320 * 1321 * <BR />This method computes the sizes of the files, recursively. Tbis method enters 1322 * sub-directories (provided they pass the {@code 'directoryTest'}) to compute the total file 1323 * size. 1324 * 1325 * @param fileTest Any Java Lambda-Expression that satisfies the requirement of having a 1326 * {@code public boolean test(FileNode); } method. An instance of the interface 1327 * {@code 'FileNodeFilter'} will also work. 1328 * 1329 * <BR /><BR />This is used to "test" whether to include the {@link #fileSize} for a specific 1330 * file in a directory in the summed return value. When {@code TRUE} is returned by the 1331 * {@code Predicate 'test'} method, a file's size will be included in the sum-total 1332 * directory-size. When the {@code Predicate 'test'} method returns {@code FALSE}, the tested 1333 * file's size will be ignored, and not included in the total. 1334 * 1335 * <BR /><BR />This may be null, and if it is, it is ignored. This means that file-sizes for 1336 * all files in the directory will count towards the total-size returned by this method. 1337 * 1338 * @param directoryTest Any Java Lambda-Expression that satisfies the requirement of having a 1339 * {@code public boolean test(FileNode); } method. An instance of the interface 1340 * {@code 'FileNodeFilter'} will also work. 1341 * 1342 * <BR /><BR />This is used to test directories, rather than files, for inclusion in the total 1343 * file-size returned by this method. When {@code TRUE} is returned by the filter's 1344 * {@code 'test'} method, then that directory shall be traversed, inspected, and its contents 1345 * shall have their {@code fileSize's} included in the computed result. 1346 * 1347 * <BR /><BR />This parameter may be null, and if it is, it is ignored. This would mean that 1348 * all sub-directories shall be traversed when computing the total directory size. 1349 * 1350 * @return The sum of all file-sizes for each file in this directory that pass 1351 * {@code 'fileTest'}, and all sub-dir's that pass the {@code 'directoryTest'}. 1352 * 1353 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is not a 1354 * directory, but rather a file, then this exception is thrown. (Files <I>may not</I> have 1355 * child-nodes, only directories). 1356 ( 1357 * @see #fileSize 1358 * @see #children 1359 * @see #getDirTotalContentsSize() 1360 */ 1361 public long getDirTotalContentsSize(FileNodeFilter fileTest, FileNodeFilter directoryTest) 1362 { 1363 DirExpectedException.check(this); 1364 1365 long size=0; 1366 1367 for (FileNode f : children) 1368 1369 if (f.isDirectory) 1370 { 1371 if ((directoryTest == null) || directoryTest.test(f)) 1372 size += f.getDirTotalContentsSize(fileTest, directoryTest); 1373 } 1374 1375 else 1376 { 1377 if ((fileTest == null) || fileTest.test(f)) 1378 size += f.fileSize; 1379 } 1380 1381 return size; 1382 } 1383 1384 1385 // ******************************************************************************************** 1386 // ******************************************************************************************** 1387 // These count files and sub-directories 1388 // ******************************************************************************************** 1389 // ******************************************************************************************** 1390 1391 1392 /** 1393 * Convenience Method. 1394 * <BR />Invokes: {@link #count(FileNodeFilter, FileNodeFilter)} 1395 * <BR />Passes: null to both filter-parameters. (All files and directories are counted) 1396 */ 1397 public int count() { return count(null, null); } 1398 1399 /** 1400 * Performs a count on the total number of files and directories contained by {@code 'this'} 1401 * directory. This method is recursive, and traverses both {@code 'this'} directory, and all 1402 * sub-directories when calculating the return-value. 1403 * 1404 * @param fileFilter This allows a user to eliminate certain files from the total count. 1405 * 1406 * <BR /><BR />The filter provided should be a {@code Predicate<FileNode>} that returns 1407 * {@code TRUE} if the file <I>should be counted</I>, and {@code FALSE} if the file <I>should 1408 * <B>not</B></I> be counted. 1409 * 1410 * <BR /><BR />This parameter may be {@code 'null'}, and if it is, it will be ignored. In 1411 * such cases, all files will be included in the total count. 1412 * 1413 * @param directoryFilter This allows a user to skip branches of the directory-tree when 1414 * performing the count. 1415 * 1416 * <BR /><BR />The filter provided should be a {@code Predicate<FileNode>} that returns 1417 * {@code TRUE} if the sub-directory <I>should be entered</I> (and counted), and {@code FALSE} 1418 * if the sub-directory tree-branch <I>should be skipped</I> completely. 1419 * 1420 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_COUNT_DIRFILT> 1421 * 1422 * @return A total count of all files and sub-directories contained by {@code 'this'} instance 1423 * of {@code FileNode} - less the files and directory-tree branches that were excluded by the 1424 * filters that may or may not have been passed to this method. 1425 * 1426 * @throws DirExpectedException If the user has attempted to perform a count on a 1427 * {@code FileNode} that is a 'file' rather than a 'directory'. 1428 */ 1429 public int count(FileNodeFilter fileFilter, FileNodeFilter directoryFilter) 1430 { 1431 DirExpectedException.check(this); 1432 1433 // This was moved to an "INTERNAL" method to avoid invoking the above exception check 1434 // every time this (recursive) code encounters a directory. 1435 1436 return countINTERNAL(fileFilter, directoryFilter); 1437 } 1438 1439 private int countINTERNAL(FileNodeFilter fileFilter, FileNodeFilter directoryFilter) 1440 { 1441 int count = 0; 1442 1443 for (FileNode fn : children) 1444 1445 if (fn.isDirectory) 1446 { 1447 if ((directoryFilter == null) || directoryFilter.test(fn)) 1448 count += 1 /* 'this' adds 1 */ + fn.countINTERNAL(fileFilter, directoryFilter); 1449 } 1450 else 1451 if ((fileFilter == null) || fileFilter.test(fn)) 1452 count++; 1453 1454 return count; 1455 } 1456 1457 /** 1458 * Convenience Method. 1459 * <BR />Invokes: {@link #countJustFiles(FileNodeFilter, FileNodeFilter)} 1460 * <BR />Passes: null to both filter-parameters 1461 * (all <B>files</B> counted, no directories skipped). 1462 */ 1463 public int countJustFiles() { return countJustFiles(null, null); } 1464 1465 /** 1466 * Performs a count on the total number of <I><B>files only</I></B> (does not count sub 1467 * directories) contained by {@code 'this'} directory. This method is recursive, and traverses 1468 * both {@code 'this'} directory, and all sub-directories when calculating the return-value. 1469 * 1470 * @param fileFilter This allows a user to eliminate certain files from the total count. 1471 * 1472 * <BR /><BR />The filter provided should be a {@link FileNodeFilter} (Predicate} / 1473 * Lambda-Expression that returns {@code TRUE} if the file <I>should be counted</I>, and 1474 * {@code FALSE} if the file <I>should <B>not</B></I> be counted. 1475 * 1476 * <BR /><BR />This parameter may be {@code 'null'}, and if it is, it will be ignored. In 1477 * such cases, all files will be included in the total count. 1478 * 1479 * @param directoryFilter This allows a user to skip branches of the directory-tree when 1480 * performing the count. 1481 * 1482 * <BR /><BR />The filter provided should be a {@link FileNodeFilter} (Predicate} / 1483 * Lambda-Expression that returns {@code TRUE} if the sub-directory <I>should be entered</I> 1484 * (the directory itself will not contribute to the count). When this filter returns 1485 * {@code FALSE} the sub-directory tree-branch <I>will be skipped</I> completely, and any files 1486 * in those sub-directories will not contribute to the total file-count. 1487 * 1488 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_COUNT_DIRFILT> 1489 * 1490 * @return A total count of all files (excluding sub-directories) contained by {@code 'this'} 1491 * instance of {@code FileNode} - less the files that reside in directory-tree branches that 1492 * were excluded by the {@code 'directoryFilter'} parameter <B><I>and</I></B> less the files 1493 * that were excluded by {@code 'fileFilter'}. 1494 * 1495 * @throws DirExpectedException If the user has attempted to perform a count on a 1496 * {@code FileNode} that is a 'file' rather than a 'directory'. 1497 */ 1498 public int countJustFiles(FileNodeFilter fileFilter, FileNodeFilter directoryFilter) 1499 { 1500 DirExpectedException.check(this); 1501 1502 // This was moved to an "INTERNAL" method to avoid invoking the above exception check 1503 // every time this (recursive) code encounters a directory. 1504 1505 return countJustFilesINTERNAL(fileFilter, directoryFilter); 1506 } 1507 1508 private int countJustFilesINTERNAL(FileNodeFilter fileFilter, FileNodeFilter directoryFilter) 1509 { 1510 int count = 0; 1511 1512 for (FileNode fn : children) 1513 1514 if (fn.isDirectory) 1515 { 1516 if ((directoryFilter == null) || directoryFilter.test(fn)) 1517 count += fn.countJustFilesINTERNAL(fileFilter, directoryFilter); 1518 } 1519 1520 else // fn is a file, not a dir. 1521 if ((fileFilter == null) || fileFilter.test(fn)) 1522 count++; 1523 1524 return count; 1525 } 1526 1527 /** 1528 * Convenience Method. 1529 * <BR />Invokes: {@link #countJustDirs(FileNodeFilter)} 1530 * <BR />Passes: null to {@code 'directorFilter'} (all <B>directories</B> are counted). 1531 */ 1532 public int countJustDirs() { return countJustDirs(null); } 1533 1534 /** 1535 * Performs a count on the total number of sub-directories contained by {@code 'this'} 1536 * directory. This method is recursive, and traverses all sub-directories when calculating 1537 * the return-value. 1538 * 1539 * @param directoryFilter This allows a user to skip branches of the directory-tree when 1540 * performing the count. 1541 * 1542 * <BR /><BR />The filter provided should be a {@link FileNodeFilter} (Predicate} / 1543 * Lambda-Expression that returns {@code TRUE} if the sub-directory <I>should be entered</I> 1544 * and {@code FALSE} if sub-directory tree-branch <I>should be skipped</I> completely. 1545 * 1546 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_COUNT_DIRFILT> 1547 * 1548 * @return A total count of all sub-directories contained by {@code 'this'} 1549 * instance of {@code FileNode} - less the sub-directories that reside in directory-tree 1550 * branches that were excluded by the {@code 'directoryFilter'} parameter. 1551 * 1552 * @throws DirExpectedException If the user has attempted to perform a count on a 1553 * {@code FileNode} that is a 'file' rather than a 'directory'. 1554 */ 1555 public int countJustDirs(FileNodeFilter directoryFilter) 1556 { 1557 DirExpectedException.check(this); 1558 1559 // This was moved to an "INTERNAL" method to avoid invoking the above exception check 1560 // every time this (recursive) code encounters a directory. 1561 1562 return countJustDirsINTERNAL(directoryFilter); 1563 } 1564 1565 private int countJustDirsINTERNAL 1566 (FileNodeFilter directoryFilter) 1567 { 1568 int count = 0; 1569 1570 if (directoryFilter == null) 1571 1572 for (FileNode fn1 : children) 1573 if (fn1.isDirectory) 1574 count += 1 /* 'this' adds 1 */ + fn1.countJustDirsINTERNAL(directoryFilter); 1575 1576 else 1577 1578 for (FileNode fn2 : children) 1579 if (fn2.isDirectory) 1580 if (directoryFilter.test(fn2)) 1581 count +=1 /* 'this' adds 1 */ + fn2.countJustDirsINTERNAL(directoryFilter); 1582 1583 return count; 1584 } 1585 1586 1587 // ******************************************************************************************** 1588 // ******************************************************************************************** 1589 // ALL - a single level in the file-tree. 1590 // ******************************************************************************************** 1591 // ******************************************************************************************** 1592 1593 1594 /** 1595 * Convenience Method. 1596 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1597 * <BR />Invokes: {@link #getDirContents(RetTypeChoice, FileNodeFilter)} 1598 * <BR />Passes: null to parameter {@code 'filter'} 1599 * (all files and directories found will be returned). 1600 */ 1601 public Vector<FileNode> getDirContents() 1602 { return getDirContents(RetTypeChoice.VECTOR, null); } 1603 1604 /** 1605 * Convenience Method. 1606 * <BR />Accepts: {@link RetTypeChoice}. (Specifies Output Data-Structure & Contents) 1607 * <BR />Invokes: {@link #getDirContents(RetTypeChoice, FileNodeFilter)} 1608 * <BR />Passes: null to parameter {@code 'filter'} 1609 * (all files and directories found will be returned). 1610 */ 1611 public <T> T getDirContents(RetTypeChoice<T> listChoice) 1612 { return getDirContents(listChoice, null); } 1613 1614 /** 1615 * Convenience Method. 1616 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1617 * <BR />Accepts: {@link FileNodeFilter} 1618 * <BR />Invokes: {@link #getDirContents(RetTypeChoice, FileNodeFilter)} 1619 */ 1620 public Vector<FileNode> getDirContents(FileNodeFilter filter) 1621 { return getDirContents(RetTypeChoice.VECTOR, filter); } 1622 1623 /** 1624 * This method returns the contents of a <I>single-directory in the directory-tree</I>, the 1625 * sub-directories are returned, but the contents of the sub-directories are not. Any method 1626 * whose name begins with {@code 'getDirContents ...'} will not traverse the directory tree. 1627 * Instead, <I>only the contents of the internal {@code 'children' Vector<FileNode>} of 1628 * {@code 'this'} instance of {@code FileNode} are iterated and returned.</I> 1629 * 1630 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_DIR_CONTENTS> 1631 * 1632 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_TYPE_PARAM> 1633 * 1634 * @param listChoice <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_PARAM> 1635 * 1636 * @param filter When this parameter is used, any files or directories that do not pass the 1637 * {@code filter's 'test'} method shall not be included in the returne data-structure. 1638 * 1639 * <BR /><BR />The {@code filter} that is passed should return {@code TRUE} when a file or 1640 * directory needs to be included in the returned-result. When the provided {@code filter} 1641 * returns {@code FALSE} as a result of testing a file or directory, the returned 1642 * Data-Structure will exclude it. 1643 * 1644 * <BR /><BR />If this parameter is null, it will be ignored, and every {@code FileNode} 1645 * contained by {@code 'this'} directory-instance will be included in the result. 1646 * 1647 * @return A list containing the files & sub-directories inside {@code 'this'} directory. 1648 * 1649 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_RET> 1650 * 1651 * @throws DirExpectedException <EMBED CLASS='external-html' DATA-FILE-ID=FN_DIR_C_DIR_EXP_EX> 1652 * 1653 * @see FileNodeFilter 1654 * 1655 * @see #children 1656 */ 1657 public <T> T getDirContents(RetTypeChoice<T> listChoice, FileNodeFilter filter) 1658 { 1659 DirExpectedException.check(this); 1660 1661 VarList<T, FileNode> ret = listChoice.varList.create(); 1662 1663 children.forEach 1664 ((FileNode fn) -> { if ((filter == null) || filter.test(fn)) ret.insert(fn); }); 1665 1666 return ret.retrieve(); 1667 } 1668 1669 1670 // ******************************************************************************************** 1671 // ******************************************************************************************** 1672 // DIRECTORIES - a single level in the file-tree. 1673 // ******************************************************************************************** 1674 // ******************************************************************************************** 1675 1676 1677 /** 1678 * Convenience Method. 1679 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1680 * <BR />Invokes: {@link #getDirContentsDirs(RetTypeChoice, FileNodeFilter)} 1681 * <BR />Passes: null to parameter {@code 'filter'} (all directories found are returned). 1682 */ 1683 public Vector<FileNode> getDirContentsDirs() 1684 { return getDirContentsDirs(RetTypeChoice.VECTOR, null); } 1685 1686 /** 1687 * Convenience Method. 1688 * <BR />Accepts: {@link RetTypeChoice} (Specifies Output Data-Structure & Contents) 1689 * <BR />Invokes: {@link #getDirContentsDirs(RetTypeChoice, FileNodeFilter)} 1690 * <BR />Passes: null to parameter {@code 'filter'} (all directories found are returned). 1691 */ 1692 public <T> T getDirContentsDirs(RetTypeChoice<T> listChoice) 1693 { return getDirContentsDirs(listChoice, null); } 1694 1695 /** 1696 * Convenience Method. 1697 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1698 * <BR />Accepts: {@link FileNodeFilter} 1699 * <BR />Invokes: {@link #getDirContentsDirs(RetTypeChoice, FileNodeFilter)} 1700 */ 1701 public Vector<FileNode> getDirContentsDirs(FileNodeFilter filter) 1702 { return getDirContentsDirs(RetTypeChoice.VECTOR, filter); } 1703 1704 /** 1705 * <EMBED CLASS='external-html' DATA-INCL=directories DATA-EXCL=files 1706 * DATA-FILE-ID=FN_DIR_CONTENTS_2> 1707 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_DIR_CONTENTS> 1708 * 1709 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_TYPE_PARAM> 1710 * 1711 * @param listChoice <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_PARAM> 1712 * 1713 * @param filter Any Lambda-Expression that will select directories to include in the 1714 * return Data-Structure. This parameter may be null, and if it is it will be ignored and all 1715 * sub-directories will be added to the return-instance. 1716 * 1717 * @return A list containing sub-directories rooted at {@code 'this'} directory. 1718 * 1719 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_RET> 1720 * 1721 * @throws DirExpectedException <EMBED CLASS='external-html' DATA-FILE-ID=FN_DIR_C_DIR_EXP_EX> 1722 * 1723 * @see FileNodeFilter 1724 * @see #isDirectory 1725 */ 1726 public <T> T getDirContentsDirs(RetTypeChoice<T> listChoice, FileNodeFilter filter) 1727 { 1728 FileNodeFilter dirFilter = (FileNode fn) -> fn.isDirectory; 1729 return getDirContents(listChoice, (filter != null) ? filter.and(dirFilter) : dirFilter); 1730 } 1731 1732 1733 // ******************************************************************************************** 1734 // ******************************************************************************************** 1735 // FILES - a single level in the file-tree. 1736 // ******************************************************************************************** 1737 // ******************************************************************************************** 1738 1739 1740 /** 1741 * Convenience Method. 1742 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1743 * <BR />Invokes: {@link #getDirContentsFiles(RetTypeChoice, FileNodeFilter)} 1744 * <BR />Passes: null to parameter {@code 'filter'} (all files found are returned). 1745 */ 1746 public Vector<FileNode> getDirContentsFiles() 1747 { return getDirContentsFiles(RetTypeChoice.VECTOR, null); } 1748 1749 /** 1750 * Convenience Method. 1751 * <BR />Accepts: {@link RetTypeChoice} (Specifies Output Data-Structure & Contents) 1752 * <BR />Invokes: {@link #getDirContentsFiles(RetTypeChoice, FileNodeFilter)} 1753 * <BR />Passes: null to parameter {@code 'filter'} (all files found are returned). 1754 */ 1755 public <T> T getDirContentsFiles(RetTypeChoice<T> listChoice) 1756 { return getDirContentsFiles(listChoice, null); } 1757 1758 /** 1759 * Convenience Method. 1760 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1761 * <BR />Accepts: {@link FileNodeFilter} 1762 * <BR />Invokes: {@link #getDirContentsFiles(RetTypeChoice, FileNodeFilter)} 1763 */ 1764 public Vector<FileNode> getDirContentsFiles(FileNodeFilter filter) 1765 { return getDirContentsFiles(RetTypeChoice.VECTOR, filter); } 1766 1767 /** 1768 * <EMBED CLASS='external-html' DATA-INCL=files DATA-EXCL=directories 1769 * DATA-FILE-ID=FN_DIR_CONTENTS_2> 1770 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_DIR_CONTENTS> 1771 * 1772 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_TYPE_PARAM> 1773 * 1774 * @param listChoice <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_PARAM> 1775 * 1776 * @param filter Any Lambda-Expression that will select files to include in the return 1777 * Data-Structure. This parameter may be null, and if it is it will be ignored and all files 1778 * will be added to the return-instance. 1779 * 1780 * @return A {@code Vector} that contains the files inside the current directory. 1781 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_RET> 1782 * 1783 * @throws DirExpectedException <EMBED CLASS='external-html' DATA-FILE-ID=FN_DIR_C_DIR_EXP_EX> 1784 * 1785 * @see FileNodeFilter 1786 * @see #isDirectory 1787 */ 1788 public <T> T getDirContentsFiles(RetTypeChoice<T> listChoice, FileNodeFilter filter) 1789 { 1790 FileNodeFilter fileFilter = (FileNode fn) -> ! fn.isDirectory; 1791 1792 return getDirContents 1793 (listChoice, (filter != null) ? filter.and(fileFilter) : fileFilter); 1794 } 1795 1796 1797 // ******************************************************************************************** 1798 // ******************************************************************************************** 1799 // FLATTEN - Just Directories 1800 // ******************************************************************************************** 1801 // ******************************************************************************************** 1802 1803 1804 /** 1805 * Convenience Method. 1806 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1807 * <BR />Invokes: 1808 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1809 * <BR />Parameter: {@code 'includeDirectoriesInResult'} set {@code TRUE} 1810 * <BR />Parameter: {@code 'includeFilesInResult'} set {@code FALSE} 1811 * <BR />Passes: null to both filter-parameters (all files & directories are returned) 1812 */ 1813 public Vector<FileNode> flattenJustDirs() 1814 { return flatten(RetTypeChoice.VECTOR, -1, null, false, null, true); } 1815 1816 /** 1817 * Convenience Method. 1818 * <BR />Accepts: {@link RetTypeChoice} (Specifies Output Data-Structure & Contents) 1819 * <BR />Invokes: 1820 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1821 * <BR />Parameter: {@code 'includeDirectoriesInResult'} set {@code TRUE} 1822 * <BR />Parameter: {@code 'includeFilesInResult'} set {@code FALSE} 1823 * <BR />Passes: null to both filter-parameters (all directories are returned by this method). 1824 */ 1825 public <T> T flattenJustDirs(RetTypeChoice<T> listChoice) 1826 { return flatten(listChoice, -1, null, false, null, true); } 1827 1828 /** 1829 * Convenience Method. 1830 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1831 * <BR />Invokes: 1832 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1833 * <BR />Parameter: {@code 'includeDirectoriesInResult'} set {@code TRUE} 1834 * <BR />Parameter: {@code 'includeFilesInResult'} set {@code FALSE} 1835 * <BR />Accepts: {@code 'directoryFilter'} parameter. 1836 */ 1837 public Vector<FileNode> flattenJustDirs(int maxTreeDepth, FileNodeFilter directoryFilter) 1838 { return flatten(RetTypeChoice.VECTOR, maxTreeDepth, null, false, directoryFilter, true); } 1839 1840 /** 1841 * Convenience Method. 1842 * <BR />Accepts: {@link RetTypeChoice} (Specifies Output Data-Structure & Contents) 1843 * <BR />Invokes: 1844 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1845 * <BR />Parameter: {@code 'includeDirectoriesInResult'} set {@code TRUE} 1846 * <BR />Parameter: {@code 'includeFilesInResult'} set {@code FALSE} 1847 * <BR />Accepts: {@code 'directoryFilter'} parameter 1848 */ 1849 public <T> T flattenJustDirs 1850 (RetTypeChoice<T> listChoice, int maxTreeDepth, FileNodeFilter directoryFilter) 1851 { return flatten(listChoice, maxTreeDepth, null, false, directoryFilter, true); } 1852 1853 1854 // ******************************************************************************************** 1855 // ******************************************************************************************** 1856 // FLATTEN - Just Files 1857 // ******************************************************************************************** 1858 // ******************************************************************************************** 1859 1860 1861 /** 1862 * Convenience Method. 1863 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1864 * <BR />Invokes: 1865 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1866 * <BR />Parameter: {@code includeDirectoriesInResult} set {@code FALSE} 1867 * <BR />Parameter: {@code includeFilesInResult} set {@code TRUE} 1868 * <BR />Passes: null to both filter-parameters (all files are returned) 1869 */ 1870 public Vector<FileNode> flattenJustFiles() 1871 { return flatten(RetTypeChoice.VECTOR, -1, null, true, null, false); } 1872 1873 /** 1874 * Convenience Method. 1875 * <BR />Accepts: {@link RetTypeChoice} (Specifies Output Data-Structure & Contents) 1876 * <BR />Invokes: 1877 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1878 * <BR />Parameter: {@code includeDirectoriesInResult} set {@code FALSE} 1879 * <BR />Parameter: {@code includeFilesInResult} set {@code TRUE} 1880 * <BR />Passes: null to both filter-parameters (all files are returned) 1881 */ 1882 public <T> T flattenJustFiles(RetTypeChoice<T> listChoice) 1883 { return flatten(listChoice, -1, null, true, null, false); } 1884 1885 /** 1886 * Convenience Method. 1887 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1888 * <BR />Invokes: 1889 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1890 * <BR />Parameter: {@code includeDirectoriesInResult} set {@code FALSE} 1891 * <BR />Parameter: {@code includeFilesInResult} set {@code TRUE} 1892 * <BR />Accepts: {@code 'fileFilter'} parameter 1893 */ 1894 public Vector<FileNode> flattenJustFiles(int maxTreeDepth, FileNodeFilter fileFilter) 1895 { return flatten(RetTypeChoice.VECTOR, maxTreeDepth, fileFilter, true, null, false); } 1896 1897 /** 1898 * Convenience Method. 1899 * <BR />Accepts: {@link RetTypeChoice} (Specifies Output Data-Structure & Contents) 1900 * <BR />Invokes: 1901 * {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, boolean)} 1902 * <BR />Parameter: {@code includeDirectoriesInResult} set {@code FALSE} 1903 * <BR />Parameter: {@code includeFilesInResult} set {@code TRUE} 1904 */ 1905 public <T> T flattenJustFiles 1906 (RetTypeChoice<T> listChoice, int maxTreeDepth, FileNodeFilter fileFilter) 1907 { return flatten(listChoice, maxTreeDepth, fileFilter, true, null, false); } 1908 1909 1910 // ******************************************************************************************** 1911 // ******************************************************************************************** 1912 // Core Flatten Routines 1913 // ******************************************************************************************** 1914 // ******************************************************************************************** 1915 1916 1917 /** 1918 * Convenience Method. 1919 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1920 * <BR />Invokes: {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, 1921 * boolean)} 1922 * <BR />Parameters: {@code includeFilesInResult, includeDirectoriesInResult} both set 1923 * {@code TRUE} 1924 * <BR />Passes: null to both filter-parameers (all files & directories are returned) 1925 */ 1926 public Vector<FileNode> flatten() 1927 { return flatten(RetTypeChoice.VECTOR, -1, null, true, null, true); } 1928 1929 /** 1930 * Convenience Method. 1931 * <BR />Accepts: {@link RetTypeChoice} (Specifies Output Data-Structure & Contents) 1932 * <BR />Invokes: {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, 1933 * boolean)} 1934 * <BR />Parameters: {@code includeFilesInResult, includeDirectoriesInResult} both set 1935 * {@code TRUE} 1936 * <BR />Passes: null to both filter-parameers (all files & directories are returned) 1937 */ 1938 public <T> T flatten(RetTypeChoice<T> listChoice) 1939 { return flatten(listChoice, -1, null, true, null, true); } 1940 1941 /** 1942 * Convenience Method. 1943 * <BR />Automatically Selects: {@link RetTypeChoice#VECTOR} 1944 * <BR />Invokes: {@link #flatten(RetTypeChoice, int, FileNodeFilter, boolean, FileNodeFilter, 1945 * boolean)} 1946 * <BR />Accepts: Both filters ({@code directoryFilter, fileFilter}) may be passed. 1947 * <BR />Accepts: Both {@code 'includeIn'} boolean-flags may be passed. 1948 */ 1949 public Vector<FileNode> flatten( 1950 int maxTreeDepth, 1951 FileNodeFilter fileFilter, boolean includeFilesInResult, 1952 FileNodeFilter directoryFilter, boolean includeDirectoriesInResult) 1953 { 1954 return flatten(RetTypeChoice.VECTOR, maxTreeDepth, 1955 fileFilter, includeFilesInResult, 1956 directoryFilter, includeDirectoriesInResult 1957 ); 1958 } 1959 1960 /** 1961 * This flattens the {@code FileNode} tree into a data-structure of your choosing. Review 1962 * & read the parameter explanations below, closely, to see what the specifiers do. 1963 * 1964 * <BR /><BR />The concept of "flatten" is identical to the concept of "retrieve" or 1965 * "search." All of these methods perform the 'copying' of a set of {@code filter}-matches 1966 * into a return-container. If one wishes to scour and search a {@code FileNode} tree to 1967 * obtain some or all Tree-Nodes for saving into a list (or other data-structure of your 1968 * choosing), this can be easily done using this method. 1969 * 1970 * <BR /><BR />Write the necessary Lambda-Expressions (filter-predicates) to choose the files 1971 * and directories that need to be included in the result-container, and then invoke any one 1972 * of the overloaded {@code flattan(...)} methods offered by this class. 1973 * 1974 * <BR /><BR />If you would like to "flatten" the entire tree into a {@code Vector} or some 1975 * other type of list or data-structure, then leave both of the {@code filter} parameters blank 1976 * (by passing them null), and also pass {@code '-1'} to parameter {@code 'maxTreeDepth'}. 1977 * Everything in the directory-tree that is rooted at {@code 'this'} instance of 1978 * {@code FileNode} is returned into a data-structure of your choosing. 1979 * 1980 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_TYPE_PARAM> 1981 * @param listChoice <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_PARAM> 1982 * @param maxTreeDepth <EMBED CLASS='external-html' DATA-FILE-ID=FN_MAX_TREE_DEPTH> 1983 * 1984 * @param fileFilter This is a Java 8 "accept" {@code interface java.util.function.Predicate}. 1985 * Implementing the {@code 'test(FileNode)'} method, allows one to pick & choose which 1986 * files will be visited as the tree is recursively traversed. Use a lambda-expression, if 1987 * needed or for convenience. 1988 * 1989 * <BR /><BR /><B>NOTE:</B> This parameter may be null, and if so - <I>all files</I> are 1990 * will be presumed to pass the {@code filter test}. 1991 * 1992 * <BR /><BR /><B><SPAN STYLE="color: red;">JAVA STREAM'S</SPAN></B> The behavior of this 1993 * {@code filter}-logic is identical to the Java 8+ Streams-Method 1994 * {@code 'filter(Predicate<...>)'}. Specifically, when the {@code filter} returns a 1995 * {@code TRUE} value for a particular {@code FileNode}, that {@code FileNode} shall be 1996 * retained, or 'kept', in the returned result-set. When the {@code filter} returns 1997 * {@code FALSE} for a {@code FileNode}, that file or directory will be removed from the 1998 * result-set. 1999 * 2000 * <BR /><BR />One way to think about which files are included in the results of a 2001 * {@code 'flatten'} operation is by this list below: 2002 * 2003 * <BR /><BR /><UL CLASS=JDUL> 2004 * <LI> Whether/if the {@code boolean includeFilesInResult} boolean-flag has been 2005 * set to {@code TRUE}. 2006 * </LI> 2007 * <LI> Whether the {@code FileNode} would pass the {@code fileFilter.test} predicate 2008 * (if one has been provided, otherwise ignore this metric). 2009 * </LI> 2010 * <LI> Whether the containing directory's {@code FileNode} would pass the 2011 * {@code directoryFilter.test} predicate (if one has been provided, otherwise ignore this 2012 * metric). 2013 * </LI> 2014 * <LI> Whether or not <I>all parent-containing directories</I> of the {@code FileNode} would 2015 * pass the {@code directoryFilter.test} predicate (if one were provided). 2016 * </LI> 2017 * </UL> 2018 * 2019 * @param includeFilesInResult If this parameter is {@code TRUE}, then files will be included 2020 * in the resulting {@code Vector}. 2021 * 2022 * <BR /><BR /><SPAN STYLE="color: red;"><B>NOTE:</B></SPAN> If this parameter is 2023 * {@code FALSE}, this value will "over-ride" any results that may be produced from the public 2024 * {@code fileFilter.test(this)} method (if such a filter had been provided). 2025 * 2026 * @param directoryFilter This is also a Java 8 "Predicate Filter" {@code interface 2027 * java.util.function.Predicate}. Implementing the {@code 'test(FileNode)'} method, allows 2028 * one to pick & choose which directories will be visited as the tree is recursively 2029 * traversed. Use a lambda-expression, if needed or for convenience. 2030 * 2031 * <BR /><BR /><B>NOTE:</B> This parameter may be null, and if so - <I>all directories</I> 2032 * will be traversed. 2033 * 2034 * <BR /><BR /><B><SPAN STYLE="color: red;">JAVA STREAM'S</SPAN></B> The behavior of this 2035 * {@code filter}-logic is identical to the Java 8+ Streams-Method 2036 * {@code 'filter(Predicate<...>)'.} Specifically, when the {@code filter} returns a 2037 * {@code TRUE} value for a particular {@code FileNode}, that {@code FileNode} shall be 2038 * retained, or 'kept', in the returned result-set. When the {@code filter} returns 2039 * {@code FALSE} for a {@code FileNode}, that file or directory will be removed from the 2040 * result-set. 2041 * 2042 * <BR /><BR /><SPAN STYLE="color: red;"><B>IMPORTANT:</B></SPAN> There is no way to 2043 * differentiate between which directories are traversed and which directories are included in 2044 * the result set - if a directory is not traversed or examined, then that directory, <I>and 2045 * any/all files and sub-directories contained by that directory</I> will all be eliminted 2046 * from the returned-results. 2047 * 2048 * <BR /><BR />One way to think about which directories are included in the results of a 2049 * {@code 'flatten'} operation is by this list below: 2050 * 2051 * <BR /><BR /><UL CLASS=JDUL> 2052 * <LI> Whether/if the {@code boolean includeDirectoriesInResult} boolean-flag has been 2053 * set to {@code TRUE}. 2054 * </LI> 2055 * <LI> Whether that {@code FileNode} would pass the {@code directoryFilter.test} predicate 2056 * (if one has been provided, otherwise ignore this metric). 2057 * </LI> 2058 * <LI> Whether or not <I>all parent directories</I> of the {@code FileNode} would also pass 2059 * the {@code directoryFilter.test} predicate (if one were provided). 2060 * </LI> 2061 * </UL> 2062 * 2063 * @param includeDirectoriesInResult If this parameter is {@code TRUE}, then directories will 2064 * be included in the resulting {@code Vector}. 2065 * 2066 * <BR /><BR /><SPAN STYLE="color: red;"><B>NOTE:</B></SPAN> If this parameter is 2067 * {@code FALSE}, this value will "over-ride" any results that may be produced from the public 2068 * {@code directoryFilter.test(this)} method. 2069 * 2070 * @return A flattened version of this tree. 2071 * 2072 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_RET> 2073 * 2074 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} is not a 2075 * directory, but a file, then this exception is thrown. (Files <I>may not</I> have 2076 * child-nodes, only directories). 2077 * 2078 * @throws IllegalArgumentException If the value of {@code 'maxTreeDepth'} is set to 2079 * {@code zero}, then this exception shall be thrown because the method-invocation would not be 2080 * making an actual request to do anything. 2081 * 2082 * <BR /><BR />This exception shall <I><B>*also* be throw if</I></B> both of the boolean 2083 * parameters are set to {@code FALSE}, for the same reason being that the method-invocation 2084 * would not be making a request. 2085 */ 2086 public <T> T flatten( 2087 RetTypeChoice<T> listChoice, 2088 int maxTreeDepth, 2089 FileNodeFilter fileFilter, boolean includeFilesInResult, 2090 FileNodeFilter directoryFilter, boolean includeDirectoriesInResult) 2091 { 2092 DirExpectedException.check(this); 2093 2094 if (maxTreeDepth == 0) throw new IllegalArgumentException( 2095 "flatten(int, FileNodeFilter, boolean, directoryFilter, boolean) has been invoked " + 2096 "with the maxTreeDepth (integer) parameter set to zero. This means that there is " + 2097 "nothing for the method to do." 2098 ); 2099 2100 if ((! includeFilesInResult) && (! includeDirectoriesInResult)) 2101 2102 throw new IllegalArgumentException( 2103 "flatten(int, FileNodeFilter, boolean, directoryFilter, boolean) has been " + 2104 "invoked with both of the two boolean search criteria values set to FALSE. " + 2105 "This means that there is nothing for the method to do." 2106 ); 2107 2108 // This allows us to permit the user to decide what type of Container and what type of 2109 // Object inside the container is returned. 2110 2111 VarList<T, FileNode> ret = listChoice.varList.create(); 2112 2113 // 'this' directory needs to be included (unless filtering directories) 2114 if ( includeDirectoriesInResult 2115 && ((directoryFilter == null) || directoryFilter.test(this)) 2116 ) 2117 ret.insert(this); 2118 2119 // Call the general-purpose flatten method. 2120 flattenINTERNAL( 2121 this, ret, fileFilter, includeFilesInResult, directoryFilter, 2122 includeDirectoriesInResult, 0, maxTreeDepth 2123 ); 2124 2125 // retrieve the Container specified by the user. 2126 return ret.retrieve(); 2127 } 2128 2129 private static void flattenINTERNAL( 2130 FileNode cur, VarList<?, FileNode> ret, 2131 FileNodeFilter fileFilter, boolean includeFilesInResult, 2132 FileNodeFilter directoryFilter, boolean includeDirectoriesInResult, 2133 int curTreeDepth, int maxTreeDepth 2134 ) 2135 { 2136 if ((maxTreeDepth >= 0) && (curTreeDepth > maxTreeDepth)) return; 2137 2138 if (VERBOSE) System.out.println(cur.name); 2139 2140 for (FileNode fn : cur.children) 2141 { 2142 if (fn.isDirectory) 2143 { 2144 if ( includeDirectoriesInResult 2145 && ((directoryFilter == null) || directoryFilter.test(fn)) 2146 ) 2147 ret.insert(fn); 2148 } 2149 2150 else /* fn.isDirectory is FALSE, and therefore this is a file! */ 2151 { 2152 if (includeFilesInResult && ((fileFilter == null) || fileFilter.test(fn))) 2153 ret.insert(fn); 2154 } 2155 } 2156 2157 for (FileNode fn : cur.children) 2158 2159 if (fn.isDirectory && ((directoryFilter == null) || directoryFilter.test(fn))) 2160 2161 flattenINTERNAL( 2162 fn, ret, fileFilter, includeFilesInResult, directoryFilter, 2163 includeDirectoriesInResult, curTreeDepth+1, maxTreeDepth 2164 ); 2165 } 2166 2167 2168 // ******************************************************************************************** 2169 // ******************************************************************************************** 2170 // Prune Tree 2171 // ******************************************************************************************** 2172 // ******************************************************************************************** 2173 2174 2175 /** 2176 * Convenience Method. 2177 * <BR />Invokes: {@link #pruneTree(FileNodeFilter, boolean)} 2178 * <BR />Returns: {@code 'this'} rather than {@code 'int'} 2179 */ 2180 public FileNode prune(FileNodeFilter fileFilter, boolean nullThePointers) 2181 { this.pruneTree(fileFilter, nullThePointers); return this; } 2182 2183 /** 2184 * This removes instances of {@code FileNode} that meet these conditions: 2185 * 2186 * <BR /><BR /><OL CLASS=JDOL> 2187 * 2188 * <LI> Are file instances, not directories. Specifically: {@code public final boolean 2189 * isDirectory == false;}<BR /> 2190 * </LI> 2191 * 2192 * <LI> Do not pass the {@code 'fileFilter.test(...)'} method. If the test method returns 2193 * {@code FALSE}, the file shall be removed from the containing directory's 2194 * {@link #children} {@code Vector<FileNode>} File-List. 2195 * </LI> 2196 * 2197 * </OL> 2198 * 2199 * <BR /><BR /><B CLASS=JDDescLabel>Recursive Method:</B> 2200 * 2201 * <BR />This method shall skip through, 'traverse', the entire {@code FileNode} tree and prune 2202 * all 'file-leaves' that do not meet the criteria specified by the {@code 'fileFilter'} 2203 * parameter. 2204 * 2205 * @param fileFilter This is the test used to filter out files from the directory-tree that 2206 * begins at {@code 'this'} instance. Returning {@code FALSE} shall eliminate the file from 2207 * its containing parent, and when this filter returns {@code TRUE} that file shall remain. 2208 * 2209 * @param nullThePointers The primary use of this boolean is to remind users that this 2210 * data-structure {@code class FileNode} is actually a tree that maintains pointers in both 2211 * directions - upwards and downwards. Generally, trees have the potential to make programming 2212 * an order of magnitude more complicated. Fortunately, because this data-structure merely 2213 * represents the File-System, <I><B>and because</I></B> the data-structure itself (READ: 2214 * {@code 'this'} tree) does not have much use for being modified itself... The fact that 2215 * {@code FileNode} is a two-way, bi-directional tree rarely seems important. The most useful 2216 * methods are those that "flatten" the tree, and then process the data in the files listed. 2217 * 2218 * <BR /><BR /><B>POINT:</B> When this parameter is set to {@code TRUE}, all parent pointers 2219 * shall be nulled, and this can make garbage-collection easier. 2220 * 2221 * @return The number of files that were removed. 2222 * 2223 * @throws DirExpectedException If {@code 'this'} instance of {@code FileNode} does not 2224 * represent a 'directory' on the File-System, then this exception shall throw. 2225 * 2226 * @see #prune(FileNodeFilter, boolean) 2227 * @see #isDirectory 2228 * @see #parent 2229 */ 2230 public int pruneTree(FileNodeFilter fileFilter, boolean nullThePointers) 2231 { 2232 DirExpectedException.check(this); 2233 2234 Iterator<FileNode> iter = this.children.iterator(); 2235 int removeCount = 0; 2236 2237 while (iter.hasNext()) 2238 { 2239 FileNode fn = iter.next(); 2240 2241 /* 2242 DEBUGGING, KEEP HERE. 2243 System.out.print( 2244 "Testing: fn.name: " + fn.name + "\tfn.getParentDir().name: " + 2245 fn.getParentDir().name 2246 ); 2247 */ 2248 2249 if (! fn.isDirectory) 2250 2251 // NOTE: This only filters 'files' (leaf-nodes) out of the tree. This 'tree-prune' 2252 // operation does not have any bearing on 'directory-nodes' (branch-nodes) in 2253 // the tree. 2254 2255 if (! fileFilter.test(fn)) 2256 { 2257 // These types of lines can help the Java Garbage-Collector. 2258 // They also prevent the user from ever utilizing this object reference again. 2259 2260 if (nullThePointers) fn.parent = null; 2261 2262 // System.out.println("\tRemoving..."); 2263 2264 // This iterator is one generated by class 'Vector<FileNode>', and its remove() 2265 // operation, therefore, is fully-supported. This removes FileNode fn from 2266 // 'this' private, final field 'private Vector<FileNode> children' 2267 2268 iter.remove(); 2269 2270 removeCount++; 2271 continue; 2272 } 2273 2274 // Keep Here, for Testing 2275 // System.out.println("\tKeeping..."); 2276 2277 if (fn.isDirectory) removeCount += fn.pruneTree(fileFilter, nullThePointers); 2278 } 2279 2280 return removeCount; 2281 } 2282 2283 2284 // ******************************************************************************************** 2285 // ******************************************************************************************** 2286 // Simple stuff 2287 // ******************************************************************************************** 2288 // ******************************************************************************************** 2289 2290 2291 /** 2292 * Returns the parent of {@code 'this' FileNode} 2293 * 2294 * @return {@code this.parent} 2295 * 2296 * <BR /><BR /><B>NOTE</B> If this is a "root node" or "root directory" then null will be 2297 * returned here. 2298 * 2299 * @see #parent 2300 */ 2301 public FileNode getParentDir() { return parent; } 2302 2303 /** 2304 * Move's a file or directory from "inside" or "within" the contents of the current/parent 2305 * directory, and into a new/destination/parent directory. If the {@code destinationDir} is 2306 * not actually a directory, then an exception is thrown. If this is already a child/member 2307 * of the {@code destinationDir}, then an exception is also thrown. 2308 * 2309 * <BR /><BR /><B CLASS=JDDescLabel>File-System Safety:</B> 2310 * 2311 * <BR />This method <I>does not modify</I> the underlying UNIX or MS-DOS File-System - just 2312 * the {@code FileNode} Tree representation in Java Memory! (No UNIX, Apple, MS-DOS etc. 2313 * files are actually moved by this method) 2314 * 2315 * @param destinationDir the destination directory 2316 * 2317 * @throws java.util.InputMismatchException 2318 * @throws DirExpectedException If {@code 'destinationDir'} is not a directory, but a file, 2319 * then this exception is thrown. (Files <I>may not</I> contain child-nodes, only directories) 2320 * 2321 * @see #parent 2322 * @see #name 2323 * @see #children 2324 */ 2325 public void move(FileNode destinationDir) 2326 { 2327 DirExpectedException.check(destinationDir); 2328 2329 if (this.parent == destinationDir) throw new java.util.InputMismatchException( 2330 "[" + name + "] - is already a member of the target directory " + 2331 "[" + destinationDir.name + "]" 2332 ); 2333 2334 parent = destinationDir; 2335 2336 destinationDir.children.addElement(this); 2337 } 2338 2339 /** 2340 * This deletes a file from the {@code FileNode} tree. It's only operation is to remove 2341 * {@code 'this'} from the parent-node's {@code Vector<FileNode> children} node-list! For 2342 * Java garbage collection purposes, it also empties (calls 2343 * {@code children.removeAllElements()}) on the children {@code Vector} - if there is one 2344 * (a.k.a) if {@code 'this' FileNode} represents a directory, not a file! 2345 * 2346 * <BR /><BR /><B CLASS=JDDescLabel>File-System Safety:</B> 2347 * 2348 * <BR />This method <I>does not modify</I> the underlying UNIX or MS-DOS File-System - just 2349 * the {@code FileNode}-Tree representation in Java Memory! (No UNIX, Apple, MS-DOS, etc. 2350 * files are actually deleted by this method) 2351 * 2352 * @see #parent 2353 * @see #children 2354 * @see #isDirectory 2355 */ 2356 public void del() 2357 { 2358 parent.children.removeElement(this); 2359 2360 if (isDirectory) children.removeAllElements(); 2361 2362 parent = null; 2363 } 2364 2365 /** 2366 * This visits the {@code '.name'} field for {@code 'this' FileNode}, as well as all parent 2367 * instances of {@code 'this' FileNode}, and concatenates those {@code String's}. 2368 * 2369 * @return the full, available path name for {@code 'this' FileNode} as a {@code String} 2370 * @see #parent 2371 * @see #isDirectory 2372 * @see #name 2373 * @see #getFullPathName() 2374 */ 2375 public String getFullPathName() 2376 { 2377 if (parent == null) 2378 2379 // This is tested in this class constructor, If this is TRUE, isDirectory must be true 2380 // RECENT ISSUE: May, 2022 - Google Cloud Shell Root Directory. 2381 2382 return name.equals(File.separator) 2383 ? name 2384 : name + (isDirectory ? File.separatorChar : ""); 2385 // All other nodes where 'isDirectory' is TRUE 2386 // must have the file.separator appended 2387 2388 else 2389 return parent.getFullPathName() + name + (isDirectory ? File.separatorChar : ""); 2390 } 2391 2392 /** 2393 * Returns the as much of the "Full Path Name" of the file referenced by {@code 'this'} 2394 * filename as is possible for this particular {@code FileNode}. 2395 * 2396 * <BR /><BR />If this file or directory does not have a parent, then the empty (zero-length) 2397 * {@code String} will be returned. Usually, unless certain tree modification operations have 2398 * been performed, only a <I><B>root-node</B></I> {@code FileNode} will have a 'null' parent. 2399 * 2400 * @return the full, available path name to {@code 'this' FileNode} - leaving out the actual 2401 * name of this file. 2402 * 2403 * <BR /><BR /><B>SPECIFICALLY:</B> 2404 * 2405 * <BR /><BR /><UL CLASS=JDUL> 2406 * <LI>for a file such as {@code 'directory-1/subdirectory-2/filename.txt'}</LI> 2407 * <LI>{@code 'directory-1/subdirectory-2/'} would be returned</LI> 2408 * </UL> 2409 * 2410 * @see #parent 2411 * @see #getFullPathName() 2412 */ 2413 public String getParentPathName() 2414 { if (parent == null) return ""; else return parent.getFullPathName(); } 2415 2416 /** 2417 * Gets the {@code java.io.File} version of a file. The java class for files has quite a bit 2418 * of interactive stuff for a file system - including checking for {@code 'r/w/x'} permissions. 2419 * This can be useful. 2420 * 2421 * @return Gets the {@code java.io.File} instance of {@code 'this' FileNode} 2422 * @see #getFullPathName() 2423 */ 2424 public File getJavaIOFile() { return new File(getFullPathName()); } 2425 2426 /* 2427 * THIS METHOD DOES A FILE-SYSTEM WRITE, SO IT IS COMMENTED OUT 2428 * 2429 * This presumes that {@code 'this'} instance of {@code FileNode} is not a directory, but 2430 * rather a file. If it is not a file, then an exception shall throw. This method also 2431 * requires that {@code 'this'} file represents a <B>text-file</B> that may be loaded into a 2432 * {@code String}. 2433 * 2434 * <BR /><BR />This method will load the contents of {@code 'this'} file into a 2435 * {@code java.lang.String} and then pass that {@code String} (along with {@code 'this' 2436 * FileNode} to the method {@code 'apply(FileNode, String'} provided by the 2437 * {@code BiFunction<FileNode, String>} input-parameter {@code 'f'}. 2438 * 2439 * <BR /><BR />This is the type of method that could easily be used in conjunction with Java's 2440 * {@code java.util.stream.Stream} A.P.I. If the {@code 'f'} parameter were to include a 2441 * regular-expression for modifying the contents of a file, then by using Java-Streams a 2442 * programmer could easily write a UNIX {@code 'SED'} or {@code 'AWK'} like script with just a 2443 * couple lines of Java. 2444 * 2445 * <BR /><BR />Presuming that an appropriate {@code 'myFunction'} were written, any one of the 2446 * following invocations could perform a UNIX {@code 'SED'} or {@code 'AWK'} type of routine on 2447 * a suite of text-files, <I><B>instantly</I></B>. 2448 * 2449 * <BR /><BR /><UL CLASS=JDUL> 2450 * <LI> {@code Stream<FileNode>.forEach 2451 * (fileNode -> fileNode.apply(myFunction, myIOEHandler));} 2452 * </LI> 2453 * 2454 * <LI> {@code Vector<FileNode>.forEach 2455 * (fileNode -> fileNode.apply(myFunction, myIOEHandler));} 2456 * </LI> 2457 * 2458 * <LI>{@code Stream<FileNode>.map(fileNode -> fileNode.apply(...));}</LI> 2459 * </UL> 2460 * 2461 * @param f This is the java {@code FunctionalInterface 'BiFunction'} As a 2462 * {@code functional-interface}, it has a method named {@code 'apply'} and this method 2463 * {@code 'apply'} receives two parameters itself: 2464 * 2465 * <BR /><BR /><OL CLASS=JDOL> 2466 * <LI>The first Parameter shall be {@code 'this'} instance of {@code 'FileNode'}</LI> 2467 * 2468 * <LI> The second Parameter shall be the file-contents on the File-System of 2469 * {@code 'this' FileNode} - passed as a {@code java.lang.String}. 2470 * </LI> 2471 * </OL> 2472 * 2473 * <BR /><B><SPAN STYLE="color: red;">EXPECTED RETURN:</B></SPAN> The 2474 * {@code functional-interface} that is passed to parameter {@code 'f'} should provide a 2475 * return-value that is a "new, updated {@code String}" that shall be used to "replace the 2476 * file-contents" of this instance of {@code FileNode}. 2477 * 2478 * <BR /><BR /><B><SPAN STYLE="color: red;">WRITE-NOTICE:</B></SPAN> This operation will 2479 * <B><I>OVER-WRITE</I></B> the current contents of a file on the File-System. Also, this 2480 * operation treats the file as if it contained text. Data-Files containing binary-data may 2481 * not be used with this method. This is the <I><B>only method in class {@code 'FileNode'} 2482 * that actually will modify the underlying File-System.</I></B> 2483 * 2484 * @param ioeh This is an instance of {@code functional-interface class 'IOExceptionHandler'}. 2485 * It receives an instance of an {@code IOException}, and the programmer may insert any type 2486 * of code he wants to see happen when an {@code IOException} is thrown. The 'added-value' of 2487 * including this handler is that when batches of {@code apply's} are performed on a 2488 * {@code FileNode}-tree, one file causing an exception throw does not have to halt the entire 2489 * batch-process. 2490 * 2491 * <BR /><BR /><B>NOTE:</B> This parameter may be null, and if it is, it shall be ignored. It 2492 * is only invoked if it is not null, and if an exception occurs when either reading or writing 2493 * the file to/from the File-System. 2494 * 2495 * @return This method returns {@code TRUE} if there were no I/O faults when either reading or 2496 * writing the file. 2497 * 2498 * @throws FileExpectedException If {@code 'destinationDir'} is not a file, but a directory, 2499 * then this exception is thrown. 2500 * 2501 * @see #getFullPathName() 2502 * @see FileRW#loadFileToString(String) 2503 * @see FileRW#writeFile(CharSequence, String) 2504 * @see IOExceptionHandler#accept(FileNode, IOException) 2505 * 2506 public boolean apply(BiFunction<FileNode, String, String> f, IOExceptionHandler ioeh) 2507 { 2508 // This method can only be used with 'file' FileNode's. 2509 // FileNode's that are 'directories' do not have "text-contents" or "file-contents" 2510 2511 FileExpectedException.check(this); 2512 2513 try 2514 { 2515 // Read 'this' file into a String 2516 String fileName = this.toString(); 2517 String fileContents = FileRW.loadFileToString(fileName); 2518 2519 // Send the contents of 'this' file to the BiFunction parameter 'f' 2520 fileContents = f.apply(this, fileContents); 2521 2522 // Re-write the new file back to the old location. 2523 FileRW.writeFile(fileContents, fileName); 2524 2525 return true; 2526 } 2527 catch (IOException e) 2528 { 2529 // if an I/O exception did occur, send the information to the 2530 // I/O exception handler provided by the user (if and only if the 2531 // actually provided a non-null exception handler) 2532 2533 if (ioeh != null) ioeh.accept(this, e); 2534 2535 return false; 2536 } 2537 } 2538 */ 2539 2540 /** 2541 * This presumes that {@code 'this'} instance of {@code FileNode} is not a directory, but 2542 * rather a file. If it is not a file, then an exception shall throw. This method also 2543 * requires that {@code 'this'} file represents a <B>text-file</B> that may be loaded into a 2544 * {@code String}. 2545 * 2546 * <BR /><BR />This method will load the contents of {@code 'this'} file into a 2547 * {@code java.lang.String} and then pass that {@code String} (along with {@code 'this' 2548 * FileNode} to the method {@code 'accept(FileNode, String'} provided by the 2549 * {@code BiConsumer<FileNode, String>} input-parameter {@code 'c'}. 2550 * 2551 * @param c This is the java {@code FunctionalInterface 'BiConsumer'}. As a 2552 * {@code functional-interface}, it has a method named {@code 'accept'} and this method 2553 * {@code 'accept'} receives two parameters itself: 2554 * 2555 * <BR /><BR /><OL CLASS=JDOL> 2556 * <LI>The first Parameter shall be {@code 'this'} instance of {@code 'FileNode'}</LI> 2557 * 2558 * <LI> The second Parameter shall be the file-contents on the File-System of 2559 * {@code 'this' FileNode} - passed as a {@code java.lang.String}. 2560 * </LI> 2561 * </OL> 2562 * 2563 * @param ioeh This an is instance of {@code FunctionalInterface 'IOExceptionHandler'}. It 2564 * receives an instance of an {@code IOException}, and the programmer may insert any type of 2565 * code he wants to see happen when an {@code IOException} is thrown. The 'added-value' of 2566 * including this handler is that when batches of {@code accept's} are performed one a 2567 * {@code FileNode}-tree, one file causing an exception throw does not have to halt the entire 2568 * batch-process. 2569 * 2570 * <BR /><BR /><B>NOTE:</B> This parameter may be null, and if it is, it shall be ignored. 2571 * It is only invoked if it is not null, and if an exception occurs when either reading or 2572 * writing the file to/from the File-System. 2573 * 2574 * @throws FileExpectedException If {@code 'destinationDir'} is not a file, but a directory, 2575 * then this exception is thrown. 2576 * 2577 * @see FileRW#loadFileToString(String) 2578 * @see #getFullPathName() 2579 * @see IOExceptionHandler#accept(FileNode, IOException) 2580 */ 2581 public void accept(BiConsumer<FileNode, String> c, IOExceptionHandler ioeh) 2582 { 2583 // This method can only be used with 'file' FileNode's. 2584 // FileNode's that are 'directories' do not have "text-contents" or "file-contents" 2585 2586 FileExpectedException.check(this); 2587 2588 try 2589 { c.accept(this, FileRW.loadFileToString(getFullPathName())); } 2590 2591 catch (IOException ioe) 2592 2593 // if an I/O exception did occur, send the information to the 2594 // I/O exception handler provided by the user (if and only if the 2595 // actually provided a non-null exception handler) 2596 2597 { if (ioeh != null) ioeh.accept(this, ioe); } 2598 } 2599 2600 /** 2601 * This presumes that {@code 'this'} instance of {@code FileNode} is not a directory, but 2602 * rather a file. If it is not a file, then an exception shall throw. This method also 2603 * requires that {@code 'this'} file represents a <B>text-file</B> that may be loaded into a 2604 * {@code String}. 2605 * 2606 * <BR /><BR />This method will load the contents of {@code 'this'} file into a 2607 * {@code java.lang.String} and then pass that {@code String} (along with {@code 'this' 2608 * FileNode} to the method {@code 'ask(FileNode, String'} provided by the 2609 * {@code BiPredicate<FileNode, String>} input-parameter {@code 'p'}. 2610 * 2611 * <BR /><BR />This is the type of method that could easily be used in conjunction with a 2612 * {@code java.util.stream.Stream} or a {@code java.util.Vector}. 2613 * 2614 * <BR /><BR /><UL CLASS=JDUL> 2615 * <LI> {@code Stream<FileNode>.filter 2616 * (fileNode -> fileNode.ask(myFilterPred, myIOEHandler));} 2617 * </LI> 2618 * 2619 * <LI> {@code Vector<FileNode>.removeIf 2620 * (fileNode -> fileNode.ask(myFilterPred, myIOEHandler));} 2621 * </LI> 2622 * </UL> 2623 * 2624 * @param p This is the java {@code FunctionalInterface 'BiPredicate'}. As a 2625 * {@code functional-interface}, it has a method named {@code 'test'} and this method 2626 * {@code 'test'} receives two parameters itself: 2627 * 2628 * <BR /><BR /><OL CLASS=JDOL> 2629 * <LI>The first parameter shall be {@code 'this'} instance of {@code 'FileNode'}</LI> 2630 * <LI>The second parameter shall be the file-contents on the File-System of 2631 * {@code 'this' FileNode} - passed as a {@code java.lang.String}.</LI> 2632 * </OL> 2633 * 2634 * <BR /><BR /><B>IMPORTANT:</B> The {@code functional-interface} that is passed to parameter 2635 * {@code 'p'} should provide a return {@code boolean}-value that is to act as a pass/fail 2636 * filter criteria. It is important to note that the Java {@code Vector} method 2637 * {@code Vector.removeIf(Predicate)} and the Java method {@code Stream.filter(Predicate)} 2638 * will produce <B><I>exactly opposite outputs</I></B> based on the same filter logic. 2639 * 2640 * <BR /><BR />To explain further, when {@code Vector.removeIf(Predicate)} is used, the 2641 * predicate should return {@code FALSE} to indicate that the {@code FileNode} needs to be 2642 * eliminated not retained. When {@code Stream.filter(Predicate)} is used, {@code TRUE} should 2643 * indicate that the {@code FileNode} should be retained not eliminated. 2644 * 2645 * @param ioeh This is an instance of functional-interface class, {@code IOExceptionHandler}. 2646 * It receives an instance of an {@code IOException}, and the programmer may insert any type of 2647 * code he wants to see happen when an {@code IOException} is thrown. The 'added-value' of 2648 * including this handler is that when batches of {@code ask's} are performed on a 2649 * {@code FileNode}-tree, one file causing an exception throw does not have to halt the entire 2650 * batch-process. 2651 * 2652 * <BR /><BR /><B>NOTE:</B> This parameter may be null, and if it is, it shall be ignored. It 2653 * is only invoked if it is not null, and if an exception occurs when either reading or writing 2654 * the file to/from the File-System. 2655 * 2656 * @return This method returns {@code TRUE} if there were no I/O faults when either reading or 2657 * writing the file. 2658 * 2659 * @throws FileExpectedException If {@code 'destinationDir'} is not a file, but a directory, 2660 * then this exception is thrown. 2661 * 2662 * @see #getFullPathName() 2663 * @see FileRW#loadFileToString(String) 2664 * @see IOExceptionHandler#accept(FileNode, IOException) 2665 */ 2666 public boolean ask(BiPredicate<FileNode, String> p, IOExceptionHandler ioeh) 2667 { 2668 // This method can only be used with 'file' FileNode's. 2669 // FileNode's that are 'directories' do not have "text-contents" or "file-contents" 2670 2671 FileExpectedException.check(this); 2672 2673 try 2674 { return p.test(this, FileRW.loadFileToString(getFullPathName())); } 2675 2676 catch (IOException ioe) 2677 { if (ioeh != null) ioeh.accept(this, ioe); return false; } 2678 } 2679 2680 /** 2681 * There are not any "Tree Structures" present in the HTML Search, Update, and Scrape Packages. 2682 * In the Java Packages, the {@code class 'FileNode'} is the lone source of "Tree Structures." 2683 * The Java Garbage Collector sometimes seems to work in mysterious ways. 2684 * 2685 * <BR /><BR />This method will 'null-ify' all references (pointers) in a 2686 * {@code 'FileNode'}-Tree. The {@code FileNode}-Tree can be a great asset or tool during the 2687 * development process when looking through file-contents and trying to modify them - <I>or 2688 * just find files with certain characteristics.</I> 2689 * 2690 * @see #getDirContents() 2691 * @see #getDirContentsDirs() 2692 * @see #parent 2693 * @see #children 2694 */ 2695 public void NULL_THE_TREE() 2696 { 2697 Iterator<FileNode> iter = getDirContents(RetTypeChoice.ITERATOR); 2698 2699 while (iter.hasNext()) iter.next().parent = null; 2700 2701 iter = getDirContentsDirs(RetTypeChoice.ITERATOR); 2702 2703 while (iter.hasNext()) iter.next().NULL_THE_TREE(); 2704 2705 children.clear(); 2706 } 2707 2708 /** 2709 * A class allowing a user to specify a return-type and a sort-type for results from 2710 * {@code FileNode} operations. 2711 * 2712 * <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC> 2713 */ 2714 public static class RetTypeChoice<T> 2715 { 2716 // This cannot be private, because it is also used in class "GREP". Maybe that is a 2717 // good reason to get rid of GREP. Keeping this private isn't that important, but it makes 2718 // this look a lot uglier 2719 2720 VarList<T, FileNode> varList; 2721 2722 private RetTypeChoice(VarList<T, FileNode> varList) 2723 { this.varList = varList; } 2724 2725 /** 2726 * {@code Comparator} for sorting instances of {@code FileNode} by their 2727 * {@code 'lastModified'} field. 2728 */ 2729 protected static final Comparator<FileNode> BY_DATE = 2730 Comparator.comparingLong((FileNode fn) -> fn.lastModified); 2731 2732 /** 2733 * {@code Comparator} for sorting instances of {@code FileNode} by their {@code 'fileSize'} 2734 * field. 2735 */ 2736 protected static final Comparator<FileNode> BY_FILE_SIZE = 2737 Comparator.comparingLong((FileNode fn) -> fn.fileSize); 2738 2739 /** 2740 * {@code Comparator} for sorting instances of {@code FileNode} by the results of method 2741 * {@code FileNode.getFullPathName()} 2742 */ 2743 protected static final Comparator<FileNode> BY_FULLPATH = 2744 (FileNode fn1, FileNode fn2) -> fn1.getFullPathName().compareTo(fn2.getFullPathName()); 2745 2746 /** 2747 * {@code Comparator} for sorting instances of {@code FileNode} by their {@code 'name'} 2748 * field. 2749 */ 2750 protected static final Comparator<FileNode> BY_FILENAME = 2751 (FileNode fn1, FileNode fn2) -> fn1.name.compareTo(fn2.name); 2752 2753 2754 2755 private static final VarListBuilder<FileNode> vlb = new VarListBuilder<>(FileNode.class); 2756 2757 /** {@code Vector<FileNode>} */ 2758 public static final RetTypeChoice<Vector<FileNode>> VECTOR = 2759 new RetTypeChoice<>(vlb.VECTOR); 2760 2761 /** {@code ArrayList<FileNode>} */ 2762 public static final RetTypeChoice<ArrayList<FileNode>> ARRAYLIST = 2763 new RetTypeChoice<>(vlb.ARRAYLIST); 2764 2765 /** {@code Stream<FileNode>} */ 2766 public static final RetTypeChoice<Stream<FileNode>> STREAM = 2767 new RetTypeChoice<>(vlb.STREAM); 2768 2769 /** {@code Stream.Builder<FileNode>} */ 2770 public static final RetTypeChoice<Stream.Builder<FileNode>> STREAM_BUILDER = 2771 new RetTypeChoice<>(vlb.STREAM_BUILDER); 2772 2773 /** {@code FileNode[]} */ 2774 public static final RetTypeChoice<FileNode[]> ARRAY = 2775 new RetTypeChoice<>(vlb.ARRAY); 2776 2777 /** {@code Iterator<FileNode>} */ 2778 public static final RetTypeChoice<Iterator<FileNode>> ITERATOR = 2779 new RetTypeChoice<>(vlb.ITERATOR); 2780 2781 /** {@code HashSet<FileNode>} */ 2782 public static final RetTypeChoice<HashSet<FileNode>> HASHSET = 2783 new RetTypeChoice<>(vlb.HASHSET); 2784 2785 /** {@code LinkedList<FileNode>} */ 2786 public static final RetTypeChoice<LinkedList<FileNode>> LINKEDLIST = 2787 new RetTypeChoice<>(vlb.LINKEDLIST); 2788 2789 /** {@code Stack<FileNode>} */ 2790 public static final RetTypeChoice<Stack<FileNode>> STACK = 2791 new RetTypeChoice<>(vlb.STACK); 2792 2793 2794 2795 private static final VarListBuilderWithSort<FileNode> vlbws1 = 2796 new VarListBuilderWithSort<>(BY_DATE, FileNode.class); 2797 2798 /** {@code Vector<FileNode>}, sorted by {@link FileNode#lastModified} */ 2799 public static final RetTypeChoice<Vector<FileNode>> SORTED_BY_DATE_VECTOR = 2800 new RetTypeChoice<>(vlbws1.VECTOR); 2801 2802 /** {@code ArrayList<FileNode>}, sorted by {@link FileNode#lastModified} */ 2803 public static final RetTypeChoice<ArrayList<FileNode>> SORTED_BY_DATE_ARRAYLIST = 2804 new RetTypeChoice<>(vlbws1.ARRAYLIST); 2805 2806 /** {@code Stream<FileNode>}, sorted by {@link FileNode#lastModified} */ 2807 public static final RetTypeChoice<Stream<FileNode>> SORTED_BY_DATE_STREAM = 2808 new RetTypeChoice<>(vlbws1.STREAM); 2809 2810 /** {@code Stream.Builder<FileNode>}, sorted by {@link FileNode#lastModified} */ 2811 public static final RetTypeChoice<Stream.Builder<FileNode>> SORTED_BY_DATE_STREAM_BUILDER = 2812 new RetTypeChoice<>(vlbws1.STREAM_BUILDER); 2813 2814 /** {@code FileNode[]}, sorted by {@link FileNode#lastModified} */ 2815 public static final RetTypeChoice<FileNode[]> SORTED_BY_DATE_ARRAY = 2816 new RetTypeChoice<>(vlbws1.ARRAY); 2817 2818 /** {@code Iterator<FileNode>}, sorted by {@link FileNode#lastModified} */ 2819 public static final RetTypeChoice<Iterator<FileNode>> SORTED_BY_DATE_ITERATOR = 2820 new RetTypeChoice<>(vlbws1.ITERATOR); 2821 2822 /** {@code TreeSet<FileNode>}, sorted by {@link FileNode#lastModified} */ 2823 public static final RetTypeChoice<TreeSet<FileNode>> SORTED_BY_DATE_TREESET = 2824 new RetTypeChoice<>(vlbws1.TREESET); 2825 2826 /** {@code LinkedList<FileNode>}, sorted by {@link FileNode#lastModified} */ 2827 public static final RetTypeChoice<LinkedList<FileNode>> SORTED_BY_DATE_LINKEDLIST = 2828 new RetTypeChoice<>(vlbws1.LINKEDLIST); 2829 2830 /** {@code Stack<FileNode>}, sorted by {@link FileNode#lastModified} */ 2831 public static final RetTypeChoice<Stack<FileNode>> SORTED_BY_DATE_STACK = 2832 new RetTypeChoice<>(vlbws1.STACK); 2833 2834 2835 2836 private static final VarListBuilderWithSort<FileNode> vlbws2 2837 = new VarListBuilderWithSort<>(BY_FILE_SIZE, FileNode.class); 2838 2839 /** {@code Vector<FileNode>}, sorted by {@link FileNode#fileSize} */ 2840 public static final RetTypeChoice<Vector<FileNode>> SORTED_BY_SIZE_VECTOR = 2841 new RetTypeChoice<>(vlbws2.VECTOR); 2842 2843 /** {@code ArrayList<FileNode>}, sorted by {@link FileNode#fileSize} */ 2844 public static final RetTypeChoice<ArrayList<FileNode>> SORTED_BY_SIZE_ARRAYLIST = 2845 new RetTypeChoice<>(vlbws2.ARRAYLIST); 2846 2847 /** {@code Stream<FileNode>}, sorted by {@link FileNode#fileSize} */ 2848 public static final RetTypeChoice<Stream<FileNode>> SORTED_BY_SIZE_STREAM = 2849 new RetTypeChoice<>(vlbws2.STREAM); 2850 2851 /** {@code Stream.Builder<FileNode>}, sorted by {@link FileNode#fileSize} */ 2852 public static final RetTypeChoice<Stream.Builder<FileNode>> SORTED_BY_SIZE_STREAM_BUILDER = 2853 new RetTypeChoice<>(vlbws2.STREAM_BUILDER); 2854 2855 /** {@code FileNode[]}, sorted by {@link FileNode#fileSize} */ 2856 public static final RetTypeChoice<FileNode[]> SORTED_BY_SIZE_ARRAY = 2857 new RetTypeChoice<>(vlbws2.ARRAY); 2858 2859 /** {@code Iterator<FileNode>}, sorted by {@link FileNode#fileSize} */ 2860 public static final RetTypeChoice<Iterator<FileNode>> SORTED_BY_SIZE_ITERATOR = 2861 new RetTypeChoice<>(vlbws2.ITERATOR); 2862 2863 /** {@code TreeSet<FileNode>}, sorted by {@link FileNode#fileSize} */ 2864 public static final RetTypeChoice<TreeSet<FileNode>> SORTED_BY_SIZE_TREESET = 2865 new RetTypeChoice<>(vlbws2.TREESET); 2866 2867 /** {@code LinkedList<FileNode>}, sorted by {@link FileNode#fileSize} */ 2868 public static final RetTypeChoice<LinkedList<FileNode>> SORTED_BY_SIZE_LINKEDLIST = 2869 new RetTypeChoice<>(vlbws2.LINKEDLIST); 2870 2871 /** {@code Stack<FileNode>}, sorted by {@link FileNode#fileSize} */ 2872 public static final RetTypeChoice<Stack<FileNode>> SORTED_BY_SIZE_STACK = 2873 new RetTypeChoice<>(vlbws2.STACK); 2874 2875 2876 2877 private static final VarListBuilderWithSort<FileNode> vlbws3 = 2878 new VarListBuilderWithSort<>(BY_FULLPATH, FileNode.class); 2879 2880 /** {@code Vector<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2881 public static final RetTypeChoice<Vector<FileNode>> SORTED_BY_FULLPATH_VECTOR = 2882 new RetTypeChoice<>(vlbws3.VECTOR); 2883 2884 /** {@code ArrayList<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2885 public static final RetTypeChoice<ArrayList<FileNode>> SORTED_BY_FULLPATH_ARRAYLIST = 2886 new RetTypeChoice<>(vlbws3.ARRAYLIST); 2887 2888 /** {@code Stream<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2889 public static final RetTypeChoice<Stream<FileNode>> SORTED_BY_FULLPATH_STREAM = 2890 new RetTypeChoice<>(vlbws3.STREAM); 2891 2892 /** {@code Stream.Builder<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2893 public static final RetTypeChoice<Stream.Builder<FileNode>> 2894 SORTED_BY_FULLPATH_STREAM_BUILDER = new RetTypeChoice<>(vlbws3.STREAM_BUILDER); 2895 2896 /** {@code FileNode[]}, sorted by {@link FileNode#getFullPathName()} */ 2897 public static final RetTypeChoice<FileNode[]> SORTED_BY_FULLPATH_ARRAY = 2898 new RetTypeChoice<>(vlbws3.ARRAY); 2899 2900 /** {@code Iterator<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2901 public static final RetTypeChoice<Iterator<FileNode>> SORTED_BY_FULLPATH_ITERATOR = 2902 new RetTypeChoice<>(vlbws3.ITERATOR); 2903 2904 /** {@code TreeSet<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2905 public static final RetTypeChoice<TreeSet<FileNode>> SORTED_BY_FULLPATH_TREESET = 2906 new RetTypeChoice<>(vlbws3.TREESET); 2907 2908 /** {@code LinkedList<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2909 public static final RetTypeChoice<LinkedList<FileNode>> SORTED_BY_FULLPATH_LINKEDLIST = 2910 new RetTypeChoice<>(vlbws3.LINKEDLIST); 2911 2912 /** {@code Stack<FileNode>}, sorted by {@link FileNode#getFullPathName()} */ 2913 public static final RetTypeChoice<Stack<FileNode>> SORTED_BY_FULLPATH_STACK = 2914 new RetTypeChoice<>(vlbws3.STACK); 2915 2916 2917 2918 private static final VarListBuilderWithSort<FileNode> vlbws4 = 2919 new VarListBuilderWithSort<>(BY_FILENAME, FileNode.class); 2920 2921 /** {@code Vector<FileNode>}, sorted by {@link FileNode#name} */ 2922 public static final RetTypeChoice<Vector<FileNode>> SORTED_BY_FILENAME_VECTOR = 2923 new RetTypeChoice<>(vlbws4.VECTOR); 2924 2925 /** {@code ArrayList<FileNode>}, sorted by {@link FileNode#name} */ 2926 public static final RetTypeChoice<ArrayList<FileNode>> SORTED_BY_FILENAME_ARRAYLIST = 2927 new RetTypeChoice<>(vlbws4.ARRAYLIST); 2928 2929 /** {@code Stream<FileNode>}, sorted by {@link FileNode#name} */ 2930 public static final RetTypeChoice<Stream<FileNode>> SORTED_BY_FILENAME_STREAM = 2931 new RetTypeChoice<>(vlbws4.STREAM); 2932 2933 /** {@code Stream.Builder<FileNode>}, sorted by {@link FileNode#name} */ 2934 public static final RetTypeChoice<Stream.Builder<FileNode>> 2935 SORTED_BY_FILENAME_STREAM_BUILDER = new RetTypeChoice<>(vlbws4.STREAM_BUILDER); 2936 2937 /** {@code FileNode[]}, sorted by {@link FileNode#name} */ 2938 public static final RetTypeChoice<FileNode[]> SORTED_BY_FILENAME_ARRAY = 2939 new RetTypeChoice<>(vlbws4.ARRAY); 2940 2941 /** {@code Iterator<FileNode>}, sorted by {@link FileNode#name} */ 2942 public static final RetTypeChoice<Iterator<FileNode>> SORTED_BY_FILENAME_ITERATOR = 2943 new RetTypeChoice<>(vlbws4.ITERATOR); 2944 2945 /** {@code TreeSet<FileNode>}, sorted by {@link FileNode#name} */ 2946 public static final RetTypeChoice<TreeSet<FileNode>> SORTED_BY_FILENAME_TREESET = 2947 new RetTypeChoice<>(vlbws4.TREESET); 2948 2949 /** {@code LinkedList<FileNode>}, sorted by {@link FileNode#name} */ 2950 public static final RetTypeChoice<LinkedList<FileNode>> SORTED_BY_FILENAME_LINKEDLIST = 2951 new RetTypeChoice<>(vlbws4.LINKEDLIST); 2952 2953 /** {@code Stack<FileNode>}, sorted by {@link FileNode#name} */ 2954 public static final RetTypeChoice<Stack<FileNode>> SORTED_BY_FILENAME_STACK = 2955 new RetTypeChoice<>(vlbws4.STACK); 2956 2957 2958 2959 private static final VarListBuilderWithApply<FileNode, String> vlbwa1 = 2960 new VarListBuilderWithApply<>((FileNode fn) -> fn.name, String.class); 2961 2962 /** {@code Vector<String>} of {@link FileNode#name} */ 2963 public static final RetTypeChoice<Vector<String>> FILENAME_VECTOR = 2964 new RetTypeChoice<>(vlbwa1.VECTOR); 2965 2966 /** {@code ArrayList<String>} of {@link FileNode#name} */ 2967 public static final RetTypeChoice<ArrayList<String>> FILENAME_ARRAYLIST = 2968 new RetTypeChoice<>(vlbwa1.ARRAYLIST); 2969 2970 /** {@code Stream<String>} of {@link FileNode#name} */ 2971 public static final RetTypeChoice<Stream<String>> FILENAME_STREAM = 2972 new RetTypeChoice<>(vlbwa1.STREAM); 2973 2974 /** {@code Stream.Builder<String>} of {@link FileNode#name} */ 2975 public static final RetTypeChoice<Stream.Builder<String>> FILENAME_STREAM_BUILDER = 2976 new RetTypeChoice<>(vlbwa1.STREAM_BUILDER); 2977 2978 /** {@code String[]} of {@link FileNode#name} */ 2979 public static final RetTypeChoice<String[]> FILENAME_ARRAY = 2980 new RetTypeChoice<>(vlbwa1.ARRAY); 2981 2982 /** {@code Iterator<String>} of {@link FileNode#name} */ 2983 public static final RetTypeChoice<Iterator<String>> FILENAME_ITERATOR = 2984 new RetTypeChoice<>(vlbwa1.ITERATOR); 2985 2986 /** {@code HashSet<String>} of {@link FileNode#name} */ 2987 public static final RetTypeChoice<HashSet<String>> FILENAME_HASHSET = 2988 new RetTypeChoice<>(vlbwa1.HASHSET); 2989 2990 /** {@code LinkedList<String>} of {@link FileNode#name} */ 2991 public static final RetTypeChoice<LinkedList<String>> FILENAME_LINKEDLIST = 2992 new RetTypeChoice<>(vlbwa1.LINKEDLIST); 2993 2994 /** {@code Stack<String>} of {@link FileNode#name} */ 2995 public static final RetTypeChoice<Stack<String>> FILENAME_STACK = 2996 new RetTypeChoice<>(vlbwa1.STACK); 2997 2998 2999 3000 private static final VarListBuilderWithApply<FileNode, String> vlbwa2 = 3001 new VarListBuilderWithApply<>((FileNode fn) -> fn.getFullPathName(), String.class); 3002 3003 /** {@code Vector<String>} of {@link FileNode#getFullPathName()} */ 3004 public static final RetTypeChoice<Vector<String>> FULLPATH_VECTOR = 3005 new RetTypeChoice<>(vlbwa2.VECTOR); 3006 3007 /** {@code ArrayList<String>} of {@link FileNode#getFullPathName()} */ 3008 public static final RetTypeChoice<ArrayList<String>> FULLPATH_ARRAYLIST = 3009 new RetTypeChoice<>(vlbwa2.ARRAYLIST); 3010 3011 /** {@code Stream<String>} of {@link FileNode#getFullPathName()} */ 3012 public static final RetTypeChoice<Stream<String>> FULLPATH_STREAM = 3013 new RetTypeChoice<>(vlbwa2.STREAM); 3014 3015 /** {@code Stream.Builder<String>} of {@link FileNode#getFullPathName()} */ 3016 public static final RetTypeChoice<Stream.Builder<String>> FULLPATH_STREAM_BUILDER = 3017 new RetTypeChoice<>(vlbwa2.STREAM_BUILDER); 3018 3019 /** {@code String[]} of {@link FileNode#getFullPathName()} */ 3020 public static final RetTypeChoice<String[]> FULLPATH_ARRAY = 3021 new RetTypeChoice<>(vlbwa2.ARRAY); 3022 3023 /** {@code Iterator<String>} of {@link FileNode#getFullPathName()} */ 3024 public static final RetTypeChoice<Iterator<String>> FULLPATH_ITERATOR = 3025 new RetTypeChoice<>(vlbwa2.ITERATOR); 3026 3027 /** {@code HashSet<String>} of {@link FileNode#getFullPathName()} */ 3028 public static final RetTypeChoice<HashSet<String>> FULLPATH_HASHSET = 3029 new RetTypeChoice<>(vlbwa2.HASHSET); 3030 3031 /** {@code LinkedList<String>} of {@link FileNode#getFullPathName()} */ 3032 public static final RetTypeChoice<LinkedList<String>> FULLPATH_LINKEDLIST = 3033 new RetTypeChoice<>(vlbwa2.LINKEDLIST); 3034 3035 /** {@code Stack<String>} of {@link FileNode#getFullPathName()} */ 3036 public static final RetTypeChoice<Stack<String>> FULLPATH_STACK = 3037 new RetTypeChoice<>(vlbwa2.STACK); 3038 3039 3040 3041 private static final VarListBuilderWithApplyAndSort<FileNode, String> vlbwaas1 = 3042 new VarListBuilderWithApplyAndSort<> 3043 ((FileNode fn) -> fn.name, String::compareTo, String.class); 3044 3045 /** a sorted {@code Vector<String>} of {@link FileNode#name} */ 3046 public static final RetTypeChoice<Vector<String>> SORTED_FILENAME_VECTOR = 3047 new RetTypeChoice<>(vlbwaas1.VECTOR); 3048 3049 /** a sorted {@code ArrayList<String>} of {@link FileNode#name} */ 3050 public static final RetTypeChoice<ArrayList<String>> SORTED_FILENAME_ARRAYLIST = 3051 new RetTypeChoice<>(vlbwaas1.ARRAYLIST); 3052 3053 /** a sorted {@code Stream<String>} of {@link FileNode#name} */ 3054 public static final RetTypeChoice<Stream<String>> SORTED_FILENAME_STREAM = 3055 new RetTypeChoice<>(vlbwaas1.STREAM); 3056 3057 /** a sorted {@code Stream.Builder<String>} of {@link FileNode#name} */ 3058 public static final RetTypeChoice<Stream.Builder<String>> SORTED_FILENAME_STREAM_BUILDER = 3059 new RetTypeChoice<>(vlbwaas1.STREAM_BUILDER); 3060 3061 /** a sorted {@code String[]} of {@link FileNode#name} */ 3062 public static final RetTypeChoice<String[]> SORTED_FILENAME_ARRAY = 3063 new RetTypeChoice<>(vlbwaas1.ARRAY); 3064 3065 /** a sorted {@code Iterator<String>} of {@link FileNode#name} */ 3066 public static final RetTypeChoice<Iterator<String>> SORTED_FILENAME_ITERATOR = 3067 new RetTypeChoice<>(vlbwaas1.ITERATOR); 3068 3069 /** a sorted {@code TreeSet<String>} of {@link FileNode#name} */ 3070 public static final RetTypeChoice<TreeSet<String>> SORTED_FILENAME_TREESET = 3071 new RetTypeChoice<>(vlbwaas1.TREESET); 3072 3073 /** a sorted {@code LinkedList<String>} of {@link FileNode#name} */ 3074 public static final RetTypeChoice<LinkedList<String>> SORTED_FILENAME_LINKEDLIST = 3075 new RetTypeChoice<>(vlbwaas1.LINKEDLIST); 3076 3077 /** a sorted {@code Stack<String>} of {@link FileNode#name} */ 3078 public static final RetTypeChoice<Stack<String>> SORTED_FILENAME_STACK = 3079 new RetTypeChoice<>(vlbwaas1.STACK); 3080 3081 3082 3083 private static final VarListBuilderWithApplyAndSort<FileNode, String> vlbwaas2 3084 = new VarListBuilderWithApplyAndSort<> 3085 ((FileNode fn) -> fn.getFullPathName(), String::compareTo, String.class); 3086 3087 /** a sorted {@code Vector<String>} of {@link FileNode#getFullPathName()} */ 3088 public static final RetTypeChoice<Vector<String>> SORTED_FULLPATH_VECTOR = 3089 new RetTypeChoice<>(vlbwaas2.VECTOR); 3090 3091 /** a sorted {@code ArrayList<String>} of {@link FileNode#getFullPathName()} */ 3092 public static final RetTypeChoice<ArrayList<String>> SORTED_FULLPATH_ARRAYLIST = 3093 new RetTypeChoice<>(vlbwaas2.ARRAYLIST); 3094 3095 /** a sorted {@code Stream<String>} of {@link FileNode#getFullPathName()} */ 3096 public static final RetTypeChoice<Stream<String>> SORTED_FULLPATH_STREAM = 3097 new RetTypeChoice<>(vlbwaas2.STREAM); 3098 3099 /** a sorted {@code Stream.Builder<String>} of {@link FileNode#getFullPathName()} */ 3100 public static final RetTypeChoice<Stream.Builder<String>> SORTED_FULLPATH_STREAM_BUILDER = 3101 new RetTypeChoice<>(vlbwaas2.STREAM_BUILDER); 3102 3103 /** a sorted {@code String[]} of {@link FileNode#getFullPathName()} */ 3104 public static final RetTypeChoice<String[]> SORTED_FULLPATH_ARRAY = 3105 new RetTypeChoice<>(vlbwaas2.ARRAY); 3106 3107 /** a sorted {@code Iterator<String>} of {@link FileNode#getFullPathName()} */ 3108 public static final RetTypeChoice<Iterator<String>> SORTED_FULLPATH_ITERATOR = 3109 new RetTypeChoice<>(vlbwaas2.ITERATOR); 3110 3111 /** a sorted {@code TreeSet<String>} of {@link FileNode#getFullPathName()} */ 3112 public static final RetTypeChoice<TreeSet<String>> SORTED_FULLPATH_TREESET = 3113 new RetTypeChoice<>(vlbwaas2.TREESET); 3114 3115 /** a sorted {@code LinkedList<String>} of {@link FileNode#getFullPathName()} */ 3116 public static final RetTypeChoice<LinkedList<String>> SORTED_FULLPATH_LINKEDLIST = 3117 new RetTypeChoice<>(vlbwaas2.LINKEDLIST); 3118 3119 /** a sorted {@code Stack<String>} of {@link FileNode#getFullPathName()} */ 3120 public static final RetTypeChoice<Stack<String>> SORTED_FULLPATH_STACK = 3121 new RetTypeChoice<>(vlbwaas2.STACK); 3122 3123 3124 3125 private static final VarListBuilderWithSortAndApply<FileNode, String> vlbwsaa1 = 3126 new VarListBuilderWithSortAndApply<> 3127 (BY_DATE, (FileNode fn) -> fn.name, String.class); 3128 3129 /** a sorted {@code Vector<String>} of {@link FileNode#name}. */ 3130 public static final RetTypeChoice<Vector<String>> SORTED_BY_DATE_FILENAME_VECTOR = 3131 new RetTypeChoice<>(vlbwsaa1.VECTOR); 3132 3133 /** a sorted {@code ArrayList<String>} of {@link FileNode#name}. */ 3134 public static final RetTypeChoice<ArrayList<String>> SORTED_BY_DATE_FILENAME_ARRAYLIST = 3135 new RetTypeChoice<>(vlbwsaa1.ARRAYLIST); 3136 3137 /** a sorted {@code Stream<String>} of {@link FileNode#name}. */ 3138 public static final RetTypeChoice<Stream<String>> SORTED_BY_DATE_FILENAME_STREAM = 3139 new RetTypeChoice<>(vlbwsaa1.STREAM); 3140 3141 /** a sorted {@code Stream.Builder<String>} of {@link FileNode#name}. */ 3142 public static final RetTypeChoice<Stream.Builder<String>> 3143 SORTED_BY_DATE_FILENAME_STREAM_BUILDER = new RetTypeChoice<>(vlbwsaa1.STREAM_BUILDER); 3144 3145 /** a sorted {@code String[]} of {@link FileNode#name}. */ 3146 public static final RetTypeChoice<String[]> SORTED_BY_DATE_FILENAME_ARRAY = 3147 new RetTypeChoice<>(vlbwsaa1.ARRAY); 3148 3149 /** a sorted {@code Iterator<String>} of {@link FileNode#name}. */ 3150 public static final RetTypeChoice<Iterator<String>> SORTED_BY_DATE_FILENAME_ITERATOR = 3151 new RetTypeChoice<>(vlbwsaa1.ITERATOR); 3152 3153 /** a sorted {@code LinkedList<String>} of {@link FileNode#name}. */ 3154 public static final RetTypeChoice<LinkedList<String>> SORTED_BY_DATE_FILENAME_LINKEDLIST = 3155 new RetTypeChoice<>(vlbwsaa1.LINKEDLIST); 3156 3157 /** a sorted {@code Stack<String>} of {@link FileNode#name}. */ 3158 public static final RetTypeChoice<Stack<String>> SORTED_BY_DATE_FILENAME_STACK = 3159 new RetTypeChoice<>(vlbwsaa1.STACK); 3160 3161 3162 3163 private static final VarListBuilderWithSortAndApply<FileNode, String> vlbwsaa2 = 3164 new VarListBuilderWithSortAndApply<> 3165 (BY_DATE, (FileNode fn) -> fn.getFullPathName(), String.class); 3166 3167 /** a sorted {@code Vector<String>} of {@link FileNode#getFullPathName()}. */ 3168 public static final RetTypeChoice<Vector<String>> SORTED_BY_DATE_FULLPATH_VECTOR = 3169 new RetTypeChoice<>(vlbwsaa2.VECTOR); 3170 3171 /** a sorted {@code ArrayList<String>} of {@link FileNode#getFullPathName()}. */ 3172 public static final RetTypeChoice<ArrayList<String>> SORTED_BY_DATE_FULLPATH_ARRAYLIST = 3173 new RetTypeChoice<>(vlbwsaa2.ARRAYLIST); 3174 3175 /** a sorted {@code Stream<String>} of {@link FileNode#getFullPathName()}. */ 3176 public static final RetTypeChoice<Stream<String>> SORTED_BY_DATE_FULLPATH_STREAM = 3177 new RetTypeChoice<>(vlbwsaa2.STREAM); 3178 3179 /** a sorted {@code Stream.Builder<String>} of {@link FileNode#getFullPathName()}. */ 3180 public static final RetTypeChoice<Stream.Builder<String>> 3181 SORTED_BY_DATE_FULLPATH_STREAM_BUILDER = new RetTypeChoice<>(vlbwsaa2.STREAM_BUILDER); 3182 3183 /** a sorted {@code String[]} of {@link FileNode#getFullPathName()}. */ 3184 public static final RetTypeChoice<String[]> SORTED_BY_DATE_FULLPATH_ARRAY = 3185 new RetTypeChoice<>(vlbwsaa2.ARRAY); 3186 3187 /** a sorted {@code Iterator<String>} of {@link FileNode#getFullPathName()}. */ 3188 public static final RetTypeChoice<Iterator<String>> SORTED_BY_DATE_FULLPATH_ITERATOR = 3189 new RetTypeChoice<>(vlbwsaa2.ITERATOR); 3190 3191 /** a sorted {@code LinkedList<String>} of {@link FileNode#getFullPathName()}. */ 3192 public static final RetTypeChoice<LinkedList<String>> SORTED_BY_DATE_FULLPATH_LINKEDLIST = 3193 new RetTypeChoice<>(vlbwsaa2.LINKEDLIST); 3194 3195 /** a sorted {@code Stack<String>} of {@link FileNode#getFullPathName()}. */ 3196 public static final RetTypeChoice<Stack<String>> SORTED_BY_DATE_FULLPATH_STACK = 3197 new RetTypeChoice<>(vlbwsaa2.STACK); 3198 3199 3200 3201 private static final VarListBuilderWithSortAndApply<FileNode, String> vlbwsaa3 = 3202 new VarListBuilderWithSortAndApply<> 3203 (BY_FILE_SIZE, (FileNode fn) -> fn.name, String.class); 3204 3205 /** a sorted {@code Vector<String>} of {@link FileNode#name}. */ 3206 public static final RetTypeChoice<Vector<String>> SORTED_BY_SIZE_FILENAME_VECTOR = 3207 new RetTypeChoice<>(vlbwsaa3.VECTOR); 3208 3209 /** a sorted {@code ArrayList<String>} of {@link FileNode#name}. */ 3210 public static final RetTypeChoice<ArrayList<String>> SORTED_BY_SIZE_FILENAME_ARRAYLIST = 3211 new RetTypeChoice<>(vlbwsaa3.ARRAYLIST); 3212 3213 /** a sorted {@code Stream<String>} of {@link FileNode#name}. */ 3214 public static final RetTypeChoice<Stream<String>> SORTED_BY_SIZE_FILENAME_STREAM = 3215 new RetTypeChoice<>(vlbwsaa3.STREAM); 3216 3217 /** a sorted {@code Stream.Builder<String>} of {@link FileNode#name}. */ 3218 public static final RetTypeChoice<Stream.Builder<String>> 3219 SORTED_BY_SIZE_FILENAME_STREAM_BUILDER = new RetTypeChoice<>(vlbwsaa3.STREAM_BUILDER); 3220 3221 /** a sorted {@code String[]} of {@link FileNode#name}. */ 3222 public static final RetTypeChoice<String[]> SORTED_BY_SIZE_FILENAME_ARRAY = 3223 new RetTypeChoice<>(vlbwsaa3.ARRAY); 3224 3225 /** a sorted {@code Iterator<String>} of {@link FileNode#name}. */ 3226 public static final RetTypeChoice<Iterator<String>> SORTED_BY_SIZE_FILENAME_ITERATOR = 3227 new RetTypeChoice<>(vlbwsaa3.ITERATOR); 3228 3229 /** a sorted {@code LinkedList<String>} of {@link FileNode#name}. */ 3230 public static final RetTypeChoice<LinkedList<String>> SORTED_BY_SIZE_FILENAME_LINKEDLIST = 3231 new RetTypeChoice<>(vlbwsaa3.LINKEDLIST); 3232 3233 /** a sorted {@code Stack<String>} of {@link FileNode#name}. */ 3234 public static final RetTypeChoice<Stack<String>> SORTED_BY_SIZE_FILENAME_STACK = 3235 new RetTypeChoice<>(vlbwsaa3.STACK); 3236 3237 3238 3239 private static final VarListBuilderWithSortAndApply<FileNode, String> vlbwsaa4 = 3240 new VarListBuilderWithSortAndApply<> 3241 (BY_FILE_SIZE, (FileNode fn) -> fn.getFullPathName(), String.class); 3242 3243 /** a sorted {@code Vector<String>} of {@link FileNode#getFullPathName()}. */ 3244 public static final RetTypeChoice<Vector<String>> SORTED_BY_SIZE_FULLPATH_VECTOR = 3245 new RetTypeChoice<>(vlbwsaa4.VECTOR); 3246 3247 /** a sorted {@code ArrayList<String>} of {@link FileNode#getFullPathName()}. */ 3248 public static final RetTypeChoice<ArrayList<String>> SORTED_BY_SIZE_FULLPATH_ARRAYLIST = 3249 new RetTypeChoice<>(vlbwsaa4.ARRAYLIST); 3250 3251 /** a sorted {@code Stream<String>} of {@link FileNode#getFullPathName()}. */ 3252 public static final RetTypeChoice<Stream<String>> SORTED_BY_SIZE_FULLPATH_STREAM = 3253 new RetTypeChoice<>(vlbwsaa4.STREAM); 3254 3255 /** a sorted {@code Stream.Builder<String>} of {@link FileNode#getFullPathName()}. */ 3256 public static final RetTypeChoice<Stream.Builder<String>> 3257 SORTED_BY_SIZE_FULLPATH_STREAM_BUILDER = new RetTypeChoice<>(vlbwsaa4.STREAM_BUILDER); 3258 3259 /** a sorted {@code String<String>} of {@link FileNode#getFullPathName()}. */ 3260 public static final RetTypeChoice<String[]> SORTED_BY_SIZE_FULLPATH_ARRAY = 3261 new RetTypeChoice<>(vlbwsaa4.ARRAY); 3262 3263 /** a sorted {@code Iterator<String>} of {@link FileNode#getFullPathName()}. */ 3264 public static final RetTypeChoice<Iterator<String>> SORTED_BY_SIZE_FULLPATH_ITERATOR = 3265 new RetTypeChoice<>(vlbwsaa4.ITERATOR); 3266 3267 /** a sorted {@code LinkedList<String>} of {@link FileNode#getFullPathName()}. */ 3268 public static final RetTypeChoice<LinkedList<String>> SORTED_BY_SIZE_FULLPATH_LINKEDLIST = 3269 new RetTypeChoice<>(vlbwsaa4.LINKEDLIST); 3270 3271 /** a sorted {@code Stack<String>} of {@link FileNode#getFullPathName()}. */ 3272 public static final RetTypeChoice<Stack<String>> SORTED_BY_SIZE_FULLPATH_STACK = 3273 new RetTypeChoice<>(vlbwsaa4.STACK); 3274 } 3275}