2012-05-20 30 views
6

Tôi phải chuyển ~ 100MB dữ liệu qua ServerSocket bằng NIO, nhưng tôi không thể tìm ra cách thực hiện điều này mà không cần chuyển bất kỳ nơi nào/giữ trạng thái chuyển.Java - Chuyển các tệp lớn qua các kênh - NIO

Ý tưởng đầu tiên của tôi là gửi kích thước tệp, dường như tôi không thể gửi kích thước của các tệp lớn đó vì nó thậm chí không phù hợp với RAM cùng một lúc. Sau đó, tôi nghĩ, tại sao không chỉ chuyển đến khi không có gì được nhận, nhưng thats khi vấn đề đi kèm trong.

Thậm chí nếu tôi ghi dữ liệu máy chủ mặt mọi lúc

 FileChannel fc = new FileInputStream(f).getChannel(); 
     ByteBuffer buffer = ByteBuffer.allocate(1024); 
     while(fc.read(buffer) > 0) { 
      buffer.flip(); 
      while(channel.write(buffer) > 0); 
      buffer.clear(); 
     } 

nhưng vì có phải phá vỡ trong chuyển tập tin một số thời gian đọc dữ liệu liên tục và phá vỡ khi không có gì là có sẵn là ý tưởng tồi.

Tôi không thể hiểu làm thế nào tôi có thể nói với khách hàng nếu vẫn còn dữ liệu sẵn có mà không phải gửi từng đoạn dữ liệu dưới dạng gói mới với mã opcode, v.v.

Tôi cũng tự hỏi nếu cách theres tốt hơn để gửi toàn bộ đệm hơn dưới

while(channel.write(buffer) > 0); 
+0

Tôi đã trả lời một phần của điều này nhưng tôi phải nói rằng tôi không hiểu ý bạn là gì "có phải mất thời gian chuyển tập tin" và "đọc dữ liệu liên tục và phá vỡ khi không có gì là ý tưởng tồi ". Vui lòng giải thích. – EJP

Trả lời

3

Cách đúng để sao chép các kênh truyền hình qua bộ đệm như sau:

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

này sẽ chăm sóc của tất cả các trường hợp góc bao gồm chiều dài đọc = ghi chiều dài và có dữ liệu còn sót lại ở phần cuối của đầu vào!.

NB dành cho chế độ chặn. Nếu bạn đang ở chế độ không chặn, bạn nên quay lại vòng lặp select() nếu read() hoặc write() trả về 0.

+0

Ước gì tôi có thể chấp nhận nhiều câu trả lời, bởi vì tôi không chắc chắn về việc ai chấp nhận điều này. Vizier đã cho tôi một giải pháp hoàn hảo nhưng bạn đã hoàn thành nó. Tôi hiện đang sử dụng mã gần như chính xác như của bạn và nó hoạt động hoàn hảo. Cảm ơn rất nhiều cho cả hai bạn. Tuy nhiên, tôi không chắc chắn những gì hoạt động nhỏ gọn làm, nhưng tôi đoán nó phải được tốt hơn so với thanh toán bù trừ. Cảm ơn một lần nữa! – Ruuhkis

+1

@Ruuhkis 'compact()' loại bỏ những thứ đã được viết nhưng để lại bất cứ thứ gì chưa được viết. Nếu bạn sử dụng 'clear()' thay vì bạn đang mạo hiểm mất dữ liệu nếu độ dài đọc! = Độ dài ghi, có thể xảy ra bất cứ lúc nào. – EJP

+0

Cảm ơn, đó là một số lời khuyên tuyệt vời. – Ruuhkis

4

Có lẽ bạn đang tìm kiếm này:

channel.transferFrom(0, fc.size(), fc); 
+0

Wow, làm thế nào tôi có thể bỏ lỡ điều đó? Tôi sẽ cố gắng ngày mai và hy vọng sẽ chấp nhận câu trả lời của bạn nếu nó hoạt động tốt. – Ruuhkis

+0

@Ruuhkis Xin lưu ý rằng bạn cần phải gọi phương thức này trong một vòng lặp, vì nó không được đảm bảo để chuyển toàn bộ chiều dài trong một lời gọi. Xem thêm câu trả lời của tôi. – EJP

+0

Vui lòng đọc nhận xét của tôi về câu trả lời của EJP. – Ruuhkis

0

Nếu bạn không thể phụ thuộc vào ổ cắm để ngỏ, không có cách nào xung quanh xây dựng một cơ chế phục hồi và tiếp tục vào giao thức của bạn. Như để nói cho khách hàng biết bao nhiêu byte để mong đợi, bạn có thể tìm thấy kích thước của một tập tin mà không cần đọc nó vào bộ nhớ bằng cách sử dụng File.length.

Các vấn đề liên quan