2015-06-21 87 views
1

我有一个文本文件,它包含大量的图像网址逐行。我需要获取Java代码以自动提取这些图像并将这些图像保存到文件中。我知道如何从单个URL保存图像,但我如何修改代码以执行多线程?我想用原始文件名将所有图像放在一个文件夹下。我试图谷歌了很多代码,但一切都是失败的。请帮我找到一个解决方案。将不胜感激。使用java从100个图像URL的文本文件中提取图像

我用来保存单个图像的代码是:

import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.URL; 

public class SaveImageFromUrl { 
    public static void main(String[] args) throws Exception { 
     String imageUrl = "http://http://img.emol.com/2015/04/25/nepalterremoto02ok_2260.jpg"; 
     String destinationFile = "/home/abc/image.jpg"; 
     saveImage(imageUrl, destinationFile); 
    } 

    public static void saveImage(String imageUrl, String destinationFile) throws IOException { 
     URL url = new URL(imageUrl); 
     InputStream is = url.openStream(); 
     OutputStream os = new FileOutputStream(destinationFile); 

     byte[] b = new byte[2048]; 
     int length; 

     while ((length = is.read(b)) != -1) { 
      os.write(b, 0, length); 
     } 
     is.close(); 
     os.close(); 
    } 
} 
+1

'ImageIO.read'和'ImageIO.write'([读/加载图像](http://docs.oracle.com /javase/tutorial/2d/images/loadimage.html)和[编写/保存图像](http://docs.oracle.com/javase/tutorial/2d/images/saveimage.html))。使用某种'ExecutorService',可能是一个固定池服务,从文本文件中加载所有条目,为每个条目添加一个“任务”到'ExecutorService'。运行,直到完成(可能使用像'invokeAll') – MadProgrammer

回答

0

可以使用curl在命令行上获取多个文件。不过,我想你正在努力学习Java并发,所以我使用并发重做你的程序:

更新:现在这处理该文件并下载每个URL,并保留原始文件名

/** 
* Created by justin on 6/20/15. 
*/ 

import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.lang.System; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.io.File; 
import java.nio.file.Files; 

class ImageSaver implements Runnable { 

    private final String imageUrl; 
    private final String destinationFile; 
    private Exception exception; 

    public ImageSaver(String imageUrl, String destinationFile) { 
     this.imageUrl = imageUrl; 
     this.destinationFile = destinationFile; 
     this.exception = null; 
    } 

    public boolean isFail() { 
     return exception != null; 
    } 

    public String toString() { 
     return this.imageUrl + " -> " + this.destinationFile + " Error: " + exception.toString(); 
    } 

    @Override 
    public void run() { 
     try { 
      URL url = null; 
      url = new URL(imageUrl); 
      System.out.println("Getting " + imageUrl); 
      url.openConnection(); 
      InputStream is = url.openStream(); 
      System.out.println("Opening " + imageUrl); 
      OutputStream os = new FileOutputStream(destinationFile); 

      byte[] b = new byte[2048]; 
      int length; 

      while ((length = is.read(b)) != -1) { 
       os.write(b, 0, length); 
      } 

      is.close(); 
      os.close(); 
      System.out.println("Finished getting " + imageUrl); 
     } catch (Exception e) { 
      exception = e; 
     } 

    } 

} 


public class SaveImageFromUrl { 
    public static void main(String[] args) throws Exception { 
     if (args.length < 2) { 
      System.out.println("Usage: <file with urls on each line> <dest path>"); 
      return; 
     } 
     String destPath = args[1]; 
     List<String> listOfURLs = Files.readAllLines(new File(args[0]).toPath()); 
     ExecutorService executor = Executors.newFixedThreadPool(5); 
     List<ImageSaver> save = new ArrayList<ImageSaver>(); 

     for (String path : listOfURLs) { 

      String fn = new File(path).getName(); 
      ImageSaver worker = new ImageSaver(path, destPath + fn); 
      save.add(worker); 
      executor.execute(worker); 
     } 
     executor.shutdown(); 
     while (!executor.isTerminated()) { 
      Thread.yield(); 
     } 
     for (ImageSaver s : save) { 
      if (s.isFail()) { 
       System.out.println("Failed to download " + s); 
      } 
     } 
     executor.shutdown(); 
     System.out.println("All Done"); 
    } 

} 
+0

感谢您的建议,我试过Wget -i -o log.txt从url的文本文件中提取图像。但它太慢,我真的想学习Java多线程。 –

+0

对不起,该文本文件是在我的本地文件夹内,它包含100个图像链接。我需要从该文件中获取所有图像。上面的代码无法打开文本文件。 –

+0

我更新了我的解决方案,以便它能够满足您现在要求的要求。第一个参数是一个带有URL的文件。第二个参数是你想要复制的目录。 –

0

要得到URL文本图像,你可以使用下面的代码:

public class SaveImageFromUrl { 
    BufferedImage img = null; 

    public static void main(String[] args) { 
     String path = "https://upload.wikimedia.org/wikipedia/commons/1/1e/Stonehenge.jpg"; 
     String destinationFile = "C:\\Users\\user\\Desktop"; 

     try { 
      BufferedImage tmp = ImageIO.read(new URL(path)); 
      ImageIO.write(tmp, "jpg", new File(destinationFile + "\\" + "image" + ".jpg")); 
     } catch (Exception ex) { 
      System.out.println("Exception ex ///" + ex); 
     } 
    } 
} 
+0

为什么要缩放图像? – saka1029

+0

谢谢先生“saka1029” – Rafiq

2

您可以利用预先存在的API ...

  • 使用Files.readAllLines读取文件
  • ImageIO.readImageIO.write下载文件
  • Executor API运行并发任务,以帮助它更快

所以,基本上,从每个URL下载图像是相同的过程,它可以封装成一个简单的任务。

public class DownloadImageFromURLTask implements Callable<File> { 

    private URL url; 
    private String path; 

    public DownloadImageFromURLTask(URL url, String path) { 
     this.url = url; 
     this.path = path; 
    } 

    @Override 
    public File call() throws Exception { 

     BufferedImage img = ImageIO.read(url); 
     String name = url.getPath(); 
     name = name.substring(name.lastIndexOf("/")); 
     File output = new File(path, name); 
     ImageIO.write(img, "jpg", output); 

     return output; 
    } 

} 

我用Callable这里,因为这将插件安装到Executor API,让我得到返回的结果,这是该图像的下载File

所以接下来,我们需要从文本文件中读取URL和建设任务执行的列表...

 List<String> listOfURLs = Files.readAllLines(new File("ListOfURLs.txt").toPath()); 
     List<DownloadImageFromURLTask> listOfTasks = new ArrayList<>(listOfURLs.size()); 
     String path = "/home/abc"; 
     for (String url : listOfURLs) { 
      listOfTasks.add(new DownloadImageFromURLTask(new URL(url), path)); 
     } 

为简单起见,我只是用Files.readAllLines

接下来,我们需要执行的所有任务......

 ExecutorService exector = Executors.newFixedThreadPool(4); 
     List<Future<File>> listOfFutures = exector.invokeAll(listOfTasks); 

这是使用一个固定大小的线程池,这使得一些性能调整我们的一部分,每一个任务将是便便直到一个线程可用来运行它。

这里使用invokeAll是一个阻塞调用,这意味着在所有任务完成或失败之前,它不会返回。方便。

或者,您可以处理由此产生的FutureList的,这些携带Callable小号

 for (int index = 0; index < listOfFutures.size(); index++) { 
      Future<File> future = listOfFutures.get(index); 
      try { 
       File file = future.get(); 
      } catch (ExecutionException ex) { 
       String url = listOfURLs.get(index); 
       System.out.println("Failed to download image from " + url); 
       ex.printStackTrace(); 
      } 
     } 

的回归结果在这个例子中,它的处理列表寻找失败的任务。

看一看Reading/Loading an ImageWriting/Saving an ImageExecutorsReading, Writing, and Creating Files更多细节