Java 多线程从sftp服务器下载同一文件
我有一个系统,当找到某种类型的文件时,我会在一个单独的线程中下载、编码和上传它们Java 多线程从sftp服务器下载同一文件,java,multithreading,sftp,Java,Multithreading,Sftp,我有一个系统,当找到某种类型的文件时,我会在一个单独的线程中下载、编码和上传它们 while(true) { for(SftpClient c : clients) { try { filenames = c.list("*.wav", "_rdy_"); } catch (SftpException e) { e.printStackTrace(); } if(filenam
while(true) {
for(SftpClient c : clients) {
try {
filenames = c.list("*.wav", "_rdy_");
} catch (SftpException e) {
e.printStackTrace();
}
if(filenames.size() > 0) {
//AudioThread run() method handles the download, encode, and upload
AudioThread at = new AudioThread(filenames);
at.setNode(c.getNode());
Thread t = new Thread(at);
t.start();
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
AudioThread的run方法
public void run() {
System.out.println("Running...");
this.buildAsteriskMapping();
this.connectToSFTP();
ac = new AudioConvert();
this.connectToS3();
String downloadDir = "_rough/" + getNode() + "/" + Time.getYYYYMMDDDate() + "/";
String encodeDir = "_completed" + getNode() + "/" + Time.getYYYYMMDDDate() + "/";
String uploadDir = getNode() + "/" + Time.getYYYYMMDDDate() + "/";
System.out.println("Downloading...");
try {
sftp.get(filenames, downloadDir);
} catch (SftpException e) {
//download failed
System.out.println("DL Failed...");
e.printStackTrace();
}
System.out.println("Encoding...");
try {
ac.encodeWavToMP3(filenames, downloadDir, encodeDir);
} catch (IllegalArgumentException | EncoderException e) {
System.out.println("En Failed...");
e.printStackTrace();
}
System.out.println("Uploading...");
try {
s3.upload(filenames, encodeDir, uploadDir);
} catch (AmazonClientException e) {
System.out.println("Up Failed...");
e.printStackTrace();
}
}
下载方法:
public void get(ArrayList<String> src, String dest) throws SftpException {
for(String file : src) {
System.out.println(dest + file);
channel.get(file, dest + file);
}
}
public void upload(ArrayList<String> filenames, String encodeDir, String uploadDir) throws AmazonClientException, AmazonServiceException {
for(String f : filenames) {
s3.putObject(new PutObjectRequest(bucketName, uploadDir, new File(encodeDir + f)));
}
}
public void get(ArrayList src,String dest)抛出SftpException{
for(字符串文件:src){
System.out.println(dest+文件);
channel.get(文件,dest+file);
}
}
编码方法:
public void encodeWavToMP3(ArrayList<String> filenames, String downloadDir, String encodeDir) throws IllegalArgumentException, EncoderException {
for(String f : filenames) {
File wav = new File(downloadDir + f);
File mp3 = new File(encodeDir + wav.getName().replace(".wav", ".mp3"));
encoder.encode(wav, mp3, attrs);
}
}
public void encodewaftomp3(ArrayList文件名、String downloadDir、String encodeDir)抛出IllegalArgumentException、EncoderException{
for(字符串f:文件名){
File wav=新文件(downloadDir+f);
File mp3=新文件(encodeDir+wav.getName().replace(“.wav”和“.mp3”);
编码器。编码(wav、mp3、ATTR);
}
}
上载方法:
public void get(ArrayList<String> src, String dest) throws SftpException {
for(String file : src) {
System.out.println(dest + file);
channel.get(file, dest + file);
}
}
public void upload(ArrayList<String> filenames, String encodeDir, String uploadDir) throws AmazonClientException, AmazonServiceException {
for(String f : filenames) {
s3.putObject(new PutObjectRequest(bucketName, uploadDir, new File(encodeDir + f)));
}
}
public void upload(ArrayList文件名、String encodeDir、String uploadDir)抛出AmazonClientException、AmazonServiceException{
for(字符串f:文件名){
s3.putObject(新的PutObjectRequest(bucketName、uploadDir、新文件(encodeDir+f));
}
}
问题是我一直在为每个线程下载相同的文件(或大约相同的文件)。我想为每个保存正在下载的文件的客户端添加一个变量,但我不知道如何从此变量中删除列表/文件名。解决办法是什么?我的老板还希望只允许x个线程运行。很难看出问题所在,因为实际下载的代码缺失:p 然而,我会使用某种形式的替代 基本上,我会将每个下载请求添加到服务中(包装在一个“DownloadTask”中,其中包含对要下载的文件的引用以及获取该文件可能需要的任何其他相关信息),并让服务处理其余部分 下载任务可以按照您认为合适的方式进行编码,以考虑现有文件 根据您的需求,这可以是单线程或多线程服务。它还可以让你把上传任务也放在里面 查看线索了解更多信息 总体思路是使用一种生产者/消费者模式。您将拥有(至少)一个线程,该线程将查找所有要下载的文件,并将每个文件添加到executor服务中。下载完文件后,我会排队并将请求上传到同一个服务中 这样,您就避免了同步和线程管理的混乱:D
您可以对扫描任务使用相同的想法,对于每个客户端,您可以将一个任务分配给单独的服务很难看出问题所在,因为实际下载的代码缺失:p 然而,我会使用某种形式的替代 基本上,我会将每个下载请求添加到服务中(包装在一个“DownloadTask”中,其中包含对要下载的文件的引用以及获取该文件可能需要的任何其他相关信息),并让服务处理其余部分 下载任务可以按照您认为合适的方式进行编码,以考虑现有文件 根据您的需求,这可以是单线程或多线程服务。它还可以让你把上传任务也放在里面 查看线索了解更多信息 总体思路是使用一种生产者/消费者模式。您将拥有(至少)一个线程,该线程将查找所有要下载的文件,并将每个文件添加到executor服务中。下载完文件后,我会排队并将请求上传到同一个服务中 这样,您就避免了同步和线程管理的混乱:D
您可以对扫描任务使用相同的想法,对于每个客户端,您可以将一个任务分配给一个单独的服务代码中存在一个问题,您在while循环中实例化AudioThread 请注意,在创建线程并执行t.start()之后,所有下载、编码和上载都是异步进行的。因此,在启动线程后,循环将继续执行对c.list(…)的另一个调用,而您创建的第一个线程仍在处理第一组文件。由于在调用中指定了文件模式,并且没有代码标记当前正在处理的文件,因此在后续的c.list()调用中很可能会返回相同的文件集 我的建议是:
- 使用Executors.newFixedThreadPool(intnthreads),如前一篇文章所述。并将线程数指定为计算机中的处理器数。在while循环之前执行此操作
- 对于从ftp s.list()检索到的每个文件名,创建一个可调用类并调用ExecutorService.invokeAll(收集任务)。您将创建的Callable中的代码是AudioThread代码。修改AudioThread代码,一次只处理一个文件(如果可能的话),这样您就可以对每个文件进行并行下载、上载和编码李>
- 添加标记已处理哪些文件的代码。我建议添加一段代码,将处理过的文件重命名为不同的名称,以避免在下一次c.list()调用中返回
- 调用ExecutorService.shutdown(…)在while循环块之后
- 使用Exe