【问题标题】:Extracting images from a text file of 100 image urls using java使用java从100个图像url的文本文件中提取图像
【发布时间】:2015-06-21 05:19:43
【问题描述】:

我有一个文本文件,其中逐行包含大量图像 URL。我需要一个 Java 代码来自动提取这些图像并将这些图像保存到一个文件中。我知道如何从单个 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();
    }
}

【问题讨论】:

  • ImageIO.readImageIO.writeReading/Loading an ImageWriting/Saving an Image)。使用某种ExecutorService,可能是一个固定池服务,从文本文件中加载所有条目,为每个条目添加一个“任务”到ExecutorService。运行直到全部完成(可能使用invokeAll之类的东西)

标签: java file url file-io


【解决方案1】:

您可以利用预先存在的 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 是一个阻塞调用,这意味着在所有任务完成或失败之前,它不会返回。方便。

您可以选择处理Future 的结果List,这些带有Callables 的返回结果

        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 了解更多详情

【讨论】:

    【解决方案2】:

    您可以在命令行上使用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");
        }
    
    }
    

    【讨论】:

    • 感谢您的建议,我尝试使用 Wget -i -o log.txt 从 url 的文本文件中提取图像。但它太慢了,我实际上想学习 Java 多线程。
    • 很抱歉没有提到文本文件在我的本地文件夹中,它包含 100 个图像链接。我需要从该文件中获取所有图像。上面的代码无法打开文本文件。
    • 我更新了我的解决方案,现在它可以满足您的要求。第一个参数是一个带有 url 的文件。第二个参数是你想要复制的目录。
    【解决方案3】:

    要从 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);
            }
        }
    }
    

    【讨论】:

    • 为什么要缩放图像?
    • 感谢“saka1029”先生
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    • 1970-01-01
    • 2011-01-09
    相关资源
    最近更新 更多