openplanning

Hướng dẫn và ví dụ Java WritableByteChannel

  1. WritableByteChannel
  2. Methods
  3. write(ByteBuffer src)
  4. Example 1

1. WritableByteChannel

Nếu bạn mới bắt đầu với Java NIO, hãy đọc trước các bài viết dưới đây để hiểu thêm về các khái niệm cơ bản:
  • Hướng dẫn và ví dụ Java Nio (Java New IO)
WritableByteChannel là một interface mở rộng từ interface Channel, nó đại diện cho các kênh có thể ghi các bytes vào một thiết bị IO nào đó.
public interface WritableByteChannel extends Channel
So với inteface cha, WritableByteChannel chỉ cung cấp thêm duy nhất một phương thức để ghi các bytes từ một ByteBuffer vào Channel này.
public int write(ByteBuffer src) throws IOException;
Tại một thời điểm chỉ một hoạt động ghi trên Channel được diễn ra. Điều này có nghĩa là nếu một thread đang bắt đầu thao tác ghi trên một Channel thì các thread khác không thể ghi trên Channel này, chúng bị chặn (block) cho tới khi hoạt động này hoàn thành. Các hoạt động IO khác có thể tiến hành đồng thời với hoạt động ghi hay không phụ thuộc vào loại Channel.
Hệ thống phân cấp các interface và các lớp có liên quan tới WritableByteChannel:

2. Methods

WritableByteChannel chỉ cung cấp thêm một phương thức so với interface cha của nó.
public int write(ByteBuffer src) throws IOException;
Các phương thức khác thừa kế từ interface Channel:
public boolean isOpen();  
public void close() throws IOException;

3. write(ByteBuffer src)

public int write(ByteBuffer byteBuffer) throws IOException;
Phương thức write(ByteBuffer) ghi một dẫy các bytes nằm giữa positionlimit-1 trên ByteBuffer đã chỉ định vào Channel này. Nó sẽ ghi nhiều nhất có thể và trả về số bytes đã ghi.
  • Mỗi byte được ghi vào Channel này sẽ làm cho vị trí con trỏ trên ByteBuffer tăng thêm 1.
  • Trước khi gọi phương thức này bạn nên gọi phương thức ByteBuffer.clear() để sét position = 0limit = capacity.
  • Số bytes nhiều nhất có thể ghi được trong 1 lần gọi phương thức này là byteBuffer.limit()-byteBuffer.position().
Phương thức sẽ cố gắng ghi tất cả các bytes từ vị trí position tới limit-1 vào Channel này. Tuy nhiên một số loại Channel chẳng hạn như SocketChannel, tuỳ thuộc vào trạng thái của nó, có thể chỉ một vài bytes được ghi vào. Vì vậy bạn cần viết code giống dưới đây để đảm bảo rằng tất cả các bytes được ghi vào thành công:
while(byteBuffer.hasRemaining())  {
    channel.write(byteBuffer);
}
Tại một thời điểm chỉ một hoạt động ghi trên Channel được diễn ra. Điều này có nghĩa là nếu một thread đang bắt đầu thao tác ghi trên một Channel thì các thread khác không thể ghi trên Channel này, chúng bị chặn (block) cho tới khi hoạt động này hoàn thành. Các hoạt động IO khác có thể tiến hành đồng thời với hoạt động ghi hay không phụ thuộc vào loại Channel.

4. Example 1

Ví dụ: Sử dụng WritableByteChannel để ghi dữ liệu vào một file.
WritableByteChannel_ex1.java
package org.o7planning.writablebytechannel.ex;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;

public class WritableByteChannel_ex1 {
    // Windows: "C:/somepath/out-file.txt";
    private static final String outFilePath = "/Volumes/Data/test/out-file.txt";

    public static void main(String[] args) throws IOException {  
        OutputStream outputStream = null;
        WritableByteChannel channel = null;
        try {
            byte[] byteData = "JP日本-八洲".getBytes("UTF-8");
            
            File outFile = new File(outFilePath);
            outFile.getParentFile().mkdirs(); // Make sure parent folder is exists.
            outputStream = new FileOutputStream(outFile);
            
            // Create WritableByteChannel to write data to an OutputStream.
            channel = Channels.newChannel(outputStream);
            
            ByteBuffer buffer = ByteBuffer.allocate(byteData.length);
            buffer.put(byteData);
            // Set limit = current position and position = 0;
            buffer.flip();
            
            while(buffer.hasRemaining())  {
                channel.write(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeQuietly(outputStream);
            closeQuietly(channel);
        }
    }

    private static void closeQuietly(Closeable closeable) {
        try {
            closeable.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Cả OutputStreamChannel đều thi hành (implements) hoặc mở rộng từ interface Closeable, vì vậy nó có khả năng tự động đóng nếu bạn sử dụng cú pháp "Closeable-try-catch". Và chúng ta viết lại ví dụ trên một cách ngắn gọn hơn.
WritableByteChannel_ex1b.java
package org.o7planning.writablebytechannel.ex;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;

public class WritableByteChannel_ex1b {
    // Windows: "C:/somepath/out-file.txt";
    private static final String outFilePath = "/Volumes/Data/test/out-file.txt";

    public static void main(String[] args) throws IOException {
        File outFile = new File(outFilePath);
        outFile.getParentFile().mkdirs(); // Make sure parent folder is exists.

        // Closeable-try-catch Syntax:
        try (OutputStream outputStream = new FileOutputStream(outFile);
                // Create WritableByteChannel to write data to an OutputStream.
                WritableByteChannel channel = Channels.newChannel(outputStream);) { // try

            byte[] byteData = "JP日本-八洲".getBytes("UTF-8");
            ByteBuffer buffer = ByteBuffer.allocate(byteData.length);
            buffer.put(byteData);
            // Set limit = current position and position = 0;
            buffer.flip();

            while (buffer.hasRemaining()) {
                channel.write(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • Hướng dẫn và ví dụ Java Closeable