【问题标题】:How to get list of files from an SFTP server?如何从 SFTP 服务器获取文件列表?
【发布时间】:2021-03-31 17:12:40
【问题描述】:

我有一个问题,希望得到解决方案。我也写了一些代码,但需要修改。

问题: 我有一个需要连接的 SFTP 服务器(出于隐私目的,我将提供虚拟凭据)。

服务器名称:服务器名称
端口:22
用户名:用户名
密码:密码

当我连接到服务器时,它会自动将我放到/FGV 目录中。在这个目录里面有几个其他的文件夹。我需要从/FGV/US/BS/ 目录中获取一个 xml 消息列表并将它们放在一个列表中(文件形式为文件)。在列表中,我需要有文件的目录、文件名和文件体。我正在考虑创建一个对象并将此信息放入其中并创建该对象的列表。

我当前的代码创建一个连接并只下载一个 xml 文件。如果有两个 xml 文件,那么我本地机器中的文件没有任何内容。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

public class SFTPinJava {

    public SFTPinJava() {
    }

    public static void main(String[] args) {
        String SFTPHOST = "server-name";
        int SFTPPORT = 22;
        String SFTPUSER = "username";
        String SFTPPASS = "password";
        String SFTPWORKINGDIR = "/FGV";

        Session session = null;
        Channel channel = null;
        ChannelSftp channelSftp = null;

        try {
            JSch jsch = new JSch();
            session = jsch.getSession(SFTPUSER, SFTPHOST, SFTPPORT);
            session.setPassword(SFTPPASS);
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();
            channel = session.openChannel("sftp");
            channel.connect();
            channelSftp = (ChannelSftp) channel;
            channelSftp.cd(SFTPWORKINGDIR);
            byte[] buffer = new byte[1024];
            BufferedInputStream bis = new BufferedInputStream(
                channelSftp.get("/FGV/US/BS/FGVCustomsEntryLoaderService.xml"));
            File newFile = new File(
                "C:\\workspace\\Crap\\src\\org\\raghav\\stuff\\XML_FROM_SERVER.xml");
            OutputStream os = new FileOutputStream(newFile);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            int readCount;
            //System.out.println("Getting: " + theLine);
            while ((readCount = bis.read(buffer)) > 0) {
                //System.out.println("Writing: ");
                bos.write(buffer, 0, readCount);
            }
            
            while(session != null){
                System.out.println("Killing the session");
                session.disconnect();
                bis.close();
                bos.close();
                System.exit(0);
            }
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

我需要更改此代码,以便它可以抓取多个文件并将它们放入对象列表中。该对象应具有文件目录、文件名和文件主体。

【问题讨论】:

标签: java sftp jsch


【解决方案1】:

您可以使用

列出给定目录中的所有文件
Vector<ChannelSftp.LsEntry> list = channelSftp.ls("*.csv");
for(ChannelSftp.LsEntry entry : list) {
     System.out.println(entry.getFilename()); 
}

之后添加这段代码
channelSftp.cd(SFTPWORKINGDIR);

现在您将获得文件对象列表。文件对象是 entry.if 你想下载所有文件。将此代码添加到 for 循环中。

byte[] buffer = new byte[1024];
BufferedInputStream bis = new BufferedInputStream(channelSftp.get(entry.getFilename()));
File newFile = new File("C:/Users/Desktop/sftpStuff/"+entry.getFilename());
OutputStream os = new FileOutputStream(newFile);
BufferedOutputStream bos = new BufferedOutputStream(os);
int readCount;
//System.out.println("Getting: " + theLine);
while( (readCount = bis.read(buffer)) > 0) {
  System.out.println("Writing: "+entry.getFilename() );
  bos.write(buffer, 0, readCount);
}
bis.close();
bos.close();

【讨论】:

    【解决方案2】:

    这是一种列出目标目录文件的方法。

    Vector filelist = channelSftp.ls(SFTPWORKINGDIR);
    for(int i=0; i<filelist.size();i++){
         System.out.println(filelist.get(i).toString());
         // Grap and get the file by WORKING_DIR/filelist.get(i).toString();
         // Save it to your local directory with its original name. 
    
    }
    

    其次,在 for 循环中,您可以下载所有文件,如果它们是您需要的 xml 文件。

    【讨论】:

      【解决方案3】:

      ChannelSftp 有一个从路径获取文件列表的方法。我假设您要下载的文件都在同一个目录中,并且您会这样做:

      channelSftp.cd("/FGV/US/BS/");
      Vector ls = channelSftp.ls("*")
      

      http://epaul.github.io/jsch-documentation/simple.javadoc/com/jcraft/jsch/ChannelSftp.html#ls(java.lang.String)

      一旦你有了这个列表(返回一个 Vector),设置一个 for 循环或迭代器以使用 Vector 中的每个 ChannelSftp.LsEntry,使用 getFilename 方法获取文件名。您可以检查以确保它具有 .xml 扩展名。代码中byte[] buffer 行中的所有内容都在循环内。如果要保留文件的内容,则需要将连续读取缓冲区的内容添加到 StringBuffer 中。

      至于存储文件名、每个内容和目录,您可以使用简单的包装器。示例:

      public class SFTPFileList {
          public String directory;
          public ArrayList<String> filenames;
          public ArrayList<StringBuffer> fileContents;  
      
          /**
           *Simple method to add a filename and its contents.
           *filenames and fileContents will have the same index
           *for filename<->content. 
           **/
          public void addFile(String filename, StringBuffer content) {
              filenames.add(filename);
              fileContents.add(content);
          }
      }
      

      您可以添加方法、构造函数等来正确获取、设置。或者直接访问。对于后者,在您的循环之外:

      SFTPFileList sftpFileList = new SFTPFileList();
      sftpFileList.directory = "/FGV/US/BS/";
      ArrayList<String> fileNames = new ArrayList<>();
      ArrayList<String,StringBuffer> contents = new ArrayList<>();
      sftpFileList.filenames = filenames;
      sftpFileList.contents = contents;
      

      在你的循环中:

      ChannelSftp.LsEntry entry = iter.next();  //or from a for loop
      String fileName = entry.getFileName();
      StringBuffer fileContent = new StringBuffer(); //this where you will add the results of each read -> buffer 
      ...
      read content
      ...
      sftpFileList.addFile(fileName,fileContent);
      

      然后在循环之外,您将可以通过您可以编写的另一种或多种方法访问所有文件名及其内容。或者根据需要直接访问这些成员。

      【讨论】:

        【解决方案4】:

        这段代码运行良好。

                @SuppressWarnings("null")
                Vector<ChannelSftp.LsEntry> filesList = channelSftp.ls("*.txt");
                logger.info("filesList size:" + filesList.size()); 
                if(filesList != null) {
                    for(ChannelSftp.LsEntry entry : filesList) {
                        InputStream stream = channelSftp.get(entry.getFilename());
                        br = new BufferedReader(new InputStreamReader(stream));
                        if(br != null) {
                            while ((line = br.readLine()) != null) {
                            }
                        }
                   }
                }
        

        【讨论】: