2016-04-27 87 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(); 
    } 
} 

這是我的代碼爲客戶端的write方法:

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(); 
    } 
    

    然而,如果目標是非阻塞套接字通道此變得複雜得多:你有操縱不管你是選擇OP_WRITE的取決於最後的write()是否返回零。你會發現這裏解釋了很多帖子,很多是我的。

  4. 我從來沒有在客戶端看到任何非阻塞I/O的原因,除非它連接到多個服務器(例如Web爬蟲)。我會在客戶端使用阻止模式或java.net.Socket,這將消除上面提到的寫入複雜性。

NB,你不需要同時關閉RandomAccessFile和從它派生的FileChannel。要麼會做。

+0

那麼,如果它是一個非阻塞套接字通道,最好的寫法是什麼? – jnapor

+0

使用* blocking *套接字通道或「java.net.Socket」。我說了。 – EJP