1. Khái niệm về luồng trong Java
Khi lập bất kỳ chương trình nào trong một ngôn ngữ nào thì vấn đề vào ra dữ liệu giữa
chương trình và nguồn dữ liệu cũng như đích dữ liệu là vấn đề mà người lập trình cần phải
quan tâm. Làm thế nào để ta có thể truyền dữ liệu cho một chương trình Java. Có hai cách
hiệu quả để thực hiện điều này:
• Thông qua một tài nguyên tuần tự nào đó như file hoặc qua một máy tính khác.
• Thông qua giao diện người máy.
Mục đích của chương này là xem xét cách truyền dữ liệu cho một chương trình thông
qua một máy tính khác hay tập tin.
                
              
                                            
                                
            
                       
            
                 24 trang
24 trang | 
Chia sẻ: thanhle95 | Lượt xem: 801 | Lượt tải: 1 
              
            Bạn đang xem trước 20 trang tài liệu Giáo trình Lập trình mạng với Java - Chương 3: Các luồng vào ra, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
 59
Chương 3 
Các luồng vào ra 
1. Khái niệm về luồng trong Java 
Khi lập bất kỳ chương trình nào trong một ngôn ngữ nào thì vấn đề vào ra dữ liệu giữa 
chương trình và nguồn dữ liệu cũng như đích dữ liệu là vấn đề mà người lập trình cần phải 
quan tâm. Làm thế nào để ta có thể truyền dữ liệu cho một chương trình Java. Có hai cách 
hiệu quả để thực hiện điều này: 
• Thông qua một tài nguyên tuần tự nào đó như file hoặc qua một máy tính khác. 
• Thông qua giao diện người máy. 
Mục đích của chương này là xem xét cách truyền dữ liệu cho một chương trình thông 
qua một máy tính khác hay tập tin. 
1.1. Khái niệm luồng (stream) 
Theo nghĩa đen luồng là một đường ống nước. 
Về mặt thuật ngữ chuyên ngành ta có thể hiểu “Các luồng là các dãy dữ liệu có sắp 
thứ tự”. 
Xét trên quan điểm của chương trình và nguồn dữ liệu (Data Soure) ta có thể phân 
loại luồng thành hai loại: Luồng xuất (output stream) và luồng nhập (input stream). Để trực 
quan hơn chúng ta xem hình vẽ dướ đây: 
Hình 3.1 
Như vậy nếu chúng ta cần lấy dữ liệu từ nguồn vào chương trình thì cần phải sử dụng luồng 
nhập. Ngược lại, nếu ta cần ghi dữ liệu từ chương trình ra nguồn dữ liệu thì ta cần phải sử 
dụng luồng xuất. 
Ta có thể thấy rằng có rất nhiều luồng dữ liệ, chẳng hạn như từ một tệp tin, từ các thiết bị 
xuất và nhập chuẩn, từ liên kết mạng. Như vậy một chương trình có thể truy xuất tới nhiiều 
nguồn dữ liệu. 
Program 
Data Source 
InputStream 
OutputStream 
 60
Hình 3.2 
2. Luồng xuất nhập chuẩn 
• System.out: Luồng xuất chuẩn thường được sử dụng để hiển thị kết quả đầu ra trên 
màn hình. 
• System.in: Luồng nhập chuẩn thường đến từ bàn phím và được sử dụng để hiện các 
ký tự. 
• System.err: Luồng lỗi chuẩn. 
Các luồng trên còn được gọi là các luồng hệ thống. Mặc dù các luồng này rất có ích 
khi lập trình nhưng chúng không đủ mạnh khi giải quyết các vấn đề vào ra quan trọng khác. 
Trong các mục tiếp theo ta sẽ tìm hiểu sâu một số luồng trong gói java.io 
3. Luồnng nhị phân 
3.1. Lớp InputStream 
Lớp trừu tượng InputStream khai báo các phương thức để đọc dữ liệu đầu vào từ một 
nguồn cụ thể. Lớp InputStream là lớp cơ sở của hầu hết các luồng nhập trong gói java.io, và 
nó hỗ trợ các phương thức sau: 
Các phương thức: 
• public InpuStream() 
InputStream chỉ hỗ trợ constructor không tham số. 
• public abstract int read() throws IOException 
Phương thức cơ bản của lớp InputStream là phương thức read(). Phương thức này 
đọc một byte dữ liệu từ luồng nhập và trả về một số kiểu nguyên int có giá trị nằm 
trong khoảng từ 0 đến 255. Giá trị trả về là -1 khi kết thúc luồng. Phương thức read() 
chờ và phong tỏa các đoạn mã sau nó cho tới khi một byte dữ liệu được đọc. Việc 
nhập và xuất diễn ra với tốc độ chậm, vì vậy nếu chương trình của ta thực hiện một 
công việc khác quan trọng thì tốt nhất là đặt các lệnh nhập xuất vào một tuyến đoạn 
riêng của nó. Phương thức read() là phương thức trừu tượng bởi vì các lớp con cần 
thay đổi để thích ích với môi trường cụ thể. 
• public int read(byte[] b) throws IOException 
Phương thức này đọc một dãy các byte dữ liệu liên tục từ một nguồn của luồng nhập 
và lưu vào mảng b. 
• public int read(byte[] b, int offs, int len) throws IOException 
Phương thức này đọc một dãy các byte dữ liệu và lưu vào mảng b, vị trí bắt đầu lưu 
dữ liệu là offs và lưu len byte dữ liệu 
Thiết bị 
Console 
Tệp tin 
Mạng 
InputStream 
OutputStream 
Chương trình 
ứng dụng 
 61
• public int available() throws IOException 
Phương thức này cho biết còn bao nhiêu byte dữ liệu trong luồng. 
• public long skip(long count) throws IOException 
Phương thức skip(long count) bỏ qua long byte dữ liệu 
• public synchronized void mark(int readLimit) 
Phương thức này được sử dụng để dánh dấu vị trí hiện thời trong luồng 
• public void reset() throws IOException 
Phương thức này xác định lại vị trí luồng là vị trí đánh dấu lần gần đây nhất. 
• public boolean markSupported() 
Phương thức này trả về giá trị true nếu luồng này hỗ trợ đánh dấu và false nếu nó 
không hỗ trợ đánh dấu. 
• public void close() throws IOException 
Khi đã làm việc xong với một luồng, ta cần đóng lại luồng đó. Điều này cho phép hệ điều 
hành giải phóng các tài nguyên gắn với luồng. 
3.2. Lớp OutputStream 
Lớp trừu tượng OutputStream khai báo các phương thức để ghi dữ liệu ra luồng. 
Chúng bao gồm các phương thức sau đây: 
• public OuputStream() 
Phương thức OutputStream hỗ trợ constructor không tham số 
• public abstract void write(int b)throws IOException 
Phương thức này ghi một byte không dấu có giá trị trong khoảng từ 0 đến 255. Nếu ta 
truyền vào một số có giá trị lớn hơn 255 hoặc nhỏ hơn 0, nó sẽ thực hiện phép tính 
b =b mod 256 trước khi ghi giá trị vào luồng. 
• public void write(byte[] b)throws IOException 
Phương thức này ghi dữ liệu từ luồng vào toàn bộ mảng b. 
• public void write(byte[] b, int off, int len) throws IOException 
Phương thức này chỉ ghi một đoạn con của mảng dữ liệu bắt đầu từ vị trí offs và tiếp 
tục cho tới khi ghi hết len byte. 
• public void close() 
Phương thức này đóng một luồng. Phương thức này được gọi để giải phóng các tài 
nguyên gắn với luồng. 
• public void flush() 
Các luồng xuất nhập khác được thừa kế từ các luồng trừu tượng InputStream và 
OutputStream. Đối với mỗi kiểu dữ liệu và nguồn dữ liệu chúng ta có thể có các kiểu luồng 
xuất và nhập riêng, chẳng hạn DataInputStream, DataOutputStream, FileInputStream, 
FileOutputStream, Sau đây chúng ta sẽ lần lượt xem xét từng kiểu luồng cụ thể. 
 62
3.3. Các luồng xuất nhập mảng byte 
Để xây dựng một xâu ký tự biểu diễn dữ liệu có thể đọc được hoặc giải mã dữ liệu, 
người ta xem các mảng byte như là nguồn của các luồng nhập hoặc đích của các luồng 
xuất. Các luồng byte cung cấp các khả năng này. 
Hình 3.3 
3.3.1. Luồng nhập mảng byte 
Lớp ByteArrayInputStream sử dụng một mảng byte như là một nguồn dữ liệu đầu vào. 
Nó có hai constructor: 
• public ByteArrayInputStream(byte[] buf) 
Tạo ra một đối tượng ByteArrayInputStream từ một mảng xác định. Mảng đầu vào 
được sử dụng một cách trực tiếp. Khi kết thúc buf nghĩa là kết thúc nhập từ luồng. 
• public ByteArrayInputStream(byte[] buf, int offset, int length) 
Tạo ra một đối tượng ByteArrayInputStream từ một mảng xác định, chỉ sử dụng một 
phần của mảng buf từ buf[offset] đến buff[offset+length-1] hoặc kết thúc mảng. 
ByteArrayInputStream tạo ra một luồng nhập từ một vùng đệm trong bộ nhớ được 
biểu diễn bằng một mảng byte. Lớp này không hỗ trợ bất kỳ phương thức mới nào, nó nạp 
chồng các phương thức read(), skip(), available(), và reset() của lớp cha InputStream. 
Ví dụ: 
Tạo một mảng gồm 100 byte rồi gắn vào mảng này một luồng ByteArrayInputStream 
để lấy dữ liệu ra. 
import java.io.*; 
public class LuongNhapMang 
{ 
 public static void main(String[] args) 
 { 
 byte[] b = new byte[100]; 
 for(byte i=0;i<b.length;i++) b[i]=i; 
 try{ 
 InputStream is = new ByteArrayInputStream(b); 
 for(byte i=0;i<b.length;i++) 
ByteArrayInputStream 
ByteArrayOutputStream 
 63
 System.out.print(is.read()+" "); 
 } 
 catch(IOException e) 
 { 
 System.err.println(e); 
 } 
} 
} 
Kết quả thực hiện chương trình 
C:\MyJava\Baitap>java LuongNhapMang 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 
91 92 93 94 95 96 97 98 99 
Chú ý: Mỗi lần đọc luồng bằng phương thức read(), một byte dữ liệu không còn trong 
luồng, nhưng vẫn tồn tại trong mảng. 
3.3.1. Luồng nhập mảng byte 
ByteArrayOutputStream tạo ra một luồng xuất trên một mảng byte. Nó cũng cung cấp 
các khả năng bổ sung. 
Các constructor: 
• public ByteArrayOutputStream() 
Tạo ra một đối tượng ByteArrayOutputStream với kích thước mặc định 
• public ByteArrayOutputStream(int size) 
Tạo ra một đối tượng ByteArrayOutputStream với kích thước xác định ban đầu. 
Các phương thức mới của lớp ByteArrayOutputStream: 
• public synchronized byte[] toByteArray(): 
 Phương thức này trả về một bản sao dữ liệu của luồng và lưu dữ liệu vào một mảng 
và có thể sửa đổi dữ liệu trong mảng này mà không cần thay đổi các byte của luồng xuất. 
• public size() 
Trả về kích thước hiện thời của vùng đệm 
• public String toString(int hiByte) 
Tạo một đối tượng String mới từ nội dung của luồng xuất mảng byte 
• public String toString() 
Phương thức chuyển đổi một luồng byte thành một đối tượng String 
Ví dụ: 
Viết chương trình tạo lập một luồng xuất mảng (ByteArrayOutputStream) 100 byte. 
Ghi vào luồng xuất mảng 100 phần tử từ 0 đến 99. Đổ dữ liệu từ luồng xuất mảng vào mảng 
b. In dữ liệu từ mảng b ra màn hình. 
import java.io.*; 
class LuongXuatMang 
{ 
 64
 public static void main(String[] args) 
 { 
 try{ 
 //Tao mot luong xuat mang 100 byte 
ByteArrayOutputStream os = new ByteArrayOutputStream(100); 
 //Ghi du lieu vao luong 
 for(byte i=0;i<100;i++) os.write(i); 
 //Doc du lieu tu luong vao mang 
 byte[] b = os.toByteArray(); 
 for(byte i=0;i<100;i++) System.out.print(b[i]+" "); 
 os.close(); 
 } 
 catch(IOException e) 
 { 
 System.err.println(e); 
 } 
 } 
} 
Kết quả thực hiện chương trình: 
C:\MyJava\Baitap>java LuongXuatMang 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 
91 92 93 94 95 96 97 98 99 
3.4. Luồng xuất nhập tập tin 
Phần lớn việc nhập và xuất dữ liệu trong các ứng dụng là đọc và ghi dữ liệu từ các tệp 
tin và ghi vào dữ liệu vào tệp tin. Hai luồng trong java.io thực hiện việc xuất nhập tệp tin là 
FileInputStream và FileOutputStream. Mỗi kiểu luồng có ba constructor. 
• Một constructor nhận một đối tượng String làm tên của tệp tin. 
• Một constructor nhận một đối tượng File để tham chiếu đến tệp tin. 
• Một constructor nhận đối tượng FileDescriptor làm tham số. 
FileDescriptor biểu diễn một giá trị phụ thuộc vào hệ thống mô tả một tệp đang mở. 
Đối với luồng xuất nhập tập tin ta hình dung như sau: chương trình Java là nơi tiêu thụ 
dữ liệu, tập tin là nơi cung cấp dữ liệu. Để đọc dữ liệu từ tập tin vào bộ nhớ ta sử dụng luồng 
nhập tập tin FileInputStream. Để ghi dữ liệu từ bộ nhớ vào tập tin ta sử dụng luồng xuất tập 
tin FileOutputStream. 
 65
Hình 4.5 
Ví dụ 
import java.io.*; 
public class FileIOExam 
{ 
 public static void main(String[] args) 
 { 
 //Tao mot file de ghi 
 try{ 
 OutputStream os = new FileOutputStream(args[0]); 
 String s = "Thu nghiem voi luong xuat nhap tap tin"; 
 for(int i=0;i<s.length();i++) os.write(s.charAt(i)); 
 os.close(); 
 //Mo de doc 
 InputStream is = new FileInputStream(args[0]); 
 int len = is.available(); 
 System.out.println("Luong nhap co "+len+ " bytes"); 
 byte b[] = new byte[len]; 
 int sobyte = is.read(b,0,len); 
 System.out.println(sobyte+ " la so bytes da doc"); 
 System.out.println(new String(b)); 
 is.close(); 
 } 
 catch(IOException e) 
 { 
 System.err.println(e); 
 } 
 } 
} 
Kết quả thực hiện chương trình 
FILE 
FileInputStream 
FileOutputStream 
 66
C:\MyJava\Baitap>java FileIOExam abc.txt 
Luong nhap co 38 bytes 
38 la so bytes da doc 
Thu nghiem voi luong xuat nhap tap tin 
3.5. Truy nhập tệp ngẫu nhiên 
RandomAccessFile cho phép ta truy nhập trực tiếp vào các tệp, nghĩa là có thể đọc, 
ghi các byte ở bất kỳ vị trí nào đó trong tệp. 
Các phương thức tạo luồng truy nhập tệp ngẫu nhiên 
• RandomAccessFile(String name, String mode) throws IOException 
• RandomAccessFile(File file, String mode) throws IOException 
Tệp được xác định bởi tên hoặc đối tượng File. 
Tham số mode cho phép xác định mở file để đọc hay ghi. 
-“r”: Dùng để đọc. 
-“rw”: Dùng để ghi. 
Các phương thức khác 
• long getFilePointer() throws IOException : Trả về vị trí của con trỏ tệp. 
• long length() throws IOException: cho biết số byte hay độ dài của tệp. 
• void seek(long offset) throws IOException: Chuyển con trỏ tệp đi offset vị trí kể từ đầu 
tệp. 
• void close() throws IOException: Khi không cần truy nhập tệp nữa thì đóng lại. 
Ví dụ: 
import java.io.*; 
public class RandomAccessDemo 
{ 
 static String filename="dayso.dat"; 
 final static int INT_SIZE=4; 
 //Tao file de ghi 
 public void createFile() throws IOException 
 { 
 File datFile = new File(filename); 
 RandomAccessFile out_file = new RandomAccessFile(datFile,"rw"); 
 for(int i=0;i<10;i++)out_file.writeInt(i*i); 
 out_file.close(); 
 } 
 //Mo file de doc 
 public void readFile() throws IOException 
 { 
 File datFile = new File(filename); 
 67
 RandomAccessFile inp_file= new RandomAccessFile(datFile,"r"); 
 System.out.println("Cac so doc tu file:"); 
 long len = inp_file.length(); 
 for(int i=INT_SIZE;i<len;i+=2*INT_SIZE) 
 { 
 inp_file.seek(i); 
 System.out.println(inp_file.readInt()); 
 } 
 inp_file.close(); 
 } 
 //Mo file de ghi 
 public void extendFile() throws IOException 
 { 
 RandomAccessFile out_file = new RandomAccessFile(filename,"rw"); 
 for(int i=10;i<20;i++) out_file.writeInt(i*i); 
 out_file.close(); 
 } 
 public static void main(String[] args) 
 { 
 try{ 
 RandomAccessDemo rnd = new RandomAccessDemo(); 
 rnd.createFile(); 
 rnd.readFile(); 
 rnd.extendFile(); 
 rnd.readFile(); 
 } 
 catch(IOException e) 
 { 
 System.err.println(e); 
 } 
 } 
} 
 68
3.5. Luồng PrintStream 
Luồng PrintStream được sử dụng mỗi khi cần sử dụng các phương thức print và 
println trong chương trình. Lớp PrintStream là lớp con của lớp InputStream, vì vậy ta có thể 
sử dụng luồng này để lọc các byte. Nó cung cấp các phương thức print và println cho các 
kiểu dữ liệu sau: 
char int float Object boolean 
char[ ] long double String 
Ngoài ra phương thức println không tham số được sử dụng để kết thúc một dòng. 
 PrintStream hỗ trợ hai constuctor. Constructor thứ nhất nhận tham số là một luồng. 
Constructor thứ hai có thêm tham số điều khiển việc đẩy dữ liệu ra khỏi luồng. 
Ngoài ra còn một số kiểu luồng xuất và nhập khác như DataInputStream, 
DataOutputStream,tùy thuộc vào từng tình huống cụ thể mà chúng ta có những lựa chọn 
cho phù hợp. 
4. Luồng ký tự 
Luồng ký tự cung cấp một cách thức để quản lý việc vào ra với các ký tự. Các luồng này sử 
dụng tập ký tự Unicode và vì thế có thể quốc tế hóa. Trong một số trường hợp làm việc với 
các luồng ký tự hiệu quả hơn luồng byte. 
Các luồng ký tự chuẩn vay mượn từ rất nhiều các lớp luồng hướng byte, bao gồm 
luồng lọc, luồng đệm, và các luồng tệp tin, và tất cả các luồng được dẫn xuất từ các lớp cha 
Reader và Writer. Ngoài ra, có hai lớp đóng vai trò cầu nối giữa các luồng byte và các luồng 
ký tự. Hai lớp này kết hợp các hàm chuyển đổi các ký tự thành các byte và ngược lại theo 
một kiểu mã hóa đã được xác định. Điều này cho phép một nguồn dữ liệu ASCII được 
chuyển đổi dễ dàng thành một luồng ký tự Unicode và tương tự cho dữ liệu Unicode được 
ghi một cách dễ dàng vào một tệp tin theo chuẩn mã hóa cục bộ, cho dù nó là chuẩn 8-bit, 
UTF-8, hoặc 16 bit. 
Hình 4.6 
Hình 4.7 
 4.1. Sự tương ứng giữa luồng byte và luồng ký tự 
Bảng dưới đây chỉ ra sự tương ứng giữa luồng byte và luồng ký tự 
Luồng byte Luồng ký tự 
OuputStream Writer 
InputStream Reader 
FileOutputStream FileWriter 
FileInputStream FileReader 
ByteArrayInputStream CharArrayReader 
InputStream InputStreamReader 72 105 33 8-bit 16-bit “Hi!” 
OutputStream OutputStreamWriter “Hi!” 16-bit 255 254 0 105 0 33 0 
 69
ByteArrayOutputStream CharArrayWriter 
- StringWriter 
StringBufferedInputStream StringReader 
PipedOuputStream PipedWriter 
PipedInputStream PipedReader 
FilterOutputStream FilterWriter 
FilterInputStream FilterReader 
BufferedOuputStream BufferedWriter 
BufferedInputStream BufferedReader 
PushbackInputStream PushbackReader 
LineNumberInputStream LineNumberReader 
PrintStream PrintWriter 
DataOutputStream - 
DataInputStream - 
ObjectInputStream - 
ObjectOuputStream - 
SequenceInputStream - 
- OuputStreamWriter 
- OutputStreamReader 
Bảng 3.1 
4.2. Mã hóa ký tự 
Khi tạo cầu nối giữa một luồng ký tự và một luồng byte, cần thiết phải xác định cách 
mã hóa được sử dụng bởi các luồng byte; nghĩa là, các ký tự được biểu diễn bởi từng byte 
hoặc từng nhóm các byte. Tên của cách mã hóa các byte được đặc tả bởi một xâu ký tự 
được truyền cho constructor tạo cầu nối OuputStreamReader và InputStreamReader. 
Mã hóa Char Bytes 
US-ASCII ! 33 
IBM-EBCDIC ! 90 
ISO Latin 
ISO Latin 2 
UTF-8 
Bảng 3.2 
 70
Các phương thức hướng ký tự của các luồng byte tương đương với latin 1, còn được 
biết đến như là ISO Latin 1 hoặc ISO 8859-1; nghĩa là cách mã hóa 8-bit tương ứng với 256 
ký tự Unicode đầu tiên. Các tên kiểu mã hóa ký tự thường là phân biệt chữ hoa và chữ 
thường. 
4.3 Lớp Writer 
Writer là lớp cha của tất cả các luồng xuất ký tự. Nó cung cấp các phương thức tương 
tự như luồng OuputStream, nhưng chủ yếu là ghi các ký tự. 
4.3.1. Các constructor 
Có hai constructor được cung cấp bởi lớp này. Các constructor này là protected. Ta 
không thể tạo các đối tượng của lớp Writer nhưng ta có thể tạo ra các đối tượng thuộc lớp 
con của lớp này. 
• protected Writer() 
• protected Writer(Object obj) 
4.3.1. Các phương thức 
Lớp Writer cung cấp các phương thức để ghi các ký tự, từ một mảng, hoặc một phần 
của xâu ký tự. 
• void write(int c) throws IOException 
Phương thức này ghi ký tự c vào kênh truyền tin được biểu diễn bởi luồng này. 
• void write(char cbuff[]) throws IOException 
Phương thức này ghi mảng ký tự vào luồng 
• abstract void write(char cbuff[], int off, int len) throws IOException 
Phương thức này ghi len ký tự từ mảng cbuff ra luồng gắn với mảng, bắt đầu từ vị trí 
off. Đây là phương thức trừu tượng bởi vì nó phải được cài đặt bởi một lớp con gắn với 
kênh truyền tin thực sự, như tệp tin hoặc một luồng khác. 
• void write(String str) throws IOException. 
Phương thức này ghi một xâu ký tự str ra luồng. 
4.4. Lớp Reader 
Reader là lớp cha của tất cả các luồng nhập ký tự. Nó cung cấp các phương thức 
tương tự như luồng InputStream, nhưng chủ yếu phục vụ cho việc đọc các ký tự. 
• protetected Reader() 
• protected Reader(Object lock) 
4.4.1. Các phương thức 
Các phương thức của lớp Reader giống như các phương thức của lớp InputStream 
ngoại trừ phương thức available() được thay thế bởi phương thức ready(). 
• int read() throws IOException 
Phương thức này đọc một ký tự từ kênh truyền tin được biểu diễn bởi luồng này và trả 
về ký tự, hoặc giá trị -1 nếu kết thúc luồng. 
int read(char cbuff[]) throws IOException 
Phương thức này đọc các ký tự vào mảng cbuff 
4.5. Lớp OutputStreamWriter 
Lớp này cung cấp một cầu nối Writer hướng ký tự với một luồng OutputStream. Các 
ký tự được ghi vào lớp Writer được chuyển thành các byte tương ứng với một kiểu mã hóa 
được xác định trong constructor và sau đó được ghi vào luồng OutputStream gắn với nó. 
Lớp này cung cấp khả năng đệm dữ liệu cho các byte để ghi vào luồng. 
 71
Các constructor 
• public OutputStreamWriter(OutputStream out) 
• public OutputStreamWriter(OutputStream out, String encoding) 
• String getEncoding() 
Phương thức này trả về tên cách mã hóa các byte được sử dụng để chuyển đổi các 
ký tự thành các byte. 
4.6. Lớp InputStreamReader 
Lớp này biểu diễn một cầu nối hướng ký tự của một luồng nhập InputStream. Các 
byte được đọc từ luồng nhập và được chuyển thành các ký tự tương ứng với kiểu mã hóa 
được xác định trong constructor. 
• InputStreamReader(InputStream in) 
• InputStreamReader(InputStream in, String enc) 
• String getEncoding() 
Phương thức này trả về tên của cách mã hóa byte được sử dụng bởi luồng