14

I'm using Apache Commons FTP to upload a file. Before uploading I want to check if the file already exists on the server and make a backup from it to a backup directory on the same server.

Does anyone know how to copy a file from a FTP server to a backup directory on the same server?

public static void uploadWithCommonsFTP(File fileToBeUpload){
    FTPClient f = new FTPClient();
    FTPFile backupDirectory;
    try {
        f.connect(server.getServer());
        f.login(server.getUsername(), server.getPassword());
        FTPFile[] directories = f.listDirectories();
        FTPFile[] files = f.listFiles();
        for(FTPFile file:directories){
            if (!file.getName().equalsIgnoreCase("backup")) {
                backupDirectory=file;
            } else {
               f.makeDirectory("backup");
            }
        }
        for(FTPFile file: files){
            if(file.getName().equals(fileToBeUpload.getName())){
                //copy file to backupDirectory
            }
        }

    } catch (IOException e) {
        e.printStackTrace();
    }

}

Edited code: still there is a problem, when i backup zip file, the backup-ed file is corrupted.

Does any body know the reason for it?

 public static void backupUploadWithCommonsFTP(File fileToBeUpload) {
    FTPClient f = new FTPClient();
    boolean backupDirectoryExist = false;
    boolean fileToBeUploadExist = false;
    FTPFile backupDirectory = null;
    try {
        f.connect(server.getServer());
        f.login(server.getUsername(), server.getPassword());
        FTPFile[] directories = f.listDirectories();
        // Check for existence of backup directory
        for (FTPFile file : directories) {
            String filename = file.getName();
            if (file.isDirectory() && filename.equalsIgnoreCase("backup")) {
                backupDirectory = file;
                backupDirectoryExist = true;
                break;
            }
        }
        if (!backupDirectoryExist) {
            f.makeDirectory("backup");
        }
        // Check if file already exist on the server
        f.changeWorkingDirectory("files");
        FTPFile[] files = f.listFiles();
        f.changeWorkingDirectory("backup");
        String filePathToBeBackup="/home/user/backup/";
        String prefix;
        String suffix;
        String fileNameToBeBackup;
        FTPFile fileReadyForBackup = null;
        f.setFileType(FTP.BINARY_FILE_TYPE);
        f.setFileTransferMode(FTP.BINARY_FILE_TYPE);
        for (FTPFile file : files) {
            if (file.isFile() && file.getName().equals(fileToBeUpload.getName())) {
                prefix = FilenameUtils.getBaseName(file.getName());
                suffix = ".".concat(FilenameUtils.getExtension(file.getName()));
                fileNameToBeBackup = prefix.concat(Calendar.getInstance().getTime().toString().concat(suffix));
                filePathToBeBackup = filePathToBeBackup.concat(fileNameToBeBackup);
                fileReadyForBackup = file;
                fileToBeUploadExist = true;
                break;
            }
        }
        // If file already exist on the server create a backup from it otherwise just upload the file.
        if(fileToBeUploadExist){
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            f.retrieveFile(fileReadyForBackup.getName(), outputStream);
            InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
            if(f.storeUniqueFile(filePathToBeBackup, is)){
                JOptionPane.showMessageDialog(null, "Backup succeeded.");
                f.changeWorkingDirectory("files");
                boolean reply = f.storeFile(fileToBeUpload.getName(), new FileInputStream(fileToBeUpload));
                if(reply){
                    JOptionPane.showMessageDialog(null,"Upload succeeded.");
                }else{
                    JOptionPane.showMessageDialog(null,"Upload failed after backup.");
                }
            }else{
                JOptionPane.showMessageDialog(null,"Backup failed.");
            }
        }else{
            f.changeWorkingDirectory("files");
            f.setFileType(FTP.BINARY_FILE_TYPE);
            f.enterLocalPassiveMode();
            InputStream inputStream = new FileInputStream(fileToBeUpload);
            ByteArrayInputStream in = new ByteArrayInputStream(FileUtils.readFileToByteArray(fileToBeUpload));
            boolean reply = f.storeFile(fileToBeUpload.getName(), in);
            System.out.println("Reply code for storing file to server: " + reply);
            if(!f.completePendingCommand()) {
                f.logout();
                f.disconnect();
                System.err.println("File transfer failed.");
                System.exit(1);
            }
            if(reply){

                JOptionPane.showMessageDialog(null,"File uploaded successfully without making backup." +
                        "\nReason: There wasn't any previous version of this file.");
            }else{
                JOptionPane.showMessageDialog(null,"Upload failed.");
            }
        }
        //Logout and disconnect from server
        in.close();
        f.logout();
        f.disconnect();
    } catch (IOException e) {
        e.printStackTrace();
    }

}
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
itro
  • 7,006
  • 27
  • 78
  • 121
  • what did not you understood? if you know the source path and the distanation path you just can open file for read(with buffers) and write on the distanation path. also you can use os specific api for coping files. – Dmitry Zagorulkin Jun 26 '12 at 07:10
  • The file type is FTPFile. how can i read and write in buffer? do you means like `FileInputStream in = new FileInputStream(file);` – itro Jun 26 '12 at 07:22
  • http://www.dreamincode.net/forums/topic/32031-ftp-in-java-using-apache-commons-net/ – Dmitry Zagorulkin Jun 26 '12 at 07:31
  • Did you try `f.setFileType(FTP.BINARY_FILE_TYPE);` in the `if` block also? may be you already have that file in the backup directory. And in the else what is the output of `storeFile()` true? or false? – RP- Jun 27 '12 at 13:28
  • I did add `f.setFileType(FTP.BINARY_FILE_TYPE);` and in backup directory every time i put the file with new name. I get true as a storeFile result. I put whole code above after final editing. – itro Jun 27 '12 at 14:07

4 Answers4

23

If you are using apache commons net FTPClient, there is a direct method to move a file from one location to another location (if the user has proper permissions).

ftpClient.rename(from, to);

or, If you are familiar with ftp commands, you can use something like

ftpClient.sendCommand(FTPCommand.yourCommand, args);
if(FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
     //command successful;
} else {
     //check for reply code, and take appropriate action.
}

If you are using any other client, go through the documentation, There wont be much changes between client implementations.

UPDATE:

Above approach moves the file to to directory, i.e, the file won't be there in from directory anymore. Basically ftp protocol meant to be transfer the files from local <-> remote or remote <-> other remote but not to transfer with in the server.

The work around here, would be simpler, get the complete file to a local InputStream and write it back to the server as a new file in the back up directory.

to get the complete file,

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ftpClient.retrieveFile(fileName, outputStream);
InputStream is = new ByteArrayInputStream(outputStream.toByteArray());

now, store this stream to backup directory. First we need to change working directory to backup directory.

// assuming backup directory is with in current working directory
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);//binary files
ftpClient.changeWorkingDirectory("backup");
//this overwrites the existing file
ftpClient.storeFile(fileName, is);
//if you don't want to overwrite it use storeUniqueFile

Hope this helps you..

RP-
  • 5,827
  • 2
  • 27
  • 46
  • 1
    With your solution `ftpClient.rename(from, to);` i can rename it but still stays in the same directory not to one i expected(backup directory). How can i solve it? How can i get backup path? what is right path for second argument if i want file be copyied to buckup directory? I have root directory which all files situated there and backup directory which i create it under the root directory. – itro Jun 26 '12 at 12:34
  • 1
    something like `ftpClient.rename("/root/your_file.txt", "/root/backup/your_file_bak.txt");`. One thing to note here is it moves from the `from` directory to `to` directory. You won't be having it in the `from` directory anymore. – RP- Jun 26 '12 at 12:37
  • ohhhhhhhhh no i want to have just a copy of it not moveing it to backup. – itro Jun 26 '12 at 12:59
  • Ok, that is bit of a work around with ftp client, no direct way. I will update my answer with one of the available approaches.. – RP- Jun 26 '12 at 13:24
  • When backup a .zip file the buckup is corupted but when backup .csv file backup is ok. What should be the reason? – itro Jun 27 '12 at 12:31
  • You should set the file type to `BINARY`, like `ftpClient.setFileType(FTP.BINARY_FILE_TYPE);`, I have updated the answer. – RP- Jun 27 '12 at 12:35
  • I did set it but still the same behavior i will update my code you can get whole code to see where is the problem. – itro Jun 27 '12 at 13:01
  • I did put `f.setFileTransferMode(FTP.BINARY_FILE_TYPE);` also after `f.setFileType(FTP.BINARY_FILE_TYPE);` but the same result. – itro Jun 27 '12 at 13:32
  • Thanks alot for your help.the reason was i didn't close input stream before log out. I update the code with `in.close();` – itro Jul 04 '12 at 08:44
1

Try this way,

I am using apache's library .

ftpClient.rename(from, to) will make it easier, i have mentioned in the code below where to add ftpClient.rename(from,to).

public void goforIt(){


        FTPClient con = null;

        try
        {
            con = new FTPClient();
            con.connect("www.ujudgeit.net");

            if (con.login("ujud3", "Stevejobs27!!!!"))
            {
                con.enterLocalPassiveMode(); // important!
                con.setFileType(FTP.BINARY_FILE_TYPE);
                String data = "/sdcard/prerakm4a.m4a";
                ByteArrayInputStream(data.getBytes());
                FileInputStream in = new FileInputStream(new File(data));
                boolean result = con.storeFile("/Ads/prerakm4a.m4a", in);
                in.close();
                if (result) 
                       {
                            Log.v("upload result", "succeeded");

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Add the backup Here$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//

                   // Now here you can store the file into a backup location

                  // Use ftpClient.rename(from, to) to place it in backup

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Add the backup Here$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//

                       }
                con.logout();
                con.disconnect();
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }   

    }
Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
  • I should checkout if file exist in server then make backup then upload the file. i think you did here something else – itro Jun 26 '12 at 11:01
  • Look at it properly once again, if (result) is the block which will execute after the file is successfully stored on the server..... – Kumar Vivek Mitra Jun 26 '12 at 12:42
0

There's no standard way to duplicate a remote file over FTP protocol. Some FTP servers support proprietary or non-standard extensions for this though.


So if your are lucky that your server is ProFTPD with mod_copy module, you can use FTP.sendCommand to issue these two commands:

f.sendCommand("CPFR sourcepath");
f.sendCommand("CPTO targetpath");

The second possibility is that your server allows you to execute arbitrary shell commands. This is even less common. If your server supports this you can use SITE EXEC command:

SITE EXEC cp -p sourcepath targetpath

Another workaround is to open a second connection to the FTP server and make the server upload the file to itself by piping a passive mode data connection to an active mode data connection. Implementation of this solution (in PHP though) is shown in FTP copy a file to another place in same FTP.


If neither of this works, all you can do is to download the file to a local temporary location and re-upload it back to the target location. This is that the answer by @RP- shows.


See also FTP copy a file to another place in same FTP.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
-1

To backup at same Server (move), can you use:

String source="/home/user/some";
String goal  ="/home/user/someOther";
FTPFile[] filesFTP = cliente.listFiles(source);

clientFTP.changeWorkingDirectory(goal);  // IMPORTANT change to final directory

for (FTPFile f : archivosFTP) 
   {
    if(f.isFile())
       {
        cliente.rename(source+"/"+f.getName(), f.getName());
       }
   }