Package Torello.Java

Class FileTransfer


  • public class FileTransfer
    extends java.lang.Object
    Operating-System independent utilities for moving, copying and deleting files, or an entire tree of files - using the FileNode class.

    This class allows a user to copy directories of files, and even entire sub-directory-trees of files from a source directory on the underlying file-system to a target-directory.


    IMPORTANT:
    The file-moving (file-transfer) elements provided in this class will not manipulate the FileNode-tree itself, in any way - shape or form. In order to guarantee consistency with the file-system, it would be smarter, after a file delete, move, copy or transfer to reload a FileNode-tree structure again, from the start.

    This class is kept separate from the FileNode class, primarily because the moving, copying, and deleting of files that occur as a result of these methods will not be reflected in the FileNode tree that exists in Java Memory. Rather, if the programmer would like to make sure that the FileNode-tree that he is using is mirroring the underlying operating-system's file-system remains, he should do another "loadTree()" operation after any and all moves, deletes and copies he or she has performed.

    This also guarantees that the class FileNode remains as independent as possible from method calls and invocations that would perform Operating-System File-Writes - as pledged in that class documentation-header.


    REDUNDANCY NOTE:
    This class is "sort-of" a "redundant version" of the class Shell inside this same package. This class is included because although the UNIX-Shell is also (obviously) capable of performing all of these operations very easily, if you are not using UNIX, the methods here actually work on any operating system, such as Windows/DOS and Apple.



    Here, below, is a sample use if a 'delete' method from this class:

    Example:
    import Torello.Java.FileTransfer;
    
    // The following commands delete all files in the directory-named by the string below:
    // Log information will be sent to the terminal (System.out)
    
    FileNode fn = FileNode
        .createRoot("some/directory/mydir/")
        .loadTree();
    
    FileTransfer.deleteFilesRecursive(fn, null, null, System.out);
    



    Stateless Class:
    This class neither contains any program-state, nor can it be instantiated. The @StaticFunctional Annotation may also be called 'The Spaghetti Report'. Static-Functional classes are, essentially, C-Styled Files, without any constructors or non-static member fields. It is a concept very similar to the Java-Bean's @Stateless Annotation.
    • 1 Constructor(s), 1 declared private, zero-argument constructor
    • 13 Method(s), 13 declared static
    • 0 Field(s)


    • Method Detail

      • copy

        🡇    
        public static int copy​(FileNode directory,
                               FileNodeFilter filter,
                               java.lang.String targetDirectory,
                               java.lang.Appendable a)
                        throws java.io.IOException,
                               SameSourceAndTargetException,
                               java.nio.file.InvalidPathException,
                               java.nio.file.NoSuchFileException
        Copies the contents of one directory to another. Avoids copying files that do not pass the filter test. This method will only copy files and will avoid copying any sub-directories to the target directory.

        Example:
         // This loads all available files in the 'javadoc/' directory-tree for package Torello.HTML
         FileNode fn = FileNode
                         .createRoot("javadoc/Torello/HTML/")
                         .loadTree();
         
         // This will copy all '.html' files in directory 'javadoc/Torello/HTML/' to a temp directory.
         // Log information (copy messages) will be printed to standard-out.  If the programmer is on a
         // UNIX system, they will be colorized using UNIX terminal color-codes.
         // NOTE: The directory 'temp/' must have already been created.
         FileTransfer.copy(fn, f -> f.name.endsWith(".html"), "temp/", System.out);
        
        Parameters:
        directory - This must be a "directory" not a "file" instance of public class FileNode or an exception shall be thrown. If this class is a directory, then every file that is currently in this directory shall be copied to the 'targetDirectory.' This parameter may not be null.
        filter - This parameter may be null, but if it is not, each file will be tested by this java-lambda for identifying whether or not it meets the "accept" or "reject" interface before copying is performed.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the file in question should be copied, and FALSE if no copy is needed.
        targetDirectory - Where the files shall be copied. This must be a valid directory as well, or else a FileNotFoundException shall throw. This method will not create this directory if it does not exist. See method java.io.File.mkdirs() for information on how to create files on the file-system.

        NOTE: It is expected that the last character in this String contain a directory-separator character (on UNIX, this is the forward-slash ('/') and in MS-DOS, Windows this is the back-slash ('\'). If this character is not present, if this String does not 'end-with' a java.io.File.separator then one will be appended to the end of this String.
        a - This parameter may be null, but if it is not, then debugging / logging / informational messages will be sent to this output. This parameter expects an implementation of Java's interface java.lang.Appendable which allows for a wide range of options when logging intermediate messages.
        Class or Interface InstanceUse & Purpose
        'System.out'Sends text to the standard-out terminal
        Torello.Java.StorageWriterSends text to System.out, and saves it, internally.
        FileWriter, PrintWriter, StringWriterGeneral purpose java text-output classes
        FileOutputStream, PrintStreamMore general-purpose java text-output classes

        IMPORTANT: The interface Appendable requires that the check exception IOException must be caught when using its append(CharSequence) methods.
        Returns:
        The number of files that were copied.
        Throws:
        DirExpectedException - If you pass a "file" instance of class FileNode to parameter 'directory.'
        WritableDirectoryException - If the target-directory is not available to Java for copying.
        java.nio.file.NoSuchFileException - This will be thrown if the logic which checks to ensure that the source and target directories are not identical is unable to identify the real path name of either the source or target directory. One such possible situation where this would happen would be if the user applied the UNIX tilda ('~') in either the source or target directory-name.
        java.nio.file.InvalidPathException - This will be thrown if class java.nio.file.Paths is unable to instantiate a java.nio.file.Path for either the source-directory (parameter directory), or the targetDirectory.
        SameSourceAndTargetException - This will be thrown if the source and target directories are found to point to identical locations on the file-system.
        java.io.IOException - For any IO filesystem errors.
        See Also:
        copyRecursive(FileNode, FileNodeFilter, FileNodeFilter, String, Appendable), FileNode.getDirContentsFiles(VarList), DirExpectedException.check(FileNode), WritableDirectoryException.check(String), SameSourceAndTargetException.check(FileNode, String)
        Code:
        Exact Method Body:
         // The purpose of "INTERNAL" here is that we only need to check the input ONCE.
        
         DirExpectedException.check(directory);
         WritableDirectoryException.check(targetDirectory);
         SameSourceAndTargetException.check(directory, targetDirectory);
        
         if (! targetDirectory.endsWith(File.separator))
             targetDirectory = targetDirectory + File.separator;
        
         return copyINTERNAL(directory, filter, targetDirectory, a);
        
      • copyRecursive

        🡅  🡇    
        public static int copyRecursive​(FileNode directory,
                                        FileNodeFilter fileFilter,
                                        FileNodeFilter dirFilter,
                                        java.lang.String targetDirectory,
                                        java.lang.Appendable a)
                                 throws java.io.IOException,
                                        SameSourceAndTargetException,
                                        java.nio.file.InvalidPathException,
                                        java.nio.file.NoSuchFileException
        Copies an entire directory tree to a target-directory. Note, this class will use the java.io.File.mkdirs() method to create any sub-directories that exists in the source-directory-tree, but not in the target-directory-tree.
        Parameters:
        directory - This is the source or "root node" of the directory-tree that needs to be (recursively) copied to the 'targetDirectory'. This FileNode must be a directory, or else an DirExpectedException will be thrown. This parameter may not be null.
        fileFilter - If the programmer using this method would like to maintain some control in deciding which files are copied - copying some, but not others - to the destination / target-directory, the provide a Java Predicate which makes decisions on which files to copy to the target-directory, and which files to leave out of the copy process.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the file in question should be copied, and FALSE if no copy is needed.

        NOTE: This parameter may be null, and if it is it shall just be ignored. This is the default case, and all files found in each-and-every-level of the source directory tree will be copied to the target-directory.
        dirFilter - If the programmer using this method would like to skip entire branches of the source directory tree, then implement a java predicate that identifies which sub-directories (read: 'branches') of the source directory-tree should be skipped. This parameter (a java.util.function.Predicate<FileNode>) shall receive file-system directories (not files!) as input to its public boolean test() method, and if this method returns FALSE, the branch that was passed to the Predicate shall be skipped entirely by this copy-routine.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the sub-directory in question should be traversed and copied, and FALSE in order to skip the provided sub-directory entirely from the copy process.

        NOTE: If this parameter is null, it shall just be ignored. This is the default setting, and when this parameter is null, all branches (all sub-directories) of the FileNode parameter 'fn' shall be copied to 'targetDirectory'.

        SUBTLE NOTE: The following two examples will hopefully clarify an issue about filters. The parameter 'fileFilter' is, in most cases, more useable than the 'dirFilter' parameter. The 'dirFilter' will force the code skip an entire branch of the directory tree without traversing it. See this example below where the programmer is attempting to copy all files/classes in the javadoc/Torello/HTML/NodeSearch/ directory that have the word 'TagNode'

        Example:
         // These lines will load the "javadoc" documentation files for this jar into a FileNode Tree.
         // These are mostly the '.html' files for the code-documentation you are reading right now.
         FileNode fn = FileNode
              .createRoot("javadoc/")
              .loadTree();
         
         // THIS WILL FAIL to copy the "TagNode" files in the "NodeSearch" directory to 'temp/'
         FileTransfer.copyRecursive(
              fn,
              f -> f.toString().contains("TagNode"),      // Expecting any file having "TagNode" in it's name
              f -> f.toString().contains("NodeSearch"),   // Supposedly expecting directories having "NodeSearch" in their name
              "temp/", System.out
         );
         // FAILS TO COPY ANY FILES: The directory predicate BLOCKED the first sub-directory from loading!
        
         // THIS WILL SUCCEED
         FileTransfer.copyRecursive(
              fn,
              f -> StrCmpr.containsAND(f.toString(), "TagNode", "NodeSearch"),     
              null,
              "temp/", System.out
         );
         // This SUCCEEDS since the f.toString() method will return the FULL PATH NAME of any file.
         // File's having "TagNode" or "NodeSearch" in their file name, or sub-directory path will result
         // in the file predicate returning TRUE.  16 Files here will be copied to 'temp/'
         // NOTE:  The files are javadoc/Torello/HTML/NodeSearch/TagNodeFind.html, and others...
        
        targetDirectory - Where the files shall be copied. This must be a valid directory as well, or else a FileNotFoundException shall throw. This method will not create this directory if it does not exist. See method java.io.File.mkdirs() for information on how to create files on the file-system.

        NOTE: It is expected that the last character in this String contain a directory-separator character (on UNIX, this is the forward-slash ('/') and in MS-DOS, Windows this is the back-slash ('\'). If this character is not present, if this String does not 'end-with' a java.io.File.separator then one will be appended to the end of this String.
        a - This parameter may be null, but if it is not, then debugging / logging / informational messages will be sent to this output.
        Returns:
        This method makes calls to the single-level, single-directory-version of the copy(...) method in this class for each directory found in the tree. This method shall sum-up all and count all the files as they are copied. The value returned by this method is an integer specified how many files were copied in the process.
        Throws:
        DirExpectedException - If you pass a "file" instance of class FileNode to parameter 'directory.'
        WritableDirectoryException - If the initial target-directory, itself, is not available to Java for copying, then this exception shall throw. In actuality, all sub-directories that need to be created will be created by this recursive-copy operation - except for the highest-level "top directory" (the one indicated by the parameter 'targetDirectory' - because if that doesn't exist, then this 'WritableDirectoryException' will throw).
        java.nio.file.NoSuchFileException - This will be thrown if the logic which checks to ensure that the source and target directories are not identical is unable to identify the real path name of either the source or target directory. One such possible situation where this would happen would be if the user applied the UNIX tilda ('~') in either the source or target directory-name.
        java.nio.file.InvalidPathException - This will be thrown if class java.nio.file.Paths is unable to instantiate a java.nio.file.Path for either the source-directory (parameter directory), or the targetDirectory.
        SameSourceAndTargetException - This will be thrown if the source and target directories are found to point to identical locations on the file-system.
        java.io.IOException - For any IO filesystem errors.
        See Also:
        copy(FileNode, FileNodeFilter, String, Appendable), FileNode.getDirContentsDirs(VarList), DirExpectedException.check(FileNode), WritableDirectoryException.check(String), SameSourceAndTargetException.check(FileNode, String)
        Code:
        Exact Method Body:
         // The purpose of "INTERNAL" here is that we only need to check the input ONCE.
        
         DirExpectedException.check(directory);
         WritableDirectoryException.check(targetDirectory);
         SameSourceAndTargetException.check(directory, targetDirectory);
        
         if (! targetDirectory.endsWith(File.separator))
             targetDirectory = targetDirectory + File.separator;
        
         return copyRecursiveINTERNAL(directory, fileFilter, dirFilter, targetDirectory, a);
        
      • deleteFiles

        🡅  🡇    
        public static int deleteFiles​(FileNode directory,
                                      FileNodeFilter filter,
                                      java.lang.Appendable a)
                               throws java.io.IOException
        This method will delete files (not sub-directories) from a source directory. This method is not recursive, and will not delete files from sub-directories. Files in all other directories of the directory tree that begins with parameter FileNode 'directory' shall all be left-alone, except the files inside the contents of parameter FileNode 'directory' itself.
        Parameters:
        directory - This is the source or "root node" of the directory-tree that needs to be (recursively) copied to the targetDirectory. This FileNode must be a directory, or else a DirExpectedException will be thrown. This parameter may not be null.
        filter - If the programmer using this method would like to maintain some control in deciding which files are deleted - deleting some, but not others - from 'directory', then he / she should provide a java.util.function.Predicate<FileNode> here using the 'filter' parameter which makes decisions on which files to delete, and which to leave alone.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the file in question should be deleted, and FALSE if no delete is needed.

        NOTE: This parameter may be null, and if it is it shall just be ignored, and every file found inside parameter 'directory' will be removed from the file-system.
        a - This parameter may be null, but if it is not, then debugging / logging / informational messages will be sent to this output. This parameter expects an implementation of Java's interface java.lang.Appendable which allows for a wide range of options when logging intermediate messages.
        Class or Interface InstanceUse & Purpose
        'System.out'Sends text to the standard-out terminal
        Torello.Java.StorageWriterSends text to System.out, and saves it, internally.
        FileWriter, PrintWriter, StringWriterGeneral purpose java text-output classes
        FileOutputStream, PrintStreamMore general-purpose java text-output classes

        IMPORTANT: The interface Appendable requires that the check exception IOException must be caught when using its append(CharSequence) methods.
        Returns:
        An integer that reports how many files were deleted from the file-system.

        NOTE: Only files will be deleted by this method, no directories shall be removed. Also, the only files that are deleted will be the ones directly found, which are direct-descendants of parameter FileNode 'directory' This method is not recursive, and the directory tree will not be traversed.
        Throws:
        DirExpectedException - If you pass a "file" instance of class FileNode to parameter 'directory'.
        java.io.IOException - For any IO file-system errors.
        See Also:
        deleteFilesRecursive(FileNode, FileNodeFilter, FileNodeFilter, Appendable), FileNode.getDirContentsFiles(VarList), FileNode.getJavaIOFile(), DirExpectedException.check(FileNode)
        Code:
        Exact Method Body:
         // The purpose of "INTERNAL" here is that we only need to check the input ONCE.
         DirExpectedException.check(directory);
         return deleteFilesINTERNAL(directory, filter, a);
        
      • deleteFilesRecursive

        🡅  🡇    
        public static int deleteFilesRecursive​(FileNode directory,
                                               FileNodeFilter fileFilter,
                                               FileNodeFilter dirFilter,
                                               java.lang.Appendable a)
                                        throws java.io.IOException
        Deletes files sub-directories from a FileNode.

        DELETION BEHAVIOR NOTE: When, after a delete, the contents of a directory or sub-directory are not be empty because the filters have elected not to skip deleting some of files or sub-directories, then this method be will be unable to remove these sub-directories branches of the file-system tree. This behavior is consistent with standard UNIX and MS-DOS commands such as 'cp', 'mv', 'copy' etc... If a non-null 'log' is passed to this method, then notices will be provided as directories are removed.
        Parameters:
        directory - This is the source or "root node" of the directory-tree that needs to be (recursively) deleted. This parameter may not be null. This FileNode must be a directory, or else a DirExpectedException will be thrown.
        fileFilter - If the programmer using this method would like to maintain some control in deciding which files are deleted, then he/she must provide a Java java.util.function.Predicate<FileNode> which makes these decisions regarding which files to remove, and which files to leave alone.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the file in question should be deleted, and FALSE if no delete is needed.

        NOTE: This parameter may be null, and if it is it shall just be ignored. This is the default case, and all files found in each-and-every-level of the source directory tree will be deleted.
        dirFilter - If the programmer using this method would like to skip entire branches of the source directory tree, then implement a java predicate that identifies which sub-directories (read: 'branches') of the source directory-tree should be skipped. This parameter (a java.util.function.Predicate<FileNode>) shall receive file-system directories (not files!) as input to its public boolean test() method, and if this method returns FALSE, the branch that was passed to the Predicate shall be skipped entirely by this delete-routine.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the sub-directory in question should be traversed and deleted, and FALSE in order to skip the provided sub-directory entirely from the delete process.

        NOTE: If this parameter is null, it shall just be ignored. This is the default case, and when this parameter is null, all branches (all sub-directories) of the FileNode parameter 'fn' shall be put through the deletion process.
        a - This parameter may be null, but if it is not, then debugging / logging / informational messages will be sent to this output.
        Returns:
        This method will return an integer that reports how many files were deleted. It might be important to note that when sub-directories are deleted, they are only deleted because they were empty. Any non-empty sub-directory will be left alone, and not removed. Also, when files are deleted, they add to the "total delete count" which is the output integer from this method. However, when directories are deleted, their deletion does not contribute to the output-count.
        Throws:
        DirExpectedException - If you pass a "file" instance of class FileNode to parameter 'directory'
        java.io.IOException - For any IO file-system errors.
        See Also:
        deleteFiles(FileNode, FileNodeFilter, Appendable), FileNode.getDirContentsDirs(VarList), FileNode.getJavaIOFile(), DirExpectedException.check(FileNode)
        Code:
        Exact Method Body:
         // The purpose of "INTERNAL" here is that we only need to check the input ONCE.
         DirExpectedException.check(directory);
         return deleteFilesRecursiveINTERNAL(directory, fileFilter, dirFilter, a);
        
      • move

        🡅  🡇    
        public static int move​(FileNode directory,
                               FileNodeFilter filter,
                               java.lang.String targetDirectory,
                               java.lang.Appendable a)
                        throws java.io.IOException,
                               SameSourceAndTargetException,
                               java.nio.file.InvalidPathException,
                               java.nio.file.NoSuchFileException
        Moves the contents of one directory to another. Avoids moving files that do not pass the 'filter' test. If a log parameter ('a') is provided, textual status-updates will be printed to that log.

        NOTE: All this method does is sequentially perform: 1. A copy operation of a file, and then 2. A delete operation.
        Parameters:
        directory - This must be a "directory" not a "file" instance of public class FileNode or an exception shall be thrown. If this class is a directory, then every file that is currently in this directory shall be copied to the 'targetDirectory' - and then deleted from this directory. This parameter may not be null.
        targetDirectory - Where the files shall be moved. This must be a valid directory as well, or else a FileNotFoundException shall throw. This method will not create this directory if it does not exist. See method java.io.File.mkdirs() for information on how to create files on the file-system.

        NOTE: It is expected that the last character in this String contain a directory-separator character (on UNIX, this is the forward-slash ('/') and in MS-DOS, Windows this is the back-slash ('\'). If this character is not present, if this String does not 'end-with' a java.io.File.separator then one will be appended to the end of this String.
        filter - This parameter may be null, but if it is not, each file will be tested by this java-lambda for identifying whether or not it meets the "accept" or "reject" interface before moving is performed.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the file in question should be moved, and FALSE if no move is needed.
        a - This parameter may be null, but if it is not, then debugging / logging / informational messages will be sent to this output. This parameter expects an implementation of Java's interface java.lang.Appendable which allows for a wide range of options when logging intermediate messages.
        Class or Interface InstanceUse & Purpose
        'System.out'Sends text to the standard-out terminal
        Torello.Java.StorageWriterSends text to System.out, and saves it, internally.
        FileWriter, PrintWriter, StringWriterGeneral purpose java text-output classes
        FileOutputStream, PrintStreamMore general-purpose java text-output classes

        IMPORTANT: The interface Appendable requires that the check exception IOException must be caught when using its append(CharSequence) methods.
        Returns:
        The number of files that were moved.
        Throws:
        DirExpectedException - If you pass a "file" instance of class FileNode to parameter 'directory.'
        WritableDirectoryException - If the target-directory is not available to Java for moving.
        java.nio.file.NoSuchFileException - This will be thrown if the logic which checks to ensure that the source and target directories are not identical is unable to identify the real path name of either the source or target directory. One such possible situation where this would happen would be if the user applied the UNIX tilda ('~') in either the source or target directory-name.

        This check is crucial since when performing a MOVE operation, the contents of a directory are first copied, and then deleted. If the source and target directories are identical, then after the initial copy operation, the logic would simply delete the original files.
        java.nio.file.InvalidPathException - This will be thrown if class java.nio.file.Paths is unable to instantiate a java.nio.file.Path for either the source-directory (parameter directory), or the targetDirectory.
        SameSourceAndTargetException - This will be thrown if the source and target directories are found to point to identical locations on the file-system. Since this is a MOVE operation, when moving files, the logic first copies the files and then deletes the originals. If the source and target directories are identical, after the initial COPY operation completes, the logic would simple erase those originals - which would destroy both copies!
        java.io.IOException - For any IO file-system errors.
        See Also:
        moveRecursive(FileNode, FileNodeFilter, FileNodeFilter, String, Appendable), DirExpectedException.check(FileNode), WritableDirectoryException.check(String), SameSourceAndTargetException.check(FileNode, String)
        Code:
        Exact Method Body:
         // The purpose of "INTERNAL" here is that we only need to check the input ONCE.
        
         DirExpectedException.check(directory);
         WritableDirectoryException.check(targetDirectory);
         SameSourceAndTargetException.check(directory, targetDirectory);
        
         if (! targetDirectory.endsWith(File.separator))
             targetDirectory = targetDirectory + File.separator;
        
         return moveINTERNAL(directory, filter, targetDirectory, a);
        
      • moveRecursive

        🡅    
        public static int moveRecursive​(FileNode directory,
                                        FileNodeFilter fileFilter,
                                        FileNodeFilter dirFilter,
                                        java.lang.String targetDirectory,
                                        java.lang.Appendable a)
                                 throws java.io.IOException,
                                        SameSourceAndTargetException,
                                        java.nio.file.InvalidPathException,
                                        java.nio.file.NoSuchFileException
        Copies an entire directory tree to a target-directory, and the removes the original files & directories from their original location. Note, this class will use the java.io.File.mkdirs()' method to create any sub-directories which are present in the source-directory-tree but not are not present in the target-directory-tree.

        REMOVE BEHAVIOR NOTE: When, after a move, the contents of a directory or sub-directory are not be empty because the filters have elected not to skip moving some of files or sub-directories, then this method be will be unable to remove the old-copies of some sub-directory branches of the file-system tree. Non-empty directories will not be deleted after a move. This behavior is consistent with standard UNIX and MS-DOS commands such as 'cp', 'mv', 'copy', etc... If a non-null 'log' is passed to this method, then notices will be provided as directories are removed during the move process.
        Parameters:
        directory - This is the source or "root node" of the directory-tree that needs to be (recursively) copied to the 'targetDirectory'. This FileNode must be a directory, or else an DirExpectedException will be thrown. This parameter may not be null.
        targetDirectory - Where the files shall be moved. This must be a valid directory as well, or else a FileNotFoundException shall throw. This method will not create this directory if it does not exist. See method java.io.File.mkdirs() for information on how to create files on the file-system.

        NOTE: It is expected that the last character in this String contain a directory-separator character (on UNIX, this is the forward-slash ('/') and in MS-DOS, Windows this is the back-slash ('\'). If this character is not present, if this String does not 'end-with' a java.io.File.separator then one will be appended to the end of this String.
        fileFilter - If the programmer using this method would like to maintain some control in deciding which files are copied - copying some, but not others - to the destination / target-directory, the provide a Java java.util.function.Predicate<FileNode> which makes decisions on which files to copy to 'targetDirectory', and which files to leave out of the copy process.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the file in question should be moved, and FALSE if no move is needed.

        NOTE: This parameter may be null, and if it is it shall just be ignored. This is the default case, and all files found in each-and-every-level of the source directory tree will be copied to the targetDirectory.
        dirFilter - If the programmer using this method would like to skip entire branches of the source directory tree, then implement a java predicate that identifies which sub-directories (read: 'branches') of the source directory-tree should be skipped. This parameter (a java.util.function.Predicate<FileNode>) shall receive file-system directories (not files!) as input to its public boolean test() method, and if this method returns FALSE, the branch that was passed to the Predicate shall be skipped entirely by this move-routine.

        FILTER PREDICATE BEHAVIOR: This filter Predicate<FileNode> will return TRUE to indicate that the sub-directory in question should be traversed and moved, and FALSE in order to skip the provided sub-directory entirely from the move process.

        NOTE: If this parameter is null, it shall just be ignored. This is the default case, and when this parameter is null, all branches (all sub-directories) of the FileNode parameter 'fn' shall be copied to the target directory.
        a - This parameter may be null, but if it is not, then debugging / logging / informational messages will be sent to this output.
        Returns:
        This method makes calls to the single-level, single-directory-version of the 'copy(...)' method in this class for each directory found in the tree. This method shall sum-up all and count all the files as they are copied. The value returned by this method is an integer specified how many files were copied in the process.
        Throws:
        DirExpectedException - If you pass a "file" instance of class FileNode to parameter 'directory.'
        WritableDirectoryException - If the initial target-directory, itself, is not available to Java for copying, then this exception shall throw. In actuality, all sub-directories that need to be created will be created by this recursive-copy operation - except for the highest-level "top directory" (the one indicated by the parameter 'targetDirectory' - because if that doesn't exist, then a 'WritableDirectoryException' will throw).
        java.nio.file.NoSuchFileException - This will be thrown if the logic which checks to ensure that the source and target directories are not identical is unable to identify the real path name of either the source or target directory. One such possible situation where this would happen would be if the user applied the UNIX tilda ('~') in either the source or target directory-name.

        This check is crucial since when performing a MOVE operation, the contents of a directory are first copied, and then deleted. If the source and target directories are identical, then after the initial copy operation, the logic would simply delete the original files.
        java.nio.file.InvalidPathException - This will be thrown if class java.nio.file.Paths is unable to instantiate a java.nio.file.Path for either the source-directory (parameter directory), or the targetDirectory.
        SameSourceAndTargetException - This will be thrown if the source and target directories are found to point to identical locations on the file-system. Since this is a MOVE operation, when moving files, the logic first copies the files and then deletes the originals. If the source and target directories are identical, after the initial COPY operation completes, the logic would simple erase those originals - which would destroy both copies!
        java.io.IOException - For any IO filesystem errors.
        See Also:
        move(FileNode, FileNodeFilter, String, Appendable), FileNode.getDirContentsDirs(VarList), DirExpectedException.check(FileNode), WritableDirectoryException.check(String), SameSourceAndTargetException.check(FileNode, String)
        Code:
        Exact Method Body:
         // The purpose of "INTERNAL" here is that we only need to check the input ONCE.
        
         DirExpectedException.check(directory);
         WritableDirectoryException.check(targetDirectory);
         SameSourceAndTargetException.check(directory, targetDirectory);
        
         if (! targetDirectory.endsWith(File.separator))
             targetDirectory = targetDirectory + File.separator;
        
         return moveRecursiveINTERNAL(directory, fileFilter, dirFilter, targetDirectory, a);