How do I monitor the progress of a file transfer in Apache Commons VFS?
使用 Apache Commons VFS,我如何监控文件传输的进度。我需要能够通过上传和下载来做到这一点。我还需要监控 HTTP、FTP、SFTP 和 FTPS 的进度。我在文档中找不到任何关于它的内容。
这可以通过从 VFS 获取输入和输出流来完成。以下示例使用来自 commons-net(VFS 的依赖项)的实用程序类来管理复制和进度监控。您同样可以手动完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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.
给出一个使用标准启动的示例复制操作:
1 2 3 4 | 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); |
使用自定义委托实现简单地package目标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 ="%d\\t\\t\\t%d\\t\\t\\tFile: %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); |
这将导致一个文件夹:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 |
以下是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | /** * @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 ) {} } |