使用JAVA时,是否可以非常快速地从网站下载图像

时间:2011-12-02 23:39:49

标签: java image web download

假设我们有一个名为

的URL

“mysite.com”

在这个网站中,我们有一个名为images的目录,其中包含大约200张.PNG图片

我想制作一个程序,逐个扫描这些图片(如果你知道上一张图片的URL,你可以预测图片的URL),然后我想在我的JFrame上显示这个图片

我最初想到的是,因为我知道网址,为什么我不扫描所有不同的图片网址,然后执行此操作?

  Image image = ImageIO.read(url); hasImage.setIcon(new
  ImageIcon(image));

现在

 hasImage

是一个JLabel,我使用刚从URL下载的图像

url

是类URL的对象

所以,每次在循环中我都会找到新的URL,并且我调用了上面刚刚发布的2行代码的函数,以便更新标签上的图像

请注意,这两行都在ActionListener按钮内,因此每次单击按钮时,都会显示下一个图像

这里有一个主要问题。

当我想要显示下一个图像时,需要一些时间来创建新的url对象,下载图像,然后将其显示在我的标签上,这有点烦人,特别是如果你匆忙并且想要快速显示图像...

现在,我想到了另一个实现,为什么不下载所有图像,将它们保存在本地某处,然后扫描存储图像的目录,并在每次单击按钮时显示它们?

好的,我这样做了,但问题是下载所有图片需要一分多钟 之后它运作顺利,非常快

所以这里最大的问题是它需要花费很多时间来下载图像,所以它基本上是以前的实现,但是在这一次而不是等待我按下按钮时,我等待一切下载,这需要相同的时间......

我的问题是,我怎样才能让它更快?如果它会在不到5秒的时间内下载所有图像,我会满意

这是我正在使用的功能,以保存图像

   private void saveImages() {
    Image image;
    int ID = 1;
    String destFile = "destFolder" + ID + ".png";

    try {
        image = ImageIO.read(url);
        ImageIO.write((RenderedImage) image, "png", new File(destFile));
    } catch (IOException ex) {

    }

    while (ID < 200) {
        try {
            String path = url.getPath();

            String[] token = path.split("-");
            String[] finalToken = token[2].split("\\.");
            ID = Integer.parseInt(finalToken[0]);
            url = new URL("http://somesite/images/" + (ID + 1) + ".png");


            destFile = "C:\\...\\destFolder\\" + ID + ".png";
            image = ImageIO.read(url);
            ImageIO.write((RenderedImage) image, "png", new File(destFile));

        } catch (MalformedURLException ex) {

            JOptionPane.showMessageDialog(null,
                    "URL is not in the correct form", "Malformed URL",
                    JOptionPane.ERROR_MESSAGE);

        } catch (IOException ex) {
        }
    }

    JOptionPane.showMessageDialog(null, "Images were loaded successfully",
            "Success", JOptionPane.INFORMATION_MESSAGE);
}
编辑:顺便说一下,我真的很抱歉代码,它有点乱,这只是我输入的第一件事....我会稍后改进它但我希望你能理解我遇到的问题我正面对现在:)

3 个答案:

答案 0 :(得分:3)

Java或实现都不是问题,而是连接的速度。您可以下载应用程序所需的所有图像(这需要一些时间,如果没有查看图像则毫无意义),或者在点击它们时加载它们。

如果您想让它看起来更快一点,您可以开始将图像加载到本地数据库或文件系统(如缓存)。这显然有其缺点,因为一旦图片加载一次,它只会使加载时间更快,并且通常理想的是没有非常大的缓存。

只需查看一张图片,您还可以加载五张左右的下一张和上一张图片,这样可以让用户感觉更快。

答案 1 :(得分:1)

从网络下载200张图片总是需要一些时间。你需要做些什么才能加快速度呢

  1. 为避免在事件发送线程中下载图像:它会在下载时阻止UI。图像应该在一个单独的后台线程中下载。
  2. 让两个线程同时下载图像。您可以并行下载更多内容,但大多数Web服务器拒绝来自同一主机的两个以上并发连接。

答案 2 :(得分:0)

我建议您在后台加载图片,并在加载后立即显示图片,这样您的用户界面就会响应。当您转到特定图像时,您也可以自动加载下一个图像。

这是一个相当绿色的干编码(实际上没有尝试编译)尝试,这应该证明这个想法。 (原谅紧密耦合,而不是在类中捣乱责任。而且,它对于imageBuffer的无限性而言更加傲慢,并且没有卸载到磁盘上。

class ImageManager {
  private ExecutorService asyncLoader = Executors.newFixedThreadPool(2);
  private HashMap<Integer, Image> imageBuffer = new HashMap<Integer, Image>();
  private final int PRELOAD = 2;
  private String baseUrl;
  public ImageManager(String baseUrl) {
    this.baseUrl = baseUrl;
  }
  public void loadImageAndUpdateLabel(final int idx, final JLabel label) {
    asyncLoader.execute(new Runnable() {
      public void run() {
        loadSync(idx);
        SwingUtilities.invokeLater(new Runnable() {
          label.setIcon(new ImageIcon(imageBuffer.get(idx)));
          label.setText(null);
        });
      }
    });
    triggerAsyncPreload(idx);        
  }
  public void triggerAsyncPreload(int idx) {
    for (int i=idx-PRELOAD; i<idx+PRELOAD; i++) {
      if (i>0) {
        loadAsync(i);
      }
    }
  }
  public synchronized void loadSync(int idx) {
    if (imageBuffer.get(idx) == null) {
      imageBuffer.put(idx, ImageIO.read(new URL(baseUrl, idx+".png")));
    }
  }
  public void loadAsync(final int idx) {
    asyncLoader.execute(new Runnable() {
      public void run() {
        loadSync(idx);
      }
    });
  }
}

class ... {
  ...
  private int currentImageIdx = 0;
  private ImageManager imageManager = new ImageManager("http://site.com/images/");
  private JLabel label = new JLabel();
  private JButton nextImageButton = new JButton(new AbstractAction("Next image") {
    public void actionPerformed(ActionEvent e) {
      currentImageIdx++;
      label.setIcon(null);
      label.setText("Loading image "+currentImageIdx);
      imageManager.loadImageAndUpdateLabel(currentImageIdx, label);
    }
  });
  ...
}