簡體   English   中英

如何使用 FileChannels transferFrom() 方法監控進度 (JProgressBar)?

[英]How to monitor progress (JProgressBar) with FileChannels transferFrom() method?

我需要JProgressBar組件的一些幫助。 我的程序使用java.nio FileChannels將文件從一個地方復制到另一個地方。 實際的復制方法是transferFrom()

我現在有兩個問題。

  1. 如何監控 FileChannels 的傳輸進度? 我發現的所有教程都使用傳統的 java.io InputStreams 並在循環輸入流時增加進度 int。

  2. 我的復制方法(FileChannel 方法)封裝在一個單獨的方法中,該方法由其他方法調用,這些方法遍歷源文件夾和目標文件夾,然后為每個文件調用 FileChannel 方法。

如何為完整的復制機制實現 ProgressBar?

好吧,我應該早點閱讀常見問題解答,所以我想我必須編輯我的初始帖子而不是評論答案,對嗎?

好的,這就是我到目前為止所做的。 正如 jambjo 所建議的(順便感謝), transferFrom()方法現在循環了。 順便說一句:是否有更好的塊大小,或者它是否像 EJP 所說的那樣取決於我的進度條的粒度?

這是我的代碼片段:

while (position < size) {
 position += destination.transferFrom(source, position, chunkSize);
 current =  (position/size)*100;
 System.out.println(current);
}

不幸的是,“當前”值在循環中保持為 0,我不知道為什么。 我錯過了什么嗎?

再次感謝jambjo 我非常感謝您的意見! 現在單個文件的進度監控工作正常,讓我們解決我的第二個問題。


我想,不必,不僅要監控單個文件的進度,還要監控一堆文件的進度。 我的主要復制方法遍歷各種目錄並通過調用實際傳輸方法復制適當的文件。 所以復制方法不傳輸文件,它們只是為實際傳輸方法選擇文件。

我意識到我在這里復活了一個非常古老的線程,但我今天在谷歌搜索中遇到了它,所以......

如果您想監控進度,最好是因為 EJP 建議讓系統處理塊大小,以便優化傳輸。 監視的方法是為ReadableByteChannel編寫一個包裝類,您可以使用它在調用read方法時傳遞進度消息。 下面是一個例子:

package download.progress.example;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

public class DownloadProgressExample {
    public static void main( String[] args ) {
        new Downloader( "/tmp/foo.mp3", "http://example.com/bar.mp3" );
    }

    private interface RBCWrapperDelegate {
        // The RBCWrapperDelegate receives rbcProgressCallback() messages
        // from the read loop.  It is passed the progress as a percentage
        // if known, or -1.0 to indicate indeterminate progress.
        // 
        // This callback hangs the read loop so a smart implementation will
        // spend the least amount of time possible here before returning.
        // 
        // One possible implementation is to push the progress message
        // atomically onto a queue managed by a secondary thread then
        // wake that thread up.  The queue manager thread then updates
        // the user interface progress bar.  This lets the read loop
        // continue as fast as possible.
        public void rbcProgressCallback( RBCWrapper rbc, double progress );
    }

    private static final class Downloader implements RBCWrapperDelegate {
        public Downloader( String localPath, String remoteURL ) {
            FileOutputStream        fos;
            ReadableByteChannel     rbc;
            URL                     url;

            try {
                url = new URL( remoteURL );
                rbc = new RBCWrapper( Channels.newChannel( url.openStream() ), contentLength( url ), this );
                fos = new FileOutputStream( localPath );
                fos.getChannel().transferFrom( rbc, 0, Long.MAX_VALUE );
            } catch ( Exception e ) {
                System.err.println( "Uh oh: " + e.getMessage() );
            }
        }

        public void rbcProgressCallback( RBCWrapper rbc, double progress ) {
            System.out.println( String.format( "download progress %d bytes received, %.02f%%", rbc.getReadSoFar(), progress ) );
        }

        private int contentLength( URL url ) {
            HttpURLConnection           connection;
            int                         contentLength = -1;

            try {
                HttpURLConnection.setFollowRedirects( false );

                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod( "HEAD" );

                contentLength = connection.getContentLength();
            } catch ( Exception e ) { }

            return contentLength;
        }
    }

    private static final class RBCWrapper implements ReadableByteChannel {
        private RBCWrapperDelegate              delegate;
        private long                            expectedSize;
        private ReadableByteChannel             rbc;
        private long                            readSoFar;

        RBCWrapper( ReadableByteChannel rbc, long expectedSize, RBCWrapperDelegate delegate ) {
            this.delegate = delegate;
            this.expectedSize = expectedSize;
            this.rbc = rbc;
        }

        public void close() throws IOException { rbc.close(); }
        public long getReadSoFar() { return readSoFar; }
        public boolean isOpen() { return rbc.isOpen(); }

        public int read( ByteBuffer bb ) throws IOException {
            int                     n;
            double                  progress;

            if ( ( n = rbc.read( bb ) ) > 0 ) {
                readSoFar += n;
                progress = expectedSize > 0 ? (double) readSoFar / (double) expectedSize * 100.0 : -1.0;
                delegate.rbcProgressCallback( this, progress );
            }

            return n;
        }
    }
}

無法監控單個transferFrom調用的進度,但由於您可以將偏移量和長度參數傳遞給它,因此您可以圍繞它實現自己的循環並在合適大小的數據塊之間更新進度條。

...雖然這完全不是首先使用transferTo()的重點,即盡可能多地將復制交給內核。 要么你想這樣做,要么你想看到進展。 你必須選擇。 至少你必須在進度顯示中選擇你想要的粒度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM