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.


    FileNode-Tree Changes:
    The file-moving (file-transfer) methods provided in this class will not modify or manipulate the FileNode-Tree in any way whatsoever. In order to maintain consistency with the File-System, it would be smarter, after a file delete, move, copy or transfer operation, to reload the FileNode-Tree structure again, from disk.

    Again, in order to to make sure that the FileNode-Tree being used actually mirrors the underlying File-System's structure, the programmer must perform another loadTree(...) call after any / all move, delete & copy operations have been completed.


    Redundancy & WORA:
    This class is (somewhat) a "redundant version" of the class Shell found within this same package. This class can do many of the move and copy operations that are done there.

    This class, though, is Operating-System Independent - meaning that it fulfills Java's Standard WORA Pledage. The methods in class Shell work specifically on UNIX Platforms only.



    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 expects an implementation of Java's java.lang.Appendable interface 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.StorageWriter Sends text to System.out, and saves it, internally.
        FileWriter, PrintWriter, StringWriter General purpose java text-output classes
        FileOutputStream, PrintStream More general-purpose java text-output classes

        Checked IOException:
        The Appendable interface requires that the Checked-Exception IOException be caught when using its append(...) 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(RTC), 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(RTC), 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 expects an implementation of Java's java.lang.Appendable interface 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.StorageWriter Sends text to System.out, and saves it, internally.
        FileWriter, PrintWriter, StringWriter General purpose java text-output classes
        FileOutputStream, PrintStream More general-purpose java text-output classes

        Checked IOException:
        The Appendable interface requires that the Checked-Exception IOException be caught when using its append(...) 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(RTC), 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:
        When, after a delete, a directory or sub-directory is not empty because the User-Provided Filters requested to skip the deletion of some of the sub-diretories or files, this method will therefore be unable to remove these sub-directory branches from the File-System.

        This behavior is largely consistent with standard UNIX and MS-DOS commands such as 'cp', 'mv', 'copy' etc... Under these Operating-Systems, non-empty directories cannot be deleted until their contents have been removed completely.

        Appendable Log:
        If a non-null Appendable (log) is passed to this method, notices are provided to the user as directories are removed. This may be of use for later reviewing what was deleted, and what was retained.
        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(RTC), 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.

        Method Heuristic
        All this method does is to perform, sequentially:

        1. A copy operation of a file to a new directory.
        2. A delete operation on the file from the original location.
        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 expects an implementation of Java's java.lang.Appendable interface 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.StorageWriter Sends text to System.out, and saves it, internally.
        FileWriter, PrintWriter, StringWriter General purpose java text-output classes
        FileOutputStream, PrintStream More general-purpose java text-output classes

        Checked IOException:
        The Appendable interface requires that the Checked-Exception IOException be caught when using its append(...) 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.

        Move Behavior:
        When, after a move, a sub-directory is not be completely 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 those directory-branches of the file-system tree.

        This behavior is largely consistent with standard UNIX and MS-DOS commands such as 'cp', 'mv', 'copy' etc... Under these Operating-Systems, non-empty directories cannot be deleted until their contents have been removed completely.

        Appendable Log:
        If a non-null Appendable (log) is passed to this method, notices are provided to the user as directories are removed. This may be of use for later reviewing what was deleted, and what was retained.
        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(RTC), 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);