Как скопировать файл на FTP-сервере в каталог на том же сервере в Java?

Я использую Apache Commons FTP для загрузки файла. Перед загрузкой я хочу проверить, существует ли уже файл на сервере, и сделать резервную копию из него в резервную директорию на том же сервере.

Кто-нибудь знает, как скопировать файл с FTP-сервера в каталог резервного копирования на том же сервере?

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();
    }

}

Отредактированный код: все еще существует проблема, когда я делаю резервную копию zip-файла, файл с резервной копией повреждается.

Кто-нибудь знает причину этого?

 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();
    }

}

person itro    schedule 26.06.2012    source источник
comment
что ты не понял? если вы знаете исходный путь и путь удаления, вы просто можете открыть файл для чтения (с буферами) и записать путь удаления. также вы можете использовать специфичный для ОС API для копирования файлов.   -  person Dmitry Zagorulkin    schedule 26.06.2012
comment
Тип файла — FTP-файл. как я могу читать и писать в буфер? ты имеешь в виду как FileInputStream in = new FileInputStream(file);   -  person itro    schedule 26.06.2012
comment
dreamincode.net/forums/topic /   -  person Dmitry Zagorulkin    schedule 26.06.2012
comment
Вы также пробовали f.setFileType(FTP.BINARY_FILE_TYPE); в блоке if? может быть, у вас уже есть этот файл в каталоге резервных копий. А в остальном, что является выводом storeFile() верным? или ложный?   -  person RP-    schedule 27.06.2012
comment
Я добавлял f.setFileType(FTP.BINARY_FILE_TYPE); и в каталог резервного копирования каждый раз, когда помещал файл с новым именем. Я получаю true как результат storeFile. Я помещаю весь код выше после окончательного редактирования.   -  person itro    schedule 27.06.2012


Ответы (4)


Если вы используете apache commons net FTPClient, существует прямой метод перемещения файла из одного места в другое (если user имеет соответствующие разрешения).

ftpClient.rename(from, to);

или, если вы знакомы с ftp commands, вы можете использовать что-то вроде

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

Если вы используете любой другой клиент, просмотрите документацию. Между реализациями клиента не будет больших изменений.

ОБНОВЛЕНИЕ:

Приведенный выше подход перемещает файл в каталог to, то есть файла больше не будет в каталоге from. В основном протокол ftp предназначен для передачи файлов с local <-> remote или remote <-> other remote, но не для передачи на сервер.

Работа здесь была бы проще: получить полный файл на локальный InputStream и записать его обратно на сервер в виде нового файла в каталоге резервного копирования.

чтобы получить полный файл,

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

теперь сохраните этот поток в каталоге резервного копирования. Сначала нам нужно изменить рабочий каталог на резервный каталог.

// 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

Надеюсь, это поможет вам.

person RP-    schedule 26.06.2012
comment
С вашим решением ftpClient.rename(from, to); я могу переименовать его, но все равно останется в том же каталоге, а не в том, который я ожидал (каталог резервного копирования). Как я могу это решить? Как я могу получить резервный путь? каков правильный путь для второго аргумента, если я хочу, чтобы файл был скопирован в каталог резервного копирования? У меня есть корневой каталог, в котором находятся все файлы, и резервный каталог, который я создаю в корневом каталоге. - person itro; 26.06.2012
comment
что-то вроде ftpClient.rename("/root/your_file.txt", "/root/backup/your_file_bak.txt");. Здесь следует отметить одну вещь: он перемещается из каталога from в каталог to. Вы больше не будете иметь его в каталоге from. - person RP-; 26.06.2012
comment
ohhhhhhhhh Нет, я хочу иметь только копию, не перемещая ее в резервную копию. - person itro; 26.06.2012
comment
Хорошо, это немного работает с ftp-клиентом, прямого пути нет. Я обновлю свой ответ одним из доступных подходов. - person RP-; 26.06.2012
comment
При резервном копировании файла .zip резервная копия повреждена, но при резервном копировании файла .csv все в порядке. Что должно быть причиной? - person itro; 27.06.2012
comment
Вы должны установить тип файла BINARY, например ftpClient.setFileType(FTP.BINARY_FILE_TYPE);, я обновил ответ. - person RP-; 27.06.2012
comment
Я установил его, но поведение остается тем же. Я обновлю свой код, вы можете получить весь код, чтобы увидеть, в чем проблема. - person itro; 27.06.2012
comment
Я поставил f.setFileTransferMode(FTP.BINARY_FILE_TYPE); также после f.setFileType(FTP.BINARY_FILE_TYPE);, но результат тот же. - person itro; 27.06.2012
comment
Большое спасибо за вашу помощь. Причина в том, что я не закрыл входной поток перед выходом из системы. Я обновляю код с помощью in.close(); - person itro; 04.07.2012

Попробуйте так,

Я использую библиотеку Apache.

ftpClient.rename(from, to) упростит задачу, в приведенном ниже коде я указал, куда добавить 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");

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Добавить резервную копию сюда$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$//

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

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

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Добавить резервную копию сюда$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$//

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

    }
person Kumar Vivek Mitra    schedule 26.06.2012
comment
Я должен проверить, существует ли файл на сервере, затем сделать резервную копию и загрузить файл. Я думаю, ты сделал здесь что-то еще - person itro; 26.06.2012
comment
Посмотрите на это правильно еще раз, если (результат) - это блок, который будет выполняться после того, как файл будет успешно сохранен на сервере..... - person Kumar Vivek Mitra; 26.06.2012

Не существует стандартного способа дублировать удаленный файл по протоколу FTP. Однако некоторые FTP-серверы поддерживают для этого проприетарные или нестандартные расширения.


Поэтому, если вам повезло, что ваш сервер ProFTPD с модулем mod_copy, вы можете используйте FTP.sendCommand для выполнения следующих двух команд:

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

Вторая возможность заключается в том, что ваш сервер позволяет выполнять произвольные команды оболочки. Это встречается еще реже. Если ваш сервер поддерживает это, вы можете использовать команду SITE EXEC:

SITE EXEC cp -p sourcepath targetpath

Другой обходной путь — открыть второе соединение с FTP-сервером и заставить сервер загрузить файл на себя, направив соединение для передачи данных в пассивном режиме к соединению для передачи данных в активном режиме. Реализация этого решения (хотя и на PHP) показана в FTP-копии файла в другое место на том же FTP.


Если ни один из этих способов не работает, все, что вы можете сделать, это загрузить файл в локальное временное расположение и повторно загрузить его обратно в целевое расположение. Это то, что показывает ответ @RP-.


См. также FTP-копирование файла в другое место на том же FTP.

person Martin Prikryl    schedule 24.09.2018

Для резервного копирования на том же сервере (перемещении) вы можете использовать:

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());
       }
   }
person Angel Santiago    schedule 08.06.2017
comment
Это не делает резервную копию/копирует файл, он перемещает файл. Этот вопрос не об этом. - person Martin Prikryl; 08.06.2017