• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:ProgressMonitorInputStreamを使用してテキストファイルのダウンロード状況を表示
#navi(../)
RIGHT:Posted by &author(aterai); at 2013-04-22
*ProgressMonitorInputStreamを使用してテキストファイルのダウンロード状況を表示 [#e62dec86]
``ProgressMonitorInputStream``を使用してテキストファイルのダウンロード状態を進捗表示します。
---
category: swing
folder: ProgressMonitorInputStream
title: ProgressMonitorInputStreamを使用してテキストファイルのダウンロード状況を表示
tags: [ProgressMonitorInputStream, ProgressMonitor, JProgressBar, SwingWorker, URLConnection, JTextArea]
author: aterai
pubdate: 2013-04-22T03:35:42+09:00
description: ProgressMonitorInputStreamを使用してテキストファイルのダウンロード状態を進捗表示します。
image: https://lh4.googleusercontent.com/-gXnU23f7iiw/UXQuzmKdfVI/AAAAAAAABp8/aPk0QR78NlY/s800/ProgressMonitorInputStream.png
---
* 概要 [#summary]
`ProgressMonitorInputStream`を使用してテキストファイルのダウンロード状態を進捗表示します。

-&jnlp;
-&jar;
-&zip;
#download(https://lh4.googleusercontent.com/-gXnU23f7iiw/UXQuzmKdfVI/AAAAAAAABp8/aPk0QR78NlY/s800/ProgressMonitorInputStream.png)

//#screenshot
#ref(https://lh4.googleusercontent.com/-gXnU23f7iiw/UXQuzmKdfVI/AAAAAAAABp8/aPk0QR78NlY/s800/ProgressMonitorInputStream.png)

**サンプルコード [#pabe4298]
* サンプルコード [#sourcecode]
#code(link){{
worker = new SwingWorker<String, Chunk>() {
  @Override public String doInBackground() {
    Charset cs = Charset.forName("EUC-JP");
    String ret = "Done";
    String path = "http://terai.xrea.jp/";
    URLConnection urlConnection;
    try{
      urlConnection = new URL(path).openConnection();
      System.out.println(urlConnection.getContentEncoding());
      System.out.println(urlConnection.getContentType());
class RunAction extends AbstractAction {
  public RunAction() {
    super("Load");
  }

      String encoding = urlConnection.getContentEncoding();
      if(encoding!=null) {
        cs = Charset.forName(encoding);
      }else{
        String contentType = urlConnection.getContentType();
        for(String value: contentType.split(";")) {
          value = value.trim();
          if(value.toLowerCase().startsWith("charset=")) {
            encoding = value.substring("charset=".length());
          }
        }
        if(encoding!=null) {
          cs = Charset.forName(encoding);
        }
      }
      System.out.println(cs);
    }catch(Exception ex) {
      ex.printStackTrace();
      ret = "Error";
      return ret;
  @Override public void actionPerformed(ActionEvent e) {
    runButton.setEnabled(false);
    textArea.setText("");
    URLConnection urlConnection = getURLConnection();
    if (urlConnection == null) {
      return;
    }
    Charset cs = getCharset(urlConnection, "UTF-8");
    int length = urlConnection.getContentLength();
    try(InputStream is = urlConnection.getInputStream();
        ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(frame, "Loading", is);
        BufferedReader reader = new BufferedReader(new InputStreamReader(pmis, cs))) {

    JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(
        (Component) e.getSource());
    try {
      InputStream is = urlConnection.getInputStream();
      ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(
          frame, "Loading", is);
      monitor = pmis.getProgressMonitor();
      monitor.setNote(" "); //Need for JLabel#getPreferredSize
      monitor.setMillisToDecideToPopup(0);
      monitor.setMillisToPopup(0);
      monitor.setMinimum(0);
      monitor.setMaximum(length);

      int i = 0;
      int size = 0;
      String line;
      while((line = reader.readLine()) != null) {
        if(i++%50==0) { //Wait
          Thread.sleep(10);
        }
        size += line.getBytes(cs).length + 1; //+1: \n
        String note = String.format("%03d%% - %d/%d%n", 100*size/length, size, length);
        publish(new Chunk(line, note));
      }
    }catch(InterruptedException | IOException ex) {
      ret = "Exception";
      cancel(true);
      worker = new MonitorTask(pmis, cs, length);
      worker.execute();
    } catch (IOException ex) {
      ex.printStackTrace();
    }
    return ret;
  }
}

private class MonitorTask extends Task {
  public MonitorTask(ProgressMonitorInputStream pmis, Charset cs, int length) {
    super(pmis, cs, length);
  }

  @Override protected void process(List<Chunk> chunks) {
    for(Chunk c: chunks) {
      textArea.append(c.line+"\n");
    for (Chunk c : chunks) {
      textArea.append(c.line + "\n");
      monitor.setNote(c.note);
      //System.out.println(c.note);
    }
    textArea.setCaretPosition(textArea.getDocument().getLength());
  }

  @Override public void done() {
    frame.getGlassPane().setVisible(false);
    runButton.setEnabled(true);
    String text = null;
    try{
    try {
      if (pmis != null) {
        pmis.close();
      }
      text = isCancelled() ? "Cancelled" : get();
    }catch(Exception ex) {
    } catch (IOException | InterruptedException | ExecutionException ex) {
      ex.printStackTrace();
      text = "Exception";
    }
    System.out.println(text);
  }
};
worker.execute();
}

private static class Task extends SwingWorker<String, Chunk> {
  protected final ProgressMonitorInputStream pmis;
  protected final Charset cs;
  protected final int length;
  public Task(ProgressMonitorInputStream pmis, Charset cs, int length) {
    super();
    this.pmis = pmis;
    this.cs = cs;
    this.length = length;
  }

  @Override public String doInBackground() {
    String ret = "Done";
    try (Scanner scanner = new Scanner(
          new BufferedReader(new InputStreamReader(pmis, cs)))) {
      int i = 0;
      int size = 0;
      while (scanner.hasNextLine()) {
        if (i % 50 == 0) { //Wait
          Thread.sleep(10);
        }
        i++;
        String line = scanner.nextLine();
        size += line.getBytes(cs).length + 1; //+1: \n
        String note = String.format(
            "%03d%% - %d/%d%n", 100 * size / length, size, length);
        //System.out.println(note);
        publish(new Chunk(line, note));
      }
    } catch (InterruptedException | IOException ex) {
      System.out.println("Exception");
      ret = "Exception";
      cancel(true);
    }
    return ret;
  }
}
}}

**解説 [#xaf420db]
上記のサンプルでは、``URLConnection``から開いた``InputStream``に``ProgressMonitorInputStream``をラップして、ファイルのダウンロード進捗状態を``ProgressMonitor``で表示しています。
* 解説 [#explanation]
上記のサンプルでは、`URLConnection`から開いた`InputStream`に`ProgressMonitorInputStream`をラップして、ファイルのダウンロード進捗状態を`ProgressMonitor`で表示しています。

- ``ProgressMonitorInputStream``の使用する``ProgressMonitor``の最大値は、ファイルサイズ(バイト)
-- ``ProgressMonitorInputStream``がデフォルトで設定する最大値は、``InputStream#available()``の値
-- この値がダウンロード中のストリームの合計バイト数を返す訳ではないので、これを最大値のままにしておくと、``ProgressMonitor``が表示されない、またはすぐ閉じてしまう
-- ``URLConnection#getContentLength()``で取得したバイト数を``ProgressMonitor#setMaximum(...)``で設定
- 一行ずつ``JTextArea``に文字列として読み込ませるために、``InputStreamReader``を使用しているので、エンコードを``URLConnection#getContentEncoding()``や``URLConnection#getContentType()``などで取得
-- 何パーセント読み込んだかを``ProgressMonitor#setNote(...)``で表示する場合は、一行が何バイトかを``String#getBytes(Charset)``で取得して計算
-- 注: 改行は``1``バイトで決め打ちしている
-- 進捗を表示する前に``ProgressMonitor#setNote("dummy note");``としておかないと、``Note``に使用する``JLabel``が``null``のままで表示されない、またはレイアウトがおかしくなる
- `ProgressMonitorInputStream`の使用する`ProgressMonitor`の最大値はファイルサイズ(バイト)
-- `ProgressMonitorInputStream`がデフォルトで設定する最大値は`InputStream#available()`の値
-- この値がダウンロード中のストリームの合計バイト数を返す訳ではないので、これを最大値のままにしておくと`ProgressMonitor`が表示されない場合がある
-- `URLConnection#getContentLength()`で取得したバイト数を`ProgressMonitor#setMaximum(...)`で設定
- `1`行ずつ`JTextArea`に文字列として読み込ませるために`InputStreamReader`を使用しているので、エンコーディングを`URLConnection#getContentEncoding()`や`URLConnection#getContentType()`などで取得
-- 何パーセント読み込んだかを`ProgressMonitor#setNote(...)`で表示する場合は`1`行が何バイトかを`String#getBytes(Charset)`で取得して計算
-- このサンプルでは改行は`LF`のみの`1`バイトであると決め打ちしている
-- 進捗を表示する前に`ProgressMonitor#setNote("temp note");`と適当な文字列を設定しておかないと`Note`に使用する`JLabel`が`null`のままで表示されない、またはレイアウトがおかしくなる

**参考リンク [#ie55372f]
- [[ProgressMonitorがダイアログを表示までの待ち時間>Swing/MillisToDecideToPopup]]
* 参考リンク [#reference]
- [[ProgressMonitorがダイアログを表示するまでの待ち時間>Swing/MillisToDecideToPopup]]

**コメント [#f8c160df]
* コメント [#comment]
#comment
- `EDT`外で`ProgressMonitor`を変更する(`monitor.setMinimum(0);`など)のは駄目な気がするので、修正。 -- &user(aterai); &new{2014-02-04 (火) 15:05:59};

#comment