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

pdf18 trang | Chia sẻ: candy98 | Lượt xem: 509 | Lượt tải: 0download
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.