2017-11-29 15 views
0

私はクライアントマシンからネットワークフォルダ(UNCパス)にファイルをコピーするために使用されるファイルコピーアプリケーションに取り組んでいます。クライアントとネットワークフォルダは10Gbps接続で接続されています。従来のストリーム/バッファ機構では最大250Mbpsしか使用できませんでした。だから私はNIOメソッドを使い始めたのです。 Files.copy()transferFrom()の両方の方法で最大6Gbpsの帯域幅を使用できますが、これで十分です。しかし問題は、これらの両方の方法が進歩をもたらさないということです。アプリケーションにファイルの進行状況を表示する必要があります。進捗状況を監視する最速のJavaファイルコピー方法は何ですか?

次に、アップロードの進捗状況を追跡するためのReadableByteChannelインターフェイスが見つかりました。しかし、これを実装した後、アップロード速度は100Mbpsに落ちました。私が正しく実装していないかどうかはわかりません。

OSレベルのコピー(Ctrl + CとCtrl + V)は、6Gbpsの帯域幅使用で動作します。どのように進捗監視とJavaメソッドで同じを達成するために?

public class AppTest { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     File source = new File(args[0]); 
     File dest = new File(args[1] + File.separator + source.getName()); 
     long startTime = System.currentTimeMillis(); 
     try { 
      if (args[2].equalsIgnoreCase("s")) { 
       copyUsingStream(source, dest, args.length > 3 ? Integer.parseInt(args[3]) : 32 * 1024); 
      } else if (args[2].equalsIgnoreCase("fp")) { 
       copyUsingFileChannelWithProgress(source, dest); 
      } else if (args[2].equalsIgnoreCase("f")){ 
       copyUsingFileChannels(source, dest); 
      } else if (args[2].equalsIgnoreCase("j")) { 
       copyUsingFilescopy(source, dest); 
      } else { 
       System.out.println("Unknown copy option."); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Completed in " + (System.currentTimeMillis() - startTime)); 
    } 

    private static void copyUsingStream(File source, File dest, int buf_size) throws IOException { 
     System.out.println("Copying using feeder code..."); 
     System.out.println("Buffer Size : " + buf_size); 
     FileInputStream sourceFileIS = new FileInputStream(source); 
     FileOutputStream srvrFileOutStrm = new FileOutputStream(dest); 
     byte[] buf = new byte[buf_size]; 
     int dataReadLen; 
     while ((dataReadLen = sourceFileIS.read(buf)) > 0) { 
      srvrFileOutStrm.write(buf, 0, dataReadLen); 
     } 
     srvrFileOutStrm.close(); 
     sourceFileIS.close(); 
    } 

    private static void copyUsingFileChannels(File source, File dest) 
      throws IOException { 
     System.out.println("Copying using filechannel..."); 
     FileChannel inputChannel = null; 
     FileChannel outputChannel = null; 
     try { 
      inputChannel = new FileInputStream(source).getChannel(); 
      outputChannel = new FileOutputStream(dest).getChannel(); 
      outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); 
     } finally { 
      inputChannel.close(); 
      outputChannel.close(); 
     } 
    } 

    private static void copyUsingFilescopy(File source, File dest) throws IOException{ 
     Files.copy(source.toPath(), dest.toPath()); 
    } 

    interface ProgressCallBack { 

     public void callback(CallbackByteChannel rbc, double progress); 
    } 

    static class CallbackByteChannel implements ReadableByteChannel { 

     ProgressCallBack delegate; 
     long size; 
     ReadableByteChannel rbc; 
     long sizeRead; 

     CallbackByteChannel(ReadableByteChannel rbc, long sizeRead, long expectedSize, ProgressCallBack delegate) { 
      this.delegate = delegate; 
      this.sizeRead = sizeRead; 
      this.size = expectedSize; 
      this.rbc = rbc; 
     } 

     @Override 
     public void close() throws IOException { 
      rbc.close(); 
     } 

     public long getReadSoFar() { 
      return sizeRead; 
     } 

     @Override 
     public boolean isOpen() { 
      return rbc.isOpen(); 
     } 

     @Override 
     public int read(ByteBuffer bb) throws IOException { 
      int n; 
      double progress; 
      if ((n = rbc.read(bb)) > 0) { 
       sizeRead += n; 
       progress = size > 0 ? (double) sizeRead/(double) size * 100.0 : -1.0; 
       delegate.callback(this, progress); 
      } 
      return n; 
     } 
    } 

    private static void copyUsingFileChannelWithProgress(File sourceFile, File destFile) throws IOException { 
     ProgressCallBack progressCallBack = new ProgressCallBack() { 

      @Override 
      public void callback(CallbackByteChannel rbc, double progress) { 
//       publish((int)progress); 
      } 
     }; 
     FileOutputStream fos = null; 
     FileChannel sourceChannel = null; 
     sourceChannel = new FileInputStream(sourceFile).getChannel(); 
     ReadableByteChannel rbc = new CallbackByteChannel(sourceChannel, 0, sourceFile.length(), progressCallBack); 
     fos = new FileOutputStream(destFile); 
     fos.getChannel().transferFrom(rbc, 0, sourceFile.length()); 
     if (sourceChannel.isOpen()) { 
      sourceChannel.close(); 
     } 
     fos.close(); 
    } 

} 

答えて

0

transferFrom()は、ファイルサイズよりも大きいチャンクサイズの大きなループで使用します。ここで進行状況を表示するには、速度をトレードオフする必要があります。速度を保持するには、おそらくチャンクを少なくとも1Mbにする必要があります。

+0

ありがとうございました! –

関連する問題