如何监控Apache Commons VFS中文件传输的进度



使用Apache Commons VFS,如何监控文件传输的进度。我需要能够通过上传和下载来做到这一点。我还需要通过 HTTP、FTP、SFTP 和 FTPS 监控进度。我在文档中找不到有关它的任何内容。

这可以通过从VFS获取输入和输出流来完成。以下示例使用来自 commons-net(VFS 的依赖项)的实用程序类来管理复制和进度监视。您也可以手动执行此操作。

import org.apache.commons.net.io.Util;
import org.apache.commons.net.io.CopyStreamListener;
private void copy(FileObject sourceFile, FileObject destinationFile, CopyStreamListener progressMonitor) throws IOException {
    InputStream sourceFileIn = sourceFile.getContent().getInputStream();
    try {
        OutputStream destinationFileOut = destinationFile.getContent().getOutputStream();
        try {
            Util.copyStream(sourceFileIn, destinationFileOut, Util.DEFAULT_COPY_BUFFER_SIZE, sourceFile.getContent().getSize(), progressMonitor);
        } finally {
            destinationFileOut.close();
        }
    } finally {
        sourceFileIn.close();
    }
}

提出的解决方案有点偏离,而且有点"弱"。让我们尝试一个更整洁的!
注意:以下代码需要 JDK 16。

给定一个使用标准启动的示例复制操作:

final var manager = VFS.getManager();
final var origin = manager.resolveFile(originUri.toString(), fileSystemOptions);
final var destination = manager.resolveFile(destinationUri.toString(), fileSystemOptions);
destination.copyFrom(origin, Selectors.SELECT_ALL);

只需将目标FileObject包装为我们可以称之为ProgressFileObject的自定义委托实现,该实现也将接受ProgressListener

final var listener = new ProgressListener() {
  @Override
  public void started() {
    System.out.println("Started");
  }
  @Override
  public void completed() {
    System.out.println("Completed");
  }
  @Override
  public void failed(@NotNull final Exception e) {
    System.out.println("Failed: " + e.getMessage());
  }
  @Override
  public void progress(@NotNull final ProgressEvent event) {
    final var out = "%dttt%dtttFile: %s".formatted(
        event.totalBytes(),
        event.totalTransferredBytes(),
        event.lastFileDestinationPath()
    );
    System.out.println(out);
  }
};
final var progressDestination = new ProgressFileObject(destination, listener);
progressFileObject.copyFrom(origin, Selectors.SELECT_ALL);

这将导致,带有一个文件夹:

Started
4648320         119391          File: /test_dir/AN/ANI0.evt
4648320         119511          File: /test_dir/AN/ANI0.hpj
4648320         119584          File: /test_dir/AN/ANI0.ipf
4648320         119585          File: /test_dir/AN/ANI0.ipm
4648320         1907060         File: /test_dir/AN/ANI0.LST
4648320         1907253         File: /test_dir/AN/ANI0.MRG
4648320         2472700         File: /test_dir/AN/ANI0.ODF
4648320         2472707         File: /test_dir/AN/ANI0.ph
4648320         2473421         File: /test_dir/AN/ANI0.rbj
4648320         2473547         File: /test_dir/AN/ANI0.rc
4648320         2473708         File: /test_dir/AN/ANI0.rst
4648320         2474813         File: /test_dir/AN/ANI0.rtf
4648320         2474814         File: /test_dir/AN/ANI0.txc
4648320         2474819         File: /test_dir/AN/ANI0.txm
4648320         2474820         File: /test_dir/AN/ANI0.vpf
4648320         2829348         File: /test_dir/AN/ANI0.VPG
4648320         2829466         File: /test_dir/AN/P0000001.rc
4648320         2829592         File: /test_dir/AN/P0000002.rc
4648320         4648275         File: /test_dir/AN/VPGSAV55.C2T
4648320         4648320         File: /test_dir/AN/VRPGWIN.RC
Completed

以下是ProgressFileObjectProgressListenerProgressEvent来源:

/**
 * @author Edoardo Luppi
 */
public class ProgressFileObject extends DecoratedFileObject {
  private final FileObject fileObject;
  private final ProgressListener listener;
  public ProgressFileObject(
      @NotNull final FileObject fileObject,
      @NotNull final ProgressListener listener) {
    super(fileObject);
    this.fileObject = fileObject;
    this.listener = listener;
  }
  @Override
  public void copyFrom(final FileObject file, final FileSelector selector) throws FileSystemException {
    if (!FileObjectUtils.exists(file)) {
      final var exception = new FileSystemException("vfs.provider/copy-missing-file.error", file);
      listener.failed(exception);
      throw exception;
    }
    listener.started();
    // Locate the files to copy across
    final List<FileObject> files = new ArrayList<>();
    file.findFiles(selector, false, files);
    // Calculate the total bytes that will be copied
    var totalBytes = 0L;
    for (final var srcFile : files) {
      if (srcFile.getType().hasContent()) {
        totalBytes += srcFile.getContent().getSize();
      }
    }
    var totalTransferredBytes = 0L;
    // Copy everything across
    for (final var srcFile : files) {
      // Determine the destination file
      final var relPath = file.getName().getRelativeName(srcFile.getName());
      final var destFile = resolveFile(relPath, NameScope.DESCENDENT_OR_SELF);
      // Clean up the destination file, if necessary
      if (FileObjectUtils.exists(destFile) && destFile.getType() != srcFile.getType()) {
        // The destination file exists, and is not of the same type, so delete it
        destFile.deleteAll();
      }
      // Copy across
      try {
        if (srcFile.getType().hasContent()) {
          try (final var content = srcFile.getContent()) {
            final var fileTransferredBytes = content.write(destFile);
            totalTransferredBytes += fileTransferredBytes;
            final var event = new ProgressEvent(
                totalBytes,
                totalTransferredBytes,
                fileTransferredBytes,
                srcFile.getName().getPath(),
                destFile.getName().getPath()
            );
        
            listener.progress(event);
          }
        } else if (srcFile.getType().hasChildren()) {
          destFile.createFolder();
        }
      } catch (final IOException e) {
        final var exception = new FileSystemException("vfs.provider/copy-file.error", e, srcFile, destFile);
        listener.failed(exception);
        throw exception;
      }
    }
    listener.completed();
  }
  @Override
  public URI getURI() {
    return fileObject.getURI();
  }
  @Override
  public Path getPath() {
    return fileObject.getPath();
  }
  @Override
  public boolean isSymbolicLink() throws FileSystemException {
    return fileObject.isSymbolicLink();
  }
  @Override
  public void forEach(final Consumer<? super FileObject> action) {
    fileObject.forEach(action);
  }
  @Override
  public Spliterator<FileObject> spliterator() {
    return fileObject.spliterator();
  }
  @Override
  public int hashCode() {
    return fileObject.hashCode();
  }
  @Override
  public boolean equals(final Object obj) {
    return fileObject.equals(obj);
  }
  @Override
  public String toString() {
    return fileObject.toString();
  }
  public interface ProgressListener {
    void started();
    void completed();
    void failed(@NotNull final Exception e);
    void progress(@NotNull final ProgressEvent event);
  }
  public record ProgressEvent(
      long totalBytes,
      long totalTransferredBytes,
      long lastFileTransferredBytes,
      String lastFileOriginPath,
      String lastFileDestinationPath
  ) {}
}

相关内容

  • 没有找到相关文章

最新更新