openplanning

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

Xem thêm các chuyên mục:

Hãy theo dõi chúng tôi trên Fanpage để nhận được thông báo mỗi khi có bài viết mới. Facebook

1- Reader

Reader là một lớp nằm trong package java.io, nó là một lớp cơ sở đại diện cho một dòng chảy của các ký tự (stream of characters) có được khi đọc một nguồn dữ liệu nào đó, chẳng hạn file văn bản.

public abstract class Reader implements Readable, Closeable
Về cơ bản bạn không thể sử dụng lớp Reader một cách trực tiếp vì nó là một lớp trừu tượng, tuy nhiên trong trường hợp cụ thể bạn có thể sử dụng một trong các lớp con của nó.
Hãy xem một tình huống đọc một file văn bản với mã hoá UTF-8:
utf-8-file.txt

JP日本-八洲
UTF-8 sử dụng 1, 2, 3 hoặc 4 bytes để lưu trữ một ký tự. Hình ảnh dưới đây cho thấy các bytes trong file nói trên.
FileReader là một lớp con của Reader thường được sử dụng để đọc các file văn bản và chúng ta sẽ nhận được một dòng chảy các ký tự (stream of characters). Bằng một cách nào đó các ký tự UTF-8 sẽ được chuyển đổi thành các ký tự của Java.
Chú ý: Kiểu char (Ký tự) trong Java có kích thước 2 bytes. Như vậy các ký tự trên FileReader là các ký tự có kích thước 2 bytes.
Xem thêm giải thích của tôi về cách Java chuyển đổi các ký tự UTF-8 thành các ký tự Java:
Reader Methods

public static Reader nullReader()   

public int read(java.nio.CharBuffer target) throws IOException  

public int read() throws IOException  

public int read(char cbuf[]) throws IOException  

public int read(char cbuf[], int off, int len) throws IOException  

public long skip(long n) throws IOException  

public boolean ready() throws IOException   

public boolean markSupported()  

public void mark(int readAheadLimit) throws IOException  

public void reset() throws IOException   

public void close() throws IOException  

public long transferTo(Writer out) throws IOException

2- read()


public int read() throws IOException  
Phương thức read() được sử dụng để đọc một ký tự, nó trả về mã số của ký tự vừa đọc được (Là một số nguyên trong khoảng 0 đến 65535), hoặc trả về -1 nếu đã tiến tới cuối stream (dòng chẩy).
Phương thức này sẽ chặn (block) cho tới khi ký tự sẵn có hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
Ví dụ:
Reader_read_ex1.java

package org.o7planning.reader.ex;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class Reader_read_ex1 {

    public static void main(String[] args) throws IOException {
        // StringReader is a subclass of Reader.
        Reader reader = new StringReader("JP日本-八洲");

        int charCode;
        while((charCode = reader.read()) != -1) {
            System.out.println((char)charCode + " " + charCode);
        }
        reader.close();
    }
}
Output:

J 74
P 80
日 26085
本 26412
- 45
八 20843
洲 27954

3- read(char[])


public int read(char[] cbuf) throws IOException  
Phương thức read(char[]) đọc các ký tự và gán vào các phần tử của mảng và trả về số ký tự vừa đọc được. Phương thức này trả về -1 nếu đã tiến tới cuối stream.
Phương thức này sẽ chặn (block) cho tới khi các ký tự sẵn có hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
Về cơ bản sử dụng phương thức read(char[]) sẽ có hiệu xuất cao hơn so với phương thức read(), vì nó giảm số lần cần đọc từ stream.
Reader_read_ex1.java

package org.o7planning.reader.ex;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class Reader_read_ex2 {

    public static void main(String[] args) throws IOException {
        // StringReader is a subclass of Reader.
        Reader reader = new StringReader("123456789-987654321-12345");
 
        // Create a temporary char array.
        char[] temp = new char[10];
        int charCount = -1;
         
        while ((charCount = reader.read(temp)) != -1) {
            String s = new String(temp, 0, charCount);
            System.out.println(s);
        }
        reader.close();
    }
}
Output:

123456789-
987654321-
12345

4- read(char[], int, int)


public int read(char[] cbuf, int offset, int len) throws IOException  
Phương thức read(char[],int,int) đọc các ký tự và gán vào các phần tử của mảng từ chỉ số offset tới chỉ số offset+len, và trả về số ký tự vừa đọc được. Phương thức này trả về -1 nếu đã tiến tới cuối stream.
Phương thức này sẽ chặn (block) cho tới khi các ký tự sẵn có hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.

5- read(java.nio.CharBuffer)


public int read(java.nio.CharBuffer target) throws IOException  
Phương thức read(CharBuffer) được sử dụng để đọc các ký tự vào một đối tượng CharBufffer, và trả về số ký tự đọc được từ stream hoặc trả về -1 nếu đã tiến tới cuối của stream.
Phương thức này sẽ chặn (block) cho tới khi các ký tự sẵn có hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
Reader_read_ex3.java

package org.o7planning.reader.ex;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.nio.CharBuffer;

public class Reader_read_ex3 {

    public static void main(String[] args) throws IOException {
        // StringReader is a subclass of Reader.
        Reader reader = new StringReader("123456789-987654321-12345");
 
        CharBuffer cb = CharBuffer.allocate(10);
    
        // Read for the first time
        reader.read(cb);
        System.out.println(cb.flip().toString());
        
        // Read for the second time
        reader.read(cb);
        System.out.println(cb.flip().toString());
        
        // Read for the third time.
        reader.read(cb);
        System.out.println(cb.flip().toString());
        
        reader.close();  
    }
}
Output:

123456789-
987654321-
12345
  • TODO Link?

6- close()


public void close() throws IOException  
Đóng stream này và giải phóng mọi tài nguyên hệ thống được liên kết với nó. Khi stream đã bị đóng, các lệnh gọi tiếp read(), ready(), mark(), reset() hoặc skip() sẽ tạo ra một IOException. Đóng stream đã đóng trước đó không có tác dụng.

public interface Closeable extends AutoCloseable
Lớp Reader thi hành interface Closeable. Nếu bạn viết code theo quy tắc của AutoCloseable thì hệ thống sẽ tự đóng stream cho bạn mà không cần phải gọi trực tiếp phương thức close().
Reader_close_ex1.java

package org.o7planning.reader.ex;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Reader_close_ex1 {
    
    // Or Windows path: C:/Somefolder/utf8-file-without-bom.txt
    private static final String file_path = "/Volumes/Data/test/utf8-file-without-bom.txt";

    public static void main(String[] args) throws IOException {
        
        // (Reader class implements Closeable)
        // (Closeable interface extends AutoCloseable)
        // try block will automatically close stream for you.
        try (Reader fileReader= new FileReader(file_path)) {
            int code;
            while((code = fileReader.read()) !=  -1)  {
                System.out.println((char)code);
            }
        } // end try
    }
}
  • TODO Link?

7- skip(long)


public long skip(long n) throws IOException  
Phương thức skip(long) bỏ qua "n" ký tự.
Phương thức này sẽ chặn (block) cho tới khi các ký tự sẵn có hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
Reader_skip_ex1.java

package org.o7planning.reader.ex;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class Reader_skip_ex1 {

    public static void main(String[] args) throws IOException {
        // StringReader is a subclass of Reader.
        Reader reader = new StringReader("123456789-987654321-ABCDE");

        int firstCharCode = reader.read();
        int secondCharCode = reader.read();

        System.out.println("First character: " + (char) firstCharCode);
        System.out.println("Second character: " + (char) secondCharCode);

        reader.skip(18); // Skips 18 characters.

        int code;
        while ((code = reader.read()) != -1) {
            System.out.println((char) code);
        }
        reader.close();
    }
}
Output:

First character: 1
Second character: 2
A
B
C
D
E

8- transferTo(Writer)


// Java 10+
public long transferTo(Writer out) throws IOException
Phương thức transferTo(Writer) được sử dụng để đọc tất cả các ký tự từ Reader hiện tại và ghi chúng vào đối tượng Writer đã cho, và trả về số ký tự đã chuyển sang Writer. Sau khi hoàn thành, đối tượng Reader hiện tại sẽ ở cuối của stream. Phương thức này sẽ không đóng đối tượng Reader hiện tại cũng như đối tượng Writer.
Reader_transferTo_ex1.java

package org.o7planning.reader.ex;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;

public class Reader_transferTo_ex1 {

    public static void main(String[] args) throws IOException {
        // StringReader is a subclass of Reader.
        Reader reader = new StringReader("123456789-987654321-ABCDE");

        // Or Windows path: C:/Somepath/out-file.txt
        File file = new File("/Volumes/Data/test/out-file.txt");
        // Create parent folder.
        file.getParentFile().mkdirs();

        Writer writer = new FileWriter(file);

        reader.skip(10); // Skips 10 characters.

        reader.transferTo(writer);

        reader.close();
        writer.close();
    }
}
Output:
out-file.txt

987654321-ABCDE

9- markSupported()


public boolean markSupported()  
Phương thức markSupported() được sử dụng để kiểm tra đối tượng Reader hiện tại có hỗ trợ hoạt động mark(int) hay không. (Xem thêm phương thức mark(int))
Reader markSupported()?
StringReader true
CharArrayReader true
BufferedReader true
LineNumberReader true
   
FilterReader true or false
   
InputStreamReader false
FileReader false
PushbackReader false

10- mark(int)


public void mark(int readAheadLimit) throws IOException  
Phương thức mark(int) cho phép bạn đánh dấu vị trí hiện tại trên stream. Bạn có thể đọc tiếp các ký tự tiếp theo, và gọi phương thức reset() để quay trở lại vị trí đã đánh dấu trước đó. Trong đó readAheadLimit là số lượng ký tự tối đa có thể đọc sau khi đánh dấu mà không làm mất vị trí đã đánh dấu.
Chú ý: Không phải tất cả các Reader đều hỗ trợ hoạt động mark(int). Để chắc chắn bạn cần gọi phương thức markSupported() để kiểm tra xem đối tượng Reader hiện tại có hỗ trợ hoạt động đó hay không.
Reader_mark_ex1.java

package org.o7planning.reader.ex;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class Reader_mark_ex1 {

    public static void main(String[] args) throws IOException {
        // StringReader is a subclass of Reader.
        Reader reader = new StringReader("123456789-987654321-ABCDE");

        reader.skip(10); // Skips 10 characters.

        System.out.println("StringReader markSupported? " + reader.markSupported()); // true
        
        reader.mark(9);
        
        int code1 = reader.read();
        int code2 = reader.read();
        
        System.out.println((char) code1); // '9'
        System.out.println((char) code2); // '8'
        reader.skip(5);
        
        System.out.println("Reset");
        reader.reset(); // Return to the marked position.
        
        int code;
        while((code = reader.read())!= -1) {
            System.out.println((char)code);
        }
        reader.close();
    }
}
Output:

StringReader markSupported? true
9
8
Reset
9
8
7
6
5
4
3
2
1
-
A
B
C
D
E

11- reset()


public void reset() throws IOException  
Nếu đối tượng Reader này hỗ trợ việc đánh dấu vị trí hiện tại thông qua phương thức mark(int), thì phương thức reset() được sử dụng để quay trở lại vị trí đã được đánh dấu.

12- ready()


public boolean ready() throws IOException  
Phương thức ready() trả về true nếu sẵn có một ký tự trên stream để đọc mà không phải chờ đợi, ngược lại trả về false.

Xem thêm các chuyên mục: