Java 使用JSch使用多线程下载文件

Java 使用JSch使用多线程下载文件,java,jsch,Java,Jsch,我正在尝试使用多个线程从远程服务器下载多个文件。然而,当我使用多个线程时,我得到 java.lang.IOException:管道已关闭 当我只使用一个线程时,同样的代码可以正常工作 是否不可能使用JSch从同一远程服务器同时下载多个文件 SftpTest.java public class SftpTest { private static List<SftpAccessor> accessorList = new ArrayList<SftpAccessor>();

我正在尝试使用多个线程从远程服务器下载多个文件。然而,当我使用多个线程时,我得到

java.lang.IOException:管道已关闭

当我只使用一个线程时,同样的代码可以正常工作

是否不可能使用JSch从同一远程服务器同时下载多个文件

SftpTest.java

public class SftpTest {

private static List<SftpAccessor> accessorList = new ArrayList<SftpAccessor>();
private static List<Payload> files = new ArrayList<Payload>();
private static ExecutorService writerThreadPool = Executors.newFixedThreadPool(10);

public static void main(String args[]) throws JSchException, InterruptedException {
    SSH srcServer = new SSH();
    srcServer.setHostname("10.22.65.140");
    srcServer.setKey("D:\\jars\\dmwvmcol01.ec2user.pem");
    srcServer.setPort("22");
    srcServer.setUsername("ec2-user");

    SftpAccessor acc = new SftpAccessor(srcServer);
    accessorList.add(acc);

    files.addAll(acc.ls("/data/test/src", false, "*", 1));

    for (Payload file : files) {
        writerThreadPool.submit(new LocalWriterThread(file));
    }

    writerThreadPool.shutdown();
    writerThreadPool.awaitTermination(20, TimeUnit.MINUTES);
}}
SftpAccessor.java

public class SftpAccessor {

private JSch jsch = new JSch();
private ChannelSftp channelSftp = null;
private Session session = null;

String errorMsg = null;

public SftpAccessor(SSH ssh) throws JSchException {

    jsch.addIdentity(ssh.getKey());
    session = jsch.getSession(ssh.getUsername(), ssh.getHostname(), Integer.parseInt(ssh.getPort()));
    session.setHostKeyAlias(ssh.getKey());

    java.util.Properties config = new java.util.Properties();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.connect();
    channelSftp = (ChannelSftp) session.openChannel("sftp");
    channelSftp.connect();

}

public List<Payload> ls(String directory, boolean recursive, String filemask, int delayMinutes) {

    List<Payload> files = new ArrayList<Payload>();

    try {

        channelSftp.cd(directory);

        @SuppressWarnings("unchecked")
        Vector<ChannelSftp.LsEntry> entries = channelSftp.ls(filemask);

        for (ChannelSftp.LsEntry entry : entries) {
            try {
                if (entry.getAttrs().isDir()) {
                    if (recursive) {
                        List<Payload> filesToAdd = ls(directory + "/" + entry.getFilename(), recursive, filemask, delayMinutes);
                        files.addAll(filesToAdd);
                    }
                }
                else {

                    Date lastmodified = new Date(entry.getAttrs().getMTime() * 1000L);
                    Date currdate = new Date(new Date().getTime() - (delayMinutes * 60 * 1000L));

                    if (lastmodified.before(currdate)) {
                        String filename = entry.getFilename();
                        entry.getAttrs().getMTime();

                        Payload file = new Payload();
                        System.out.println("Getting input Stream for " + directory + "/" + filename);
                        file.setInputStream(channelSftp.get(directory + "/" + filename));
                        file.setFilename(filename);
                        file.setLastModified(lastmodified);
                        files.add(file);
                    }

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

    }
    catch (SftpException e) {

    }       

    return files;
}}

JSch不是线程安全的。即使是这样,在单个SSH会话上使用并行下载也几乎没有任何性能优势。它会像串行下载一样慢。此外,您可能会达到并发文件句柄的服务器端限制

您应该为每个线程/下载打开单独的会话

public class SSH {
String hostname;
String port;
String username;
String key;

public String getHostname() {
    return hostname;
}
public void setHostname(String hostname) {
    this.hostname = hostname;
}
public String getPort() {
    return port;
}
public void setPort(String port) {
    this.port = port;
}
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
public String getKey() {
    return key;
}
public void setKey(String key) {
    this.key = key;
} }
public class SftpAccessor {

private JSch jsch = new JSch();
private ChannelSftp channelSftp = null;
private Session session = null;

String errorMsg = null;

public SftpAccessor(SSH ssh) throws JSchException {

    jsch.addIdentity(ssh.getKey());
    session = jsch.getSession(ssh.getUsername(), ssh.getHostname(), Integer.parseInt(ssh.getPort()));
    session.setHostKeyAlias(ssh.getKey());

    java.util.Properties config = new java.util.Properties();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.connect();
    channelSftp = (ChannelSftp) session.openChannel("sftp");
    channelSftp.connect();

}

public List<Payload> ls(String directory, boolean recursive, String filemask, int delayMinutes) {

    List<Payload> files = new ArrayList<Payload>();

    try {

        channelSftp.cd(directory);

        @SuppressWarnings("unchecked")
        Vector<ChannelSftp.LsEntry> entries = channelSftp.ls(filemask);

        for (ChannelSftp.LsEntry entry : entries) {
            try {
                if (entry.getAttrs().isDir()) {
                    if (recursive) {
                        List<Payload> filesToAdd = ls(directory + "/" + entry.getFilename(), recursive, filemask, delayMinutes);
                        files.addAll(filesToAdd);
                    }
                }
                else {

                    Date lastmodified = new Date(entry.getAttrs().getMTime() * 1000L);
                    Date currdate = new Date(new Date().getTime() - (delayMinutes * 60 * 1000L));

                    if (lastmodified.before(currdate)) {
                        String filename = entry.getFilename();
                        entry.getAttrs().getMTime();

                        Payload file = new Payload();
                        System.out.println("Getting input Stream for " + directory + "/" + filename);
                        file.setInputStream(channelSftp.get(directory + "/" + filename));
                        file.setFilename(filename);
                        file.setLastModified(lastmodified);
                        files.add(file);
                    }

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

    }
    catch (SftpException e) {

    }       

    return files;
}}
public class Payload {

private String filename;
private InputStream inputStream;
private Date lastModified;

public String getFilename() {
    return filename;
}

public void setFilename(String filename) {
    this.filename = filename;
}

public Date getLastModified() {
    return lastModified;
}

public void setLastModified(Date lastModified) {
    this.lastModified = lastModified;
}

public InputStream getInputStream() {
    return inputStream;
}

public void setInputStream(InputStream inputStream) {
    this.inputStream = inputStream;
}}