java - 如何将FTP服务器上的文件复制到Java中同一服务器上的目录?

Posted

技术标签:

【中文标题】java - 如何将FTP服务器上的文件复制到Java中同一服务器上的目录?【英文标题】:How to copy a file on the FTP server to a directory on the same server in Java? 【发布时间】:2012-06-27 11:15:04 【问题描述】:

我正在使用 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();
    


【问题讨论】:

你不明白什么?如果您知道源路径和远程路径,您只需打开文件进行读取(带缓冲区)并在远程路径上写入。您也可以使用操作系统特定的 api 来处理文件。 文件类型为 FTPFile。我如何在缓冲区中读写?你的意思是像FileInputStream in = new FileInputStream(file); dreamincode.net/forums/topic/… 您是否也在if 块中尝试过f.setFileType(FTP.BINARY_FILE_TYPE);?可能是您已经在备份目录中拥有该文件。在其他情况下,storeFile() true 的输出是什么?还是假的? 我确实添加了f.setFileType(FTP.BINARY_FILE_TYPE); 并在每次我使用新名称放置文件时添加到备份目录中。我得到了真实的 storeFile 结果。我在最终编辑后将整个代码放在上面。 【参考方案1】:

如果您使用的是 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 <-> remoteremote <-> 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

希望对你有所帮助..

【讨论】:

使用您的解决方案ftpClient.rename(from, to); 我可以重命名它,但仍保留在同一目录中,而不是我预期的目录(备份目录)。我该如何解决?我怎样才能获得备份路径?如果我想将文件复制到备份目录,第二个参数的正确路径是什么?我有根目录,所有文件都位于那里,备份目录是我在根目录下创建的。 类似ftpClient.rename("/root/your_file.txt", "/root/backup/your_file_bak.txt");。这里要注意的一件事是它从from 目录移动到to 目录。你不会再在from 目录中拥有它了。 ohhhhhhhhh 不,我只想拥有它的副本,而不是将其移动到备份中。 好的,这有点用 ftp 客户端解决,没有直接的方法。我将使用其中一种可用方法更新我的答案.. 备份 .zip 文件时,备份已损坏,但备份 .csv 文件时备份正常。应该是什么原因?【参考方案2】:

试试这个方法,

我正在使用 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();
           

    

【讨论】:

我应该检查服务器中是否存在文件然后进行备份然后上传文件。我想你在这里做了别的事 再正确看一遍,if(result)是文件成功存入服务器后执行的block.....【参考方案3】:

要在同一服务器上备份(移动),您可以使用:

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

【讨论】:

这不会备份/复制文件,它会移动文件。这不是这个问题的目的。【参考方案4】:

没有通过 FTP 协议复制远程文件的标准方法。不过,一些 FTP 服务器支持专有或非标准扩展。


因此,如果您的服务器是带有mod_copy module 的 ProFTPD,您可以使用FTP.sendCommand 发出这两个命令:

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

第二种可能性是您的服务器允许您执行任意 shell 命令。这更不常见。如果你的服务器支持这个,你可以使用SITE EXEC 命令:

SITE EXEC cp -p sourcepath targetpath

另一种解决方法是打开与 FTP 服务器的第二个连接,并通过将被动模式数据连接传送到主动模式数据连接,使服务器将文件上传到自身。这个解决方案的实现(虽然在 php 中)显示在 FTP copy a file to another place in same FTP。


如果这两种方法都不起作用,您所能做的就是将文件下载到本地临时位置,然后将其重新上传回目标位置。这就是answer by @RP- shows。


另见FTP copy a file to another place in same FTP。

【讨论】:

以上是关于java - 如何将FTP服务器上的文件复制到Java中同一服务器上的目录?的主要内容,如果未能解决你的问题,请参考以下文章

java如何实现将FTP文件转移到另一个FTP服务器上

如何把FTP中的文件复制到本地文件夹

如何将文件上传到 c# Azure Function 生成的 FTP/webdav? [复制]

批处理脚本,用于复制FTP文件夹中的所有文件

如何将http上的文件远程上传到ftp空间里?

C# 将FTP文件转移到另一个FTP服务器上如何实现