2016-04-27 17 views
0

ファイルの読み取りに問題があります。私はNIOには全く新しいです。サーバーに送信するファイルの実際のサイズは、ほとんど900MBであり、3MBしか受信しませんでした。不完全なファイルコピーJava NIO

読書のためのサーバのサイドコード:

private void read(SelectionKey key) throws IOException{ 
    SocketChannel socket = (SocketChannel)key.channel(); 
    RandomAccessFile aFile = null; 
    ByteBuffer buffer = ByteBuffer.allocate(300000000); 
    try{ 
     aFile = new RandomAccessFile("D:/test2/test.rar","rw"); 

     FileChannel inChannel = aFile.getChannel(); 

     while(socket.read(buffer) > 0){ 
      buffer.flip(); 
      inChannel.write(buffer); 
      buffer.compact(); 
     } 
     System.out.println("End of file reached.."); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } 
} 

これは、クライアント側の書き込み方法のための私のコードです:

private void write(SelectionKey key) throws IOException { 
    SocketChannel socket = (SocketChannel) key.channel(); 
    RandomAccessFile aFile = null; 
    try { 
     File f = new File("D:/test.rar"); 
     aFile = new RandomAccessFile(f, "r"); 
     ByteBuffer buffer = ByteBuffer.allocate(300000000); 

     FileChannel inChannel = aFile.getChannel(); 
     while (inChannel.read(buffer) > 0) { 
      buffer.flip(); 
      socket.write(buffer); 
      buffer.compact(); 
     } 
     aFile.close(); 
     inChannel.close(); 

     key.interestOps(SelectionKey.OP_READ); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
+0

考えてみてください:read()は通常、読み込まれたバイト数を正確に示します。これは、すべてのバッファー・バイトが読み取られたわけではありません。少なくとも古い学校のIOでは、バッファからすべてのバイトを読み込むまでループしなければなりませんでした。 – GhostCat

+0

'socket.read(buffer)> 0' +ノンブロッキングIO =失敗。ゼロはストリームの終わりを意味するものではなく、その時点で読み込み可能なデータがないことを意味します。だから、あなたは完全にブロックする方法で読んでいますが、明らかに機能しないNIOを扱っています。 – user3707125

答えて

2
  1. 新しいファイルを毎回開いていますソケットチャネルは読み込み可能になります。到着したすべてのTCPセグメントは、ターゲットファイルを再作成しているため、以前に受信したものはすべて破棄します。

    単純な修正は、ファイルをすべてOP_READに添付して開くことですが、それはうんざりして非効率になります。ターゲットファイルは、それが分かったら直ちに開き、送信者からのストリームの終わりを読み取ったときに閉じるか、ストリームの終わりまでに送信されなかったコンテンツ全体を読み取ったときに閉じる必要があります。私はあなたのアプリケーションプロトコルを公開していないので、もっと具体的にすることはできません。

  2. read()は、ブロックせずに読み込み可能なデータがない場合にゼロを返します。あなたはそれをファイルの終わりとして扱っています。そうではありません。
  3. 次のようにチャンネル間の書き込みへの標準的な方法は、次のとおりです。

    while ((in.read(buffer) > 0 || buffer.position() > 0) 
    { 
        buffer.flip(); 
        out.write(buffer); 
        buffer.compact(); 
    } 
    

    しかしターゲットは、非ブロッキングソケットチャネルであれば、これはかなり複雑取得:あなたが選択しているかどうかを操作しなければなりません最後のwrite()がゼロを戻したかどうかによって、OP_WRITEの有無が判別されます。これは多くの記事の中で私が多くを説明しています。

  4. 複数のサーバー(Webクローラーなど)に接続していない限り、クライアント側で非ブロッキングI/Oの理由がわかりません。私はブロッキングモードまたはクライアントでjava.net.Socketを使用します。これは上記の複雑さを取り除きます。

NBあなたはそれから派生したRandomAccessFileFileChannelの両方をクローズする必要はありません。いずれかが行います。

+0

それは非ブロッキングソケットチャンネルであれば、どのような書き込み方法が最適ですか? – jnapor

+0

*ブロッキング*ソケットチャンネル、または 'java.net.Socket'。私は言った。 – EJP