2010-02-14 12 views
14

मुझे JProgressBar घटक के साथ थोड़ी मदद चाहिए। मेरा प्रोग्राम java.nio FileChannels का उपयोग कर फ़ाइलों को एक स्थान से दूसरे स्थान पर कॉपी करता है। वास्तविक प्रति विधि transferFrom() है।FileChannels TransferFrom() विधि के साथ प्रगति (जेपी प्रोग्रेसबार) की निगरानी कैसे करें?

मुझे अब दो प्रश्न हैं।

  1. मैं फ़ाइलChannels की स्थानांतरण प्रगति की निगरानी कैसे करूं? मैंने पाया है कि सभी ट्यूटोरियल पारंपरिक java.io इनपुटस्ट्रीम का उपयोग करते हैं और इनपुटस्ट्रीम के माध्यम से लूपिंग करते समय प्रगति int बढ़ाते हैं।

  2. मेरी प्रतिलिपि विधियों (फ़ाइलChannel विधियों) एक अलग विधि में encapsulated हैं जो स्रोत और गंतव्य फ़ोल्डरों के बावजूद अन्य विधियों द्वारा लागू किया जाता है और फिर प्रत्येक फ़ाइल के लिए FileChannel विधियों का आह्वान करते हैं।

मैं पूरी प्रतिलिपि तंत्र के लिए प्रोग्रेसबार को कैसे कार्यान्वित करूं?

वैसे मुझे थोड़ा पहले पूछे जाने वाले प्रश्नों को पढ़ना चाहिए था, इसलिए मुझे लगता है कि मुझे जवाबों की टिप्पणी करने के बजाय अपनी प्रारंभिक पोस्ट को संपादित करना होगा, है ना?

ठीक है, मैंने अभी तक यह किया है। जैसे जंबो ने सुझाव दिया (वैसे धन्यवाद), transferFrom() विधि अब लूप हो गई है। बीटीडब्ल्यू: क्या कोई बेहतर हिस्सा आकार है, या क्या यह मेरी प्रगति पट्टी की ग्रैन्युलरिटी पर निर्भर करता है जैसे ईजेपी ने कहा था?

यहाँ मेरी कोड स्निपेट है:

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

दुर्भाग्य से 'वर्तमान' मूल्य पाश के भीतर 0 रहता है और मैं पता नहीं क्यों मिल गया है। क्या मुझे कुछ याद आ रही है?

धन्यवाद फिर से jambjo! मुझे वास्तव में आपका इनपुट अच्छा लगा! अब एक फ़ाइल की प्रगति की निगरानी काम करता है, चलो मेरी दूसरी समस्या को संबोधित करते हैं।


मुझे नहीं, मुझे केवल एक फ़ाइल की प्रगति की निगरानी करने की ज़रूरत नहीं है, बल्कि फाइलों का एक समूह है। मेरी मुख्य प्रति विधि विभिन्न निर्देशिकाओं के माध्यम से पुनरावृत्ति करती है और वास्तविक स्थानांतरण विधि का आह्वान करके उचित फ़ाइलों की प्रतिलिपि बनाता है। तो कॉपी विधियां फ़ाइलों को स्थानांतरित नहीं करती हैं, वे केवल वास्तविक स्थानांतरण विधि के लिए फ़ाइलों का चयन कर रहे हैं।

+0

यदि स्थिति और आकार पूर्णांक प्रकार (int या long) हैं, तो पूर्णांक विभाजन स्थिति/आकार हमेशा 0 होगा, यदि आकार स्थिति से अधिक है। (int) (100. * स्थिति/आकार) शायद आप जो चाहते हैं वह करेंगे। – jarnbjo

उत्तर

7

transferFrom के एकल आमंत्रण की प्रगति की निगरानी करने का कोई तरीका नहीं है, लेकिन चूंकि आप इसे ऑफ़सेट और लम्बाई पैरामीटर पास कर सकते हैं, इसलिए आप इसके चारों ओर अपने लूप को कार्यान्वित कर सकते हैं और डेटा के उपयुक्त आकार वाले हिस्सों के बीच प्रगति पट्टी को अपडेट कर सकते हैं।

+1

हां लेकिन यह समाधान एनआईओ एपीआई के प्रदर्शन को प्रभावित करेगा, है ना? इस मामले में, इसका उपयोग करने का कोई मतलब नहीं है। पीटर शायद आईओ एपीआई का उपयोग करना चाहिए। – Maxbester

+0

@ मैक्सबेस्टर: यदि भाग उचित रूप से आकार में हैं (बड़े भाग पसंद करते हैं), प्रदर्शन अंतर नगण्य होना चाहिए। – jarnbjo

+0

आप अपने स्वयं के थ्रेड में '' ट्रांसफर से '' निष्पादित कर सकते हैं, फिर अपने मुख्य (अवरुद्ध) थ्रेड से इसकी प्रगति की निगरानी करें ... यह दोनों दुनिया के सर्वश्रेष्ठ होना चाहिए –

2

... हालांकि यह पहले स्थान पर स्थानांतरण() का उपयोग करने के बिंदु के बगल में पूरी तरह से होगा, जो जितना संभव हो सके कर्नेल को कॉपी करना है। या तो आप ऐसा करना चाहते हैं या आप प्रगति देखना चाहते हैं। तुम्हे चुनना है। कम से कम आपको चुनना होगा कि प्रगति प्रदर्शन में आप कितनी ग्रैन्युलरिटी चाहते हैं।

+0

नहीं। आप सही हैं कि स्थानांतरण का मुख्य लाभ * विधियां FileChannel में सबसे कम संभव स्तर पर प्रतिलिपि बनाना है, लेकिन एक कारण नहीं है कि एक संपूर्ण फ़ाइल की प्रतिलिपि बनाना एक समय में छोटे हिस्सों की प्रतिलिपि बनाने से कहीं बेहतर प्रदर्शन करना चाहिए। – jarnbjo

+2

एर, हाँ वहाँ है, यही कारण है कि एपीआई मौजूद है। यदि कर्नेल को प्रक्रियाओं को फिर से निर्धारित करने की आवश्यकता नहीं है, तो स्मृति को दोबारा मैप करें, आदि, यह एक और अधिक कुशल प्रतिलिपि कर सकता है। बड़ा हिस्सा बेहतर है। – EJP

26

मुझे एहसास है कि मैं यहां एक बहुत पुराने धागे को पुनर्जीवित कर रहा हूं लेकिन मैं आज अपने गुगल में आया, इसलिए ...

यदि आप प्रगति की निगरानी करना चाहते हैं तो यह बेहतर होगा क्योंकि ईजेपी सिस्टम को चंक आकार के साथ सौदा करने का सुझाव देता है ताकि यह स्थानांतरण को अनुकूलित कर सके। निगरानी करने का तरीका 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://foo.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(); 
       connection.disconnect(); 
      } 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; 
     } 
    } 
} 
+2

बहुत अच्छा। हां, धागा पुराना था, लेकिन मुझे इसे गुगल करके भी मिला और आपका समाधान वास्तव में उपयोगी है। –

+2

यह काम करेगा, लेकिन ध्यान रखें कि यदि आप 'FileChannel'' के प्रतिस्थापन के रूप में 'FileChannel # स्थानांतरण से (...)' में स्रोत चैनल के रूप में एक 'रैपिंगबेट चैनेल' को एक रैपिंग का उपयोग करते हैं, तो आप एपीआई कार्यान्वयन में संभावित अनुकूलन को बाधित करते हैं। ओरेकल के जेवीएम उदा। 'ReadableByteChannel.read' के बजाय स्रोत चैनल से डेटा तक पहुंचने के लिए 'FileChannel.map' का उपयोग करता है। – jarnbjo

संबंधित मुद्दे