Bài giảng Lập trình hướng đối tượng - Bài 8: Luồng vào ra - Lê Hồng Phương
● Tổng quan về luồng vào ra ● Các kiểu luồng vào ra: – Luồng byte – Luồng kí tự – Luồng có đệm – Luồng dữ liệu – Luồng đối tượng
Bạn đang xem nội dung tài liệu Bài giảng Lập trình hướng đối tượng - Bài 8: Luồng vào ra - Lê Hồng Phương, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Bài 8: Luồng vào ra
Lê Hồng Phương
phuonglh@gmail.com
Khoa Toán-Cơ-Tin học
Trường Đại học Khoa học Tự nhiên Hà Nội
2012-2013 Object-Oriented Programming: I/O Streams 2
Nội dung
● Tổng quan về luồng vào ra
● Các kiểu luồng vào ra:
– Luồng byte
– Luồng kí tự
– Luồng có đệm
– Luồng dữ liệu
– Luồng đối tượng
2012-2013 Object-Oriented Programming: I/O Streams 3
Luồng vào ra
● Luồng vào ra (input/output streams – IO streams)
– Biểu diễn một nguồn vào và một đích ra
● Có nhiều kiểu nguồn và đích:
– tệp trên đĩa, thiết bị, chương trình, bộ nhớ
● Có nhiều kiểu dữ liệu khác nhau:
– các bytes
– các kiểu dữ liệu đơn giản
– các đối tượng
2012-2013 Object-Oriented Programming: I/O Streams 4
Luồng vào ra
● Định nghĩa tổng quát: mỗi luồng là một chuỗi dữ liệu.
● Mỗi chương trình thường sử dụng:
– Một luồng vào để đọc dữ liệu từ một nguồn, mỗi
lần đọc một đơn vị dữ liệu.
– Một luồng ra để ghi dữ liệu ra một đích, mỗi lần
ghi một đơn vị dữ liệu.
Data source 010111000111 Program
stream
2012-2013 Object-Oriented Programming: I/O Streams 5
Luồng vào ra
● Các chương trình sử dụng luồng byte để đọc/ghi các
byte (8 bits).
● Trong Java, có nhiều lớp luồng byte. Các lớp này đều
phái sinh từ hai lớp:
– InputStream
– OutputStream
● Khi đọc/ghi dữ liệu byte từ/vào tệp, ta sử dụng
– FileInputStream
– FileOutputStream
2012-2013 Object-Oriented Programming: I/O Streams 6
Luồng byte
● Viết chương trình sao chép một tệp, mô phỏng lệnh
– cp input.txt output.txt (Unix, Linux)
– copy input.txt output.txt (MS Windows)
● Sử dụng hai luồng byte gắn với hai tệp:
– Một luồng để đọc tệp input.txt
– Một luồng để ghi tệp output.txt
● Vòng lặp: mỗi lần đọc một byte của tệp input.txt và ghi
nó vào tệp output.txt. Khi hết tệp thì hàm đọc trả về -1.
2012-2013 Object-Oriented Programming: I/O Streams 7
Luồng byte
public class CopyBytes {
public static void main(String[] args) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream("input.txt");
out = new FileOutputStream("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
}
}
Tại sao không có
các khối catch?
Luôn phải đóng mọi luồng
dữ liệu khi sử dụng xong.
2012-2013 Object-Oriented Programming: I/O Streams 8
Luồng byte
● Tuy nhiên, luồng byte biểu diễn các thao tác vào/ra
mức thấp, ta nên tránh sử dụng trực tiếp các
luồng này.
● Vì các tệp input.txt, output.txt chứa các dữ liệu dạng
kí tự, cách tốt nhất là sử dụng các luồng kí tự.
● Nếu không nên dùng trực tiếp, tại sao lại giới thiệu
luồng byte?
– Vì luồng byte là cơ sở để xây dựng các kiểu luồng
khác.
2012-2013 Object-Oriented Programming: I/O Streams 9
Luồng kí tự
● Nền tảng Java lưu các giá trị kí tự sử dụng chuẩn
Unicode.
● Mọi lớp biểu diễn luồng kí tự đều phái sinh từ hai lớp
Reader và Writer.
● Khi đọc/ghi các tệp văn bản (luồng kí tự trong tệp), ta
sử dụng các lớp
– FileReader
– FileWriter
2012-2013 Object-Oriented Programming: I/O Streams 10
Luồng kí tự
public class CopyCharacters {
public static void main(String[] args) throws IOException {
Reader in = null;
Writer out = null;
try {
in = new FileReader("input.txt");
out = new FileWriter("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
}
}
2012-2013 Object-Oriented Programming: I/O Streams 11
Luồng có đệm
● Luồng không đệm:
– Mỗi lệnh đọc, ghi được thực hiện trực tiếp bởi hệ điều
hành.
– Chương trình kém hiệu quả, do mỗi lệnh đều đòi hỏi
truy xuất ổ đĩa, truyền dữ liệu qua mạng hoặc các thao
tác tốn kém khác.
● Luồng có đệm hiệu quả hơn nhiều:
– Đọc/ghi dữ liệu từ/vào một vùng nhớ (gọi là bộ đệm)
– Khi nào bộ đệm đầy thì mới gọi các lệnh đọc/ghi của hệ
điều hành
2012-2013 Object-Oriented Programming: I/O Streams 12
Luồng có đệm
● Các lớp hỗ trợ luồng có đệm:
– BufferedInputStream, BufferedOutputStream
– BufferedReader, BufferedWriter
● Kích hoạt việc đọc/ghi bộ đệm khi bộ đệm chưa đầy:
– Gọi phương thức flush()
● Để chuyển một luồng không đệm thành một luồng có
đệm, ta tạo một luồng có đệm (tương ứng):
BufferedReader bufferedReader = new
BufferedReader(new FileReader("input.txt"));
BufferedWriter bufferedWriter = new
BufferedWriter(new FileWriter("output.txt"));
2012-2013 Object-Oriented Programming: I/O Streams 13
Luồng dữ liệu
● Luồng dữ liệu hỗ trợ việc đọc, ghi các giá trị thuộc
các kiểu dữ liệu cơ sở:
– boolean, char, byte, short, int, long, float, double
– String
● Mọi luồng dữ liệu cài đặt một trong hai giao diện sau:
– DataInput, DataOutput
● Hai cài đặt được sử dụng nhiều là
– DataInputStream, DataOutputStream
2012-2013 Object-Oriented Programming: I/O Streams 14
Luồng dữ liệu
● Ví dụ, giả sử ta có 3 biến price, unit và desc lần lượt
chứa các giá trị thuộc các kiểu double, int và String.
● Ghi các giá trị vào tệp:
DataOutputStream out;
try {
out = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream("dataFile.dat")));
out.writeDouble(price);
out.writeInt(unit);
out.writeUTF(desc);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Gọi các phương
thức tương ứng của out
Sử dụng luồng có đệm
để ghi vào tệp dataFile.dat
2012-2013 Object-Oriented Programming: I/O Streams 15
Luồng dữ liệu
● Đọc dữ liệu từ tệp và gán giá trị cho các biến tương
ứng:
DataInputStream in;
try {
in = new DataInputStream(new BufferedInputStream(
new FileInputStream("dataFile.dat")));
double price = in.readDouble();
int unit = in.readInt();
String desc = in.readUTF();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Gọi các phương
thức tương ứng của in
2012-2013 Object-Oriented Programming: I/O Streams 16
Luồng đối tượng
● Luồng đối tượng hỗ trợ việc đọc, ghi các đối tượng.
● Nếu đối tượng thuộc một lớp cài đặt giao diện
Serializable thì ta có thể sử dụng luồng đối tượng để
đọc, ghi đối tượng đó.
● Hai lớp hỗ trợ luồng đối tượng:
– ObjectInputStream, ObjectOutputStream
● Hai lớp này tương ứng cài đặt các giao diện
– ObjectInput và ObjectOutput
2012-2013 Object-Oriented Programming: I/O Streams 17
Luồng đối tượng
● ObjectInput và ObjectOutput tương ứng là các giao diện
con của các giao diện DataInput và DataOutput.
● Chính vì vậy, mọi phương thức vào, ra đối với các kiểu
dữ liệu cơ sở do DataInput, DataOutput hỗ trợ đều được
cài đặt trong ObjectInput, ObjectOutput.
ObjectOutput oo = null;
try {
oo = new ObjectOutputStream(new BufferedOutputStream(
new FileOutputStream("dates.dat")));
oo.writeObject(Calendar.getInstance());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
2012-2013 Object-Oriented Programming: I/O Streams 18
Luồng đối tượng
ObjectInput oi = null;
try {
oi = new ObjectInputStream(new BufferedInputStream(
new FileInputStream("dates.dat")));
Calendar date = (Calendar)oi.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Phương thức readObject() luôn
trả về kiểu Object nên ta phải
ép thành kiểu thích hợp.