• title: ProgressMonitorInputStreamを使用してテキストファイルのダウンロード状況を表示 tags: [ProgressMonitorInputStream, ProgressMonitor, JProgressBar, SwingWorker, URLConnection, JTextArea] author: aterai pubdate: 2013-04-22T03:35:42+09:00 description: ProgressMonitorInputStreamを使用してテキストファイルのダウンロード状態を進捗表示します。

概要

ProgressMonitorInputStreamを使用してテキストファイルのダウンロード状態を進捗表示します。

サンプルコード

class RunAction extends AbstractAction {
  public RunAction() {
    super("Load");
  }
  @Override public void actionPerformed(ActionEvent e) {
    runButton.setEnabled(false);
    textArea.setText("");

    URLConnection urlConnection = getURLConnection();
    if(urlConnection==null) {
      return;
    }
    Charset cs = getCharset(urlConnection, "EUC-JP");
    int length = urlConnection.getContentLength();
    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);

      worker = new MonitorTask(pmis, cs, length);
      worker.execute();
    }catch(IOException ex) {
      ex.printStackTrace();
    }
  }
}

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");
      monitor.setNote(c.note);
    }
    textArea.setCaretPosition(textArea.getDocument().getLength());
  }
  @Override public void done() {
    runButton.setEnabled(true);
    String text = null;
    try{
      if(pmis!=null) {
        pmis.close();
      }
      text = isCancelled() ? "Cancelled" : get();
    }catch(IOException | InterruptedException | ExecutionException ex) {
      ex.printStackTrace();
      text = "Exception";
    }
    System.out.println(text);
  }
}

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(BufferedReader reader = new BufferedReader(new InputStreamReader(pmis, cs));
      Scanner scanner = new Scanner(reader)) {
      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;
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、URLConnectionから開いたInputStreamProgressMonitorInputStreamをラップして、ファイルのダウンロード進捗状態を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に使用するJLabelnullのままで表示されない、またはレイアウトがおかしくなる

参考リンク

コメント