Upload, download, delete, and rename files and directories on the Fanuc robot controller via FTP.

## Upload files

**C# : FtpFileManagementUpload**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Ftp;

public class FtpFileManagementUpload
{
    static void Main()
    {
        FanucRobot robot = new FanucRobot();
        var parameters = new ConnectionParameters("192.168.0.1");
        parameters.Ftp.Enable = true;
        parameters.Ftp.FtpUser = "";
        parameters.Ftp.FtpPassword = "";
        robot.Connect(parameters);

        /**/
        // Upload a TP program to the controller
        robot.Ftp.DirectFileHandling.UploadFileToController(@"C:\Programs\MyPrg.tp", "md:/MyPrg.tp");

        // Upload from a byte array
        byte[] fileBytes = File.ReadAllBytes(@"C:\Programs\MyPrg.tp");
        robot.Ftp.DirectFileHandling.UploadFileToController(fileBytes, "md:/MyPrg.tp");

        // Upload multiple files to a directory
        robot.Ftp.DirectFileHandling.UploadFilesToController(
            new[] { @"C:\file1.tp", @"C:\file2.tp" },
            "md:/programs/");
        /**/
    }
}
```

**Python : FtpFileManagementUpload**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Upload a TP program to the controller
robot.ftp.direct_file_handling.upload_file_to_controller(r"C:\Programs\MyPrg.tp", "md:/MyPrg.tp")

# Upload from bytes
with open(r"C:\Programs\MyPrg.tp", "rb") as f:
    file_bytes = f.read()
robot.ftp.direct_file_handling.upload_file_to_controller(file_bytes, "md:/MyPrg.tp")

# Upload multiple files to a directory
robot.ftp.direct_file_handling.upload_files_to_controller(
    [r"C:\file1.tp", r"C:\file2.tp"],
    "md:/programs/")
##
```

## Download files

**C# : FtpFileManagementDownload**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Ftp;

public class FtpFileManagementDownload
{
    static void Main()
    {
        FanucRobot robot = new FanucRobot();
        var parameters = new ConnectionParameters("192.168.0.1");
        parameters.Ftp.Enable = true;
        parameters.Ftp.FtpUser = "";
        parameters.Ftp.FtpPassword = "";
        robot.Connect(parameters);

        /**/
        // Download to a local file
        robot.Ftp.DirectFileHandling.DownloadFileFromController(@"C:\Backup\Backup.va", "md:/Backup.va");

        // Download to a byte array
        byte[] data;
        robot.Ftp.DirectFileHandling.DownloadFileFromController(out data, "md:/MyPrg.tp");

        // Download multiple files
        robot.Ftp.DirectFileHandling.DownloadFilesFromController(
            @"C:\Backup\",
            new[] { "md:/file1.tp", "md:/file2.va" });
        /**/
    }
}
```

**Python : FtpFileManagementDownload**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Download to a local file
robot.ftp.direct_file_handling.download_file_from_controller(r"C:\Backup\Backup.va", "md:/Backup.va")

# Download to bytes
data = robot.ftp.direct_file_handling.download_file_from_controller_as_bytes("md:/MyPrg.tp")

# Download multiple files
robot.ftp.direct_file_handling.download_files_from_controller(
    r"C:\Backup\\",
    ["md:/file1.tp", "md:/file2.va"])
##
```

## Delete, list, and manage directories

**C# : FtpFileManagementDirectory**
```csharp
using UnderAutomation.Fanuc;
using UnderAutomation.Fanuc.Ftp;

public class FtpFileManagementDirectory
{
    static void Main()
    {
        FanucRobot robot = new FanucRobot();
        var parameters = new ConnectionParameters("192.168.0.1");
        parameters.Ftp.Enable = true;
        parameters.Ftp.FtpUser = "";
        parameters.Ftp.FtpPassword = "";
        robot.Connect(parameters);

        /**/
        // Delete a file
        robot.Ftp.DirectFileHandling.DeleteFile("md:/OldProgram.tp");

        // Delete a directory and its contents
        robot.Ftp.DirectFileHandling.DeleteDirectory("md:/OldFolder");

        // Check if a directory exists
        bool exists = robot.Ftp.DirectFileHandling.DirectoryExists("md:/programs");

        // Create a directory
        robot.Ftp.DirectFileHandling.CreateDirectory("md:/NewFolder");

        // List files and directories
        FtpListItem[] items = robot.Ftp.DirectFileHandling.GetListing("md:/");
        foreach (var item in items)
        {
            Console.WriteLine($"{item.Name} ({item.Type}) - {item.Size} bytes");
        }

        // Rename or move a file
        robot.Ftp.DirectFileHandling.Rename("md:/old.tp", "md:/new.tp");
        /**/
    }
}
```

**Python : FtpFileManagementDirectory**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Delete a file
robot.ftp.direct_file_handling.delete_file("md:/OldProgram.tp")

# Delete a directory and its contents
robot.ftp.direct_file_handling.delete_directory("md:/OldFolder")

# Check if a directory exists
exists = robot.ftp.direct_file_handling.directory_exists("md:/programs")

# Create a directory
robot.ftp.direct_file_handling.create_directory("md:/NewFolder")

# List files and directories
items = robot.ftp.direct_file_handling.get_listing("md:/")
for item in items:
    print(f"{item.name} ({item.type}) - {item.size} bytes")

# Rename or move a file
robot.ftp.direct_file_handling.rename("md:/old.tp", "md:/new.tp")
##
```

## Complete example

**C# : FtpFileManagement**
```csharp
using UnderAutomation.Fanuc;

public class FtpFileManagement
{
  static void Main()
  {
    FanucRobot robot = new FanucRobot();
    ConnectionParameters parameters = new ConnectionParameters("192.168.0.1");
    parameters.Ftp.Enable = true;
    parameters.Ftp.FtpUser = "";
    parameters.Ftp.FtpPassword = "";
    robot.Connect(parameters);

    /**/
    // Upload a TP program to the controller
    robot.Ftp.DirectFileHandling.UploadFileToController(@"C:\Programs\MyPrg.tp", "md:/MyPrg.tp");

    // Download a file from the robot
    robot.Ftp.DirectFileHandling.DownloadFileFromController(@"C:\Backup\Backup.va", "md:/Backup.va");

    // Delete a file
    robot.Ftp.DirectFileHandling.DeleteFile("md:/OldProgram.tp");

    // List files in a directory
    var items = robot.Ftp.DirectFileHandling.GetListing("md:/");
    foreach (var item in items)
      Console.WriteLine($"{item.Name} ({item.Type})");

    // Create and delete directories
    robot.Ftp.DirectFileHandling.CreateDirectory("md:/NewFolder");

    // Rename a file
    robot.Ftp.DirectFileHandling.Rename("md:/old.tp", "md:/new.tp");

    // Check file existence
    bool exists = robot.Ftp.DirectFileHandling.FileExists("md:/MyPrg.tp");
    /**/
  }
}
```

**Python : FtpFileManagement**
```python
from underautomation.fanuc.fanuc_robot import FanucRobot
from underautomation.fanuc.connection_parameters import ConnectionParameters

robot = FanucRobot()
parameters = ConnectionParameters("192.168.0.1")
parameters.ftp.enable = True
parameters.ftp.ftp_user = ""
parameters.ftp.ftp_password = ""
robot.connect(parameters)

##
# Upload a TP program to the controller
robot.ftp.direct_file_handling.upload_file_to_controller("C:/Programs/MyPrg.tp", "md:/MyPrg.tp")

# Download a file from the robot
robot.ftp.direct_file_handling.download_file_from_controller("C:/Backup/Backup.va", "md:/Backup.va")

# Delete a file
robot.ftp.direct_file_handling.delete_file("md:/OldProgram.tp")

# List files in a directory
items = robot.ftp.direct_file_handling.get_listing("md:/")
for item in items:
    print(f"{item.name} ({item.type})")

# Create a directory
robot.ftp.direct_file_handling.create_directory("md:/NewFolder")

# Rename a file
robot.ftp.direct_file_handling.rename("md:/old.tp", "md:/new.tp")

# Check file existence
exists = robot.ftp.direct_file_handling.file_exists("md:/MyPrg.tp")
##
```

## API reference

**Members of Ftp.Internal.FtpDirectFileHandling**
```csharp
public class FtpDirectFileHandling {
    // Creates a directory on the controller. If the preceding
    // directories do not exist, then they are created.
    public void CreateDirectory(string path)

    // Deletes the specified directory and all its contents.
    public void DeleteDirectory(string path)

    // Deletes a file on the controller
    public void DeleteFile(string path)

    // Tests if the specified directory exists on the controller. This
    // method works by trying to change the working directory to
    // the path specified. If it succeeds, the directory is changed
    // back to the old working directory and true is returned. False
    // is returned otherwise and since the CWD failed it is assumed
    // the working directory is still the same.
    public bool DirectoryExists(string path)

    // Downloads the specified file and return the raw byte array.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it downloads data in chunks.
    public bool DownloadFileFromController(out byte[] outBytes, string remotePath, OnProgressDelegate progress = null)

    // Downloads the specified file into the specified stream.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it downloads data in chunks.
    public bool DownloadFileFromController(Stream outStream, string remotePath, OnProgressDelegate progress = null)

    // Downloads the specified file onto the local file system.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it downloads data in chunks.
    // It overwrites the file if it already exists.
    public bool DownloadFileFromController(string localPath, string remotePath, OnProgressDelegate progress = null)

    // Downloads the specified files into a local single directory.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it downloads data in chunks.
    public string[] DownloadFilesFromController(string localDir, string[] remotePaths, OnProgressDelegate progress = null)

    // Checks if a file exists on the controller.
    public bool FileExists(string path)

    // Gets a file listing from the controller. Each <xref href="UnderAutomation.Fanuc.Ftp.FtpListItem" data-throw-if-not-resolved="false"></xref> object returned
    // contains information about the file that was able to be retrieved.
    public FtpListItem[] GetListing(string path)

    // Returns information about a file system object. Returns null if the controller response can't
    // be parsed or the controller returns a failure completion code. The error for a failure
    // is logged with FtpTrace. No exception is thrown on error because that would negate
    // the usefulness of this method for checking for the existence of an object.
    public FtpListItem GetObjectInfo(string path)

    // Renames an object on the remote file system.
    // Throws exceptions if the file does not exist, or if the destination file already exists.
    public void Rename(string path, string dest)

    // Uploads the specified byte array as a file onto the controller.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it uploads data in chunks.
    // It overwrites file if it already exists.
    public bool UploadFileToController(byte[] fileData, string remotePath, bool createRemoteDir = false, OnProgressDelegate progress = null)

    // Uploads the specified stream as a file onto the controller.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it uploads data in chunks.
    // It overwrites file if it already exists.
    public bool UploadFileToController(Stream fileStream, string remotePath, bool createRemoteDir = false, OnProgressDelegate progress = null)

    // Uploads the specified file directly onto the controller.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it uploads data in chunks.
    public bool UploadFileToController(string localPath, string remotePath, bool createRemoteDir = false, OnProgressDelegate progress = null)

    // Uploads the given file paths to a single folder on the controller.
    // All files are placed directly into the given folder regardless of their path on the local filesystem.
    // High-level API that takes care of various edge cases internally.
    // Supports very large files since it uploads data in chunks.
    public string[] UploadFilesToController(string[] localPaths, string remoteDir, OnProgressDelegate progress = null)
}
```

**Members of Ftp.FtpListItem**
```csharp
public class FtpListItem {
    // Gets the file permissions in the CHMOD format.
    public int Chmod { get; }

    // Gets the created date of the object.
    public DateTime Created { get; }

    // Gets the full path name to the object.
    public string FullName { get; }

    // Gets the last write time of the object.
    public DateTime Modified { get; }

    // Gets name to the object.
    public string Name { get; }

    // Gets the size of the object. Only a few files (like *.tp or *.df) have a size that can be retrieved, for most files this is 0 even if they are not empty. For directories this is always 0.
    public long Size { get; }

    // Gets the type of file system object.
    public FtpFileSystemObjectType Type { get; }
}
```