Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java asyncExec不适用于文件复制进度_Java_Swt - Fatal编程技术网

Java asyncExec不适用于文件复制进度

Java asyncExec不适用于文件复制进度,java,swt,Java,Swt,我在使用线程刷新SWT构建的图形用户界面时遇到了一个大问题。我已经研究了文档,但还没弄明白。 任务是将文件夹中的所有文件(仅将文件,而不是子目录)复制到给定的目标文件夹。 在这个过程中,我计算已经完成的文件的大小和剩余时间。 然后,在每次迭代中,我都会尝试通过单步执行进度条和更改状态标签来显示这些信息 代码如下所示: public class MyClass { private Display display; private ProgressBar progressBar; pri

我在使用线程刷新SWT构建的图形用户界面时遇到了一个大问题。我已经研究了文档,但还没弄明白。 任务是将文件夹中的所有文件(仅将文件,而不是子目录)复制到给定的目标文件夹。 在这个过程中,我计算已经完成的文件的大小和剩余时间。 然后,在每次迭代中,我都会尝试通过单步执行进度条和更改状态标签来显示这些信息

代码如下所示:

public class MyClass {
  private Display display;
  private ProgressBar progressBar;
  private Label statusLabel;

  private File inputFile;
  private File outputFolder;

  ...

  public void init(File inputFile, File outputFolder) {
    this.inputFile = inputFile;
    this.outputFolder = outputFolder;

    progressBar.setSelection(0);
    statusLabel.setText("");
  }

  private class CopyFileTask implements Runnable {
    @Override
    public void run() {
      long processedSize = 0L;
      long startTime = System.currentTimeMillis();
      long totalSize = 0L;

      try {
        File[] entries = inputFile.getParentFile().listFiles();

        for (File theEntry : entries) {
          if (theEntry.isFile()) {
            totalSize += theEntry.length();
          }
        }

        for (File theEntry : entries) {
          if (theEntry.isFile()) {
            String entryName = theEntry.getName();
            File file = new File(outputFolder, entryName);

            InputStream fis = new FileInputStream(theEntry);
            FileOutputStream fos = new FileOutputStream(file);

            try {
              byte[] buffer = new byte[1024];
              int len;

              while ((len = fis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
                processedSize += len;

                showProgressInfo(startTime, processedSize, totalSize);
              }
            } finally {
              try {
                fis.close();
                fos.close();
              } catch (IOException e) {
              }
            }
          }
        }
      } catch (Exception e) {
        Log.error(e);
      }
    }

    private void showProgressInfo(long startTimeMillis, long processedSize, long totalSize) {
      int percent = (int) ((double) processedSize / (double) totalSize * 100.0);
      progressBar.setSelection(percent);

      long elapsedTimeSeconds = (System.currentTimeMillis() - startTimeMillis) / 1000L;
      long remainingSize = totalSize - processedSize;
      long remainingTimeSeconds = (long) ((double) remainingSize
        / (double) processedSize * elapsedTimeSeconds);
      statusLabel.setText(formatFileSize(processedSize)
        + " of "
        + formatFileSize(totalSize)
        + " - Remaining: "
        + secondsToString(remainingTimeSeconds));
    }

    private String formatFileSize(long value) {
      // return value in Bytes, KB, MB, GB
    }

    private String secondsToString(long value) {
      // return value in MM:SS
    }
  }
}
我通过单击一个按钮开始此过程:

startButton.addListener(SWT.Selection, new Listener() {
  @Override
  public void handleEvent(Event e) {
    display.asyncExec(new CopyFileTask());
  }    
});

现在我的问题是,GUI在整个过程完成之前一直处于冻结状态,或者换句话说,标签和进度条仅在结束时刷新。

您应该从不同的线程在selectionListener中启动更新:

startButton.addListener(SWT.Selection, new Listener() {

    @Override
    public void handleEvent(Event e) {
        Thread thread = new Thread(new CopyFileTask());
        thread.start();
    }
});
然后使用asyncExec将当前线程的进度更新发布到显示线程,例如:

...                         
final long tmpStartTime = startTime;
final long tmpProcessedSize = processedSize;
final long tmpTotalSize = totalSize;
Display.getDefault().asyncExec(new Runnable() {

    @Override
    public void run() {
        showProgressInfo(tmpStartTime, tmpProcessedSize, tmpTotalSize);
    }
});
...                         

asyncExec在UI线程上执行代码,而不是在新的单独线程中。请启动一个包含代码的后台线程,然后将所有与UI交互的调用包装为asyncExec调用。阅读了解更多信息。我获取了您的代码片段并修改了我的程序,但现在复制过程非常缓慢。复制一个100K文件需要一个多小时,问题似乎在于进度条刷新。为了确保我做的都是正确的:在start按钮的选择处理程序中,我使用CopyFileTask创建线程并启动线程。CopyFileTask类实现Runnable,run方法复制文件,在循环中,我还使用asyncExec更改进度信息?可能问题在于频繁的UI更新。根据100K文件显示的缓冲读取,将溢出约25k个可运行文件以排队和执行。每读取1kb或每过一秒钟,尝试显示ProgressInfo。