Lập trình cơ bản với Java Tác giả: PGS.TS Trần Văn Lăng, Ths. Chu Nguyên Hoàng Minh Giúp các bạn tiếp cần gần hơn với bộ môn lập trình để trở thành một Lập trình viên suất sắc Lập trình cơ bản với Java Tác giả: PGS.TS Trần Văn Lăng, Ths. Chu Nguyên Hoàng Minh Giúp các bạn tiếp cần gần hơn với bộ môn lập trình để trở thành một Lập trình viên suất sắc
Trang 1Sau khi học xong bài này sinh viên sẽ nắm được:
Thư viện các lớp về luồng trong java: luồng byte, luồng ký tự
Xuất nhập Console dùng luồng byte, luồng ký tự
Xuất nhập files dùng luồng ký tự và luồng byte
Vấn đề xử lý files truy cập ngẫu nhiên dùng lớp RandomAccessFile
Xử lý file và thư mục dùng lớp File
Số tiết lên lớp: 8
Bảng phân chia thời lượng:
03 ất nhậ file ng l ồng ý tự và l ồng te 3
Trọng tâm bài giảng:
Thư viện các lớp về luồng trong java: luồng byte, luồng ký tự
Xuất nhập Console dùng luồng byte, luồng ký tự
Xuất nhập files dùng luồng ký tự và luồng byte
Vấn đề xử lý files truy cập ngẫu nhiên dùng lớp RandomAccessFile
Xử lý file và thư mục dùng lớp File
Trang 2212
5.1 Mở đầu
Việ lư trữ dữ liệu trong các biến hương trình, mảng có tính chất tạm thời và
dữ liệu sẽ mất đi hi iến ra khỏi tầm ảnh hưởng của nó hoặ hi hương trình ết thúc ile giú h hương trình ó thể lư trữ một lượng lớn dữ liệ , ũng như ó thể lư trữ dữ liệu trong một thời gian dài ngay cả hi hương trình ết thú Tr ng hương nà chúng ta sẽ tìm hiểu làm thế nà hương trình java ó thể tạ , đọc, ghi và xử lý các files tuần tự và các file truy cập ngẫu nhiên thông qua một số ví dụ minh họa
Xử lý files là một vấn đề hết sứ ơ ản, quan trọng mà bất kỳ một ngôn ngữ lập trình nà ũng hải hỗ trợ những thư viện, hàm để xử lý một số tha t ơ ản nhất đối với kiểu dữ liệu file
Xử lý files là một phần của công việc xử lý các luồng, giúp cho một hương trình có thể đọc, ghi dữ liệu trong bộ nhớ, trên file và tra đổ dữ liệu thông qua các kết nối trên mạng
Chương nà ẽ cung cấp cho chúng ta những kiến thứ ơ ản về luồng (streams) và files:
Thư viện các lớp về luồng trong java: luồng byte, luồng ký tự
Xuất nhập Console dùng luồng byte, luồng ký tự
Xuất nhập files dùng luồng ký tự và luồng byte
Vấn đề xử lý files truy cập ngẫu nhiên dùng lớp RandomAccessFile
Xử lý file và thư mục dùng lớp File
5.2 Luồng (Streams) ([2] trang 551)
5.2.1 Khái niệm luồng
Tất cả những hoạt động nhập/xuất dữ liệu (nhập dữ liệu từ bàn phím, lấy dữ liệu từ mạng về, ghi dữ liệ ra đĩa, x ất dữ liệ ra màn hình, m in, …) đề được quy về một khái niệm gọi là luồng (stream) Luồng là nơi ó thể “ ản xuất” và “tiê thụ” thông tin Luồng thường được hệ thống xuất nhập trong java gắn kết với một thiết bị vật lý Tất cả các luồng đều có chung một nguyên tắc hoạt động ngay cả hi húng được gắn kết với các thiết bị vật lý khác nhau Vì vậy cùng một lớ , hương thức xuất nhập có thể dùng chung cho các thiết bị vật lý khác nhau Chẳng hạn cùng một hương thức có thể ng để
Trang 35.2.2 Luồng byte (Byte Streams)
Các luồng te đượ định nghĩa ng hai lớp phân cấp Mức trên cùng là hai lớp trừ tượng In tStream và O t tStream In tStream định nghĩa những đặ điểm chung cho những luồng nhập byte OutputStream mô tả cách xử lý của các luồng xuất byte Các lớp con dẫn xuất từ hai lớp InputStream và OutputStream sẽ hỗ trợ chi tiết tương ứng với việ đọc ghi dữ liệu trên những thiết bị h nha Đừng choáng ngợp với hàng loạt rất nhiều các lớ h nha Đừng quá lo lắng, mỗi khi bạn nắm vững, sử dụng thành thạo một luồng te nà đó thì ạn dễ dàng làm việc với những luồng còn lại
BufferedInputStream Buffered input stream
BufferedOutputStream Buffered output stream
Luồng xuất có những phương thức ghi những kiểu dữ liệu chuẩn trong java
Trang 4FilterInputStream Hiện thực lớp trừu tượng InputStream
FilterOutputStream Hiện thực lớp trừu tượng OutputStream
PipedOutputStream
Luồng nhập byte kiểu ống (piped) thường phải được gắn với một luồng nhập kiểu ống để tạo nên một kết nối trao đổi dữ liệu kiểu ống
PrintStream Luồng xuất có chứa hương thức print()
và println() PushbackInputStream
Là một luồng nhập kiểu Byte mà hỗ trợ thao tác trả lại (push back) và phục hồi tha t đọc một byte (unread)
RandomAccessFile Hỗ trợ tha t đọ , ghi đối với file
truy cập ngẫu nhiên
SequenceInputStream Là một luồng nhậ được tạo nên bằng
cách nối kết logic các luồng nhập khác
5.2.3 Luồng ký tự( Character Streams)
Các luồng ký tự đượ định nghĩa ng hai lớp phân cấp Mức trên cùng là hai lớp trừ tượng Reader và Writer Lớp Reader dùng cho việc nhập dữ liệu của luồng, lớp
Trang 5BufferedWriter Luồng xuất ký tự ghi dữ liệu tới một vùngđệm
CharArrayReader Luồng nhập đọc dữ liệu từ một mảng ký tự
CharArrayWriter Luồng xuất ghi dữ liệu tời một mảng ký tự
FileReader Luồng nhập ký tự đọc dữ liệu từ file
FileWriter Luồng xuất ký tự ghi dữ liệ đến file
FilterReader Lớ đọc dữ liệu trung gian (lớp trừ tượng)
FilterWriter Lớp xuất trung gian trừ tượng
InputStreamReader Luồng nhập chuyển bytes thành các ký tự
LineNumberReader Luồng nhậ đếm dòng
OutputStreamWriter Luồng xuất chuyển những ký tự thành các
bytes
PipedReader Luồng đọc dữ liệu bằng ơ hế đường ống
PipedWriter Luồng ghi dữ liệu bằng ơ hế đường ống
PrintWriter Luồng ghi văn ản ra thiết bị xuất (chứa
hương thức print() và println() )
Trang 6216
PushbackReader Luồng nhậ h hé đọc và khôi phục lại dữ
liệu
Reader Lớp nhập dữ liệu trừ tượng
StringReader Luồng nhậ đọc dữ liệu từ chuỗi
StringWriter Luồng xuất ghi dữ liệu ra chuỗi
Writer Lớp ghi dữ liệu trừ tượng
5.2.4 Những luồn được định n h trước (The PredefinedStreams)
Tất cả hương trình viết bằng java luôn tự động import gói java.lang Gói này có định nghĩa lớp System, bao gồm một số đặ điểm của môi trường run-time, nó có ba biến luồng đượ định nghĩa trước là in, out và err, các biến nà là fiel được khai báo static trong lớp System
System.out: luồng xuất chuẩn, mặ định là console
System.out là một đối tượng kiểu PrintStream
System.in: luồng nhập chuẩn, mặ định là bàn phím
System.in là một đối tượng kiểu InputStream
System.err: luồng lỗi chuẩn, mặ định ũng là n le
S tem t ũng là một đối tượng kiểu PrintStream giống System.out
5.3 Sử dụng luồng Byte
Như húng ta đã iết hai lớp InputStream và OutputStream là hai siêu lớ ( ha) đối với tất cả những lớp luồng xuất nhập kiểu byte Những hương thức trong hai siêu lớp này ném ra các lỗi kiểu IOException Những hương thứ định nghĩa tr ng hai iê lớp này là có thể dùng trong các lớp con của chúng Vì vậy tậ hương thứ đó là tập tối tiểu các chứ năng nhập xuất mà những luồng nhập xuất kiểu byte có thể sử dụng
Những hương thứ định nghĩa tr ng lớp
InputStream và OutputStream
Trang 7void mark(int numBytes) Đ nh dấu ở vị trí hiện tại trong luồng
nhập
boolean markSupported( ) Kiểm tra xem luồng nhập có hỗ trợ
phương thức mark() và reset() không
int read( ) Đọc byte tiếp theo từ luồng nhập
int read(byte buffer[ ])
Đọ ffer.length te và lư và tr ng vùng nhớ buffer Kết quả trả về số bytes thật sự đọ được
int read(byte buffer[ ], int offset, int numBytes)
Đọc numBytes bytes bắt đầu từ địa chỉ
ff et và lư và tr ng v ng nhớ buffer Kết quả trả về số bytes thật sự đọ được
void reset( ) Nhảy con trỏ đến vị trí đượ x định
bởi việc gọi hàm mark() lần sau cùng
long skip(long numBytes) Nhảy qua numBytes dữ liệu từ luồng
void flush( ) Ép dữ liệu từ bộ đệm phải ghi ngay
xuống luồng (nếu có)
void write(int b) Ghi byte dữ liệu chỉ định xuống luồng
void write(byte buffer[ ]) Ghi buffer.length bytes dữ liệu từ mảng
chỉ định xuống luồng
Trang 85.3.1 Đọc dữ liệu từ Console
Trướ đâ , hi Java mới ra đời để thực hiện việc nhập dữ liệu từ C n le người ta chỉ dùng luồng nhập byte Về sau thì chúng ta có thể dùng cả luồng byte và luồng ký tự, nhưng tr ng một số trường hợp thực tế để đọc dữ liệu từ C n le người ta thích dùng luồng kiểu ký tự hơn, vì lý đơn giản và dễ bả trì hương trình Ở đâ với mụ đí h minh họa chúng ta dùng luồng byte thực hiện việc nhập xuất Console
Ví dụ: hương trình minh họa việ đọc một mảng bytes từ System.in
import java.io.*;
class ReadBytes{
public static void main(String args[])throws IOException{
byte data[] = new byte[100];
System.out.print("Enter some characters.");
Kết quả thực thi chươn trình:
5.3.2 Xuất dữ liệu ra Console
Tương tự như nhập dữ liệu từ Console, với phiên bản đầu tiên của java để xuất dữ liệu ra Console tả chỉ có thể sử dụng luồng byte Kể từ phiên bản 1.1 (có thêm luồng ký
Trang 9219
tự), để xuất dữ liệu ra Console có thể sử dụng cả luồng ký tự và luồng byte Tuy nhiên,
h đến na để xuất dữ liệ ra C n le thường người ta vẫn dùng luồng byte
Chúng ta đã h q en th ộc với hương thứ rint() và rintln(), ng để xuất dữ liệu ra Console Bên cạnh đ1 húng ta ũng ó thể ng hương thức write()
Ví dụ: minh họa sử dụng hương thứ S tem t.write() để xuất ký tự ‘ ’ ra C n le
Kết quả thực thi chươn trình:
5.3.3 Đọc và ghi file dùng luồng Byte
Tạo một luồng Byte gắn với file chỉ định dùng FileInputStream và ileO t tStream Để mở một file, đơn giản chỉ cần tạo một đối tượng của những lớp này, tên file cần mở là thông số trong constructor Khi file mở, việ đọc và ghi dữ liệu trên file được thực hiện một h ình thường thông q a hương thức cung cấp trong luồng
5.3.3.1 Đọc dữ liệu từ file
Mở một file để đọc dữ liệu FileInputStream(String fileName) throws FileNotFoundException
Nếu file không tồn tại: thì ném ra FileNotFoundException
Đọc dữ liệ : ng hương thức read()
int read( ) throws IOException: đọc từng byte từ file và trả về giá trị của byte
đọ được Trả về -1 khi hết file, và ném ra IOException khi có lỗi đọc
Trang 10220
Đóng file: ng hương thức close()
void close( ) throws IOException: sau khi làm việc xong cần đóng file để giải
phóng tài nguyên hệ thống đã ấp phát cho file
i = fin.read();
if(i != -1) System.out.print((char) i);
} while(i != -1);
fin.close();
}
Trang 11221
}
5.3.3.2 Ghi dữ liệu xuống file
Mở một file để ghi dữ liệu FileOutputStream(String fileName) throws FileNotFoundException
Nếu file không tạ được: thì ném ra nFileNotFoundException
Ghi dữ liệu xuống: ng hương thức write()
void write(int byteval) throws IOException: ghi một te x định bởi tham số byteval xuống file, và ném ra IOException khi có lỗi ghi Đóng file: ng hương thức close()
void close( ) throws IOException: sau khi làm việc xong cần đóng file để giải phóng tài nguyên hệ thống đã ấp phát cho file
Ví dụ: copy nội dung một file text đến một file text khác
/* Copy nội dung của một file text*/
Trang 12System.out.println("Usage: CopyFile From To");
Kết quả thự thi hương trình: hương trình ẽ copy nội dung của file D:\source.txt
và ghi vào một file mới D:\dest.txt
5.3.4 Đọc và ghi dữ liệu nhị phân
Phần trên húng ta đã đọc và ghi các bytes dữ liệu là các ký tự mã ASCII Để đọc và ghi những giá trị nhị phân của các kiểu dữ liệu trong java, chúng ta sử dụng DataInputStream và DataOutputStream
Trang 13223
DataOutputStream: hiện thực interface DataOuput Interface DataOutput có các hương thức cho phép ghi tất cả những kiểu dữ liệ ơ ở của java đến luồng (the định dạng nhị phân)
void writeBoolean (boolean val)
Ghi xuống luồng một giátrị boolean được xác định bởi val
void writeByte (int val)
Ghi xuống luồng một byte được xác định bởi val
void writeChar (int val)
Ghi xuống luồng một Char được xác định bởi val
void writeDouble (double val)
Ghi xuống luồng một giátrị Double được xác định bởi val
void writeFloat (float
Contructor: DataOutputStream(OutputStream outputStream)
OutputStream: là luồng xuất dữ liệ Để ghi dữ liệ ra file thì đối tượng outputStream có
thể là FileOutputStream
DataInputStream: hiện thự interfa e DataIn t Interfa e DataIn t ó hương
thứ h hé đọc tất cả những kiểu dữ liệ ơ ở của java (the định dạng nhị phân)
boolean readBoolean( ) Đọc một giá trị boolean
double readDouble( ) Đọc một giá trị Double
float readFloat( ) Đọc một giá trị float
Long readLong( ) Đọc một giá trị long
short readShort( ) Đọc một giá trị short
Contructor: DataInputStream(InputStream inputStream)
Trang 14224
InputStream: là luồng nhập dữ liệ Để đọ dữ liệu từ file thì đối tượng InputStream có
thể là FileInputStream
Ví dụ: ng DataO t tStream và DataIn tStream để ghi và đọc những kiểu dữ liệu
khác nhau trên file
Trang 15225
System.out.println("Write error.");
} dataOut.close();
}
}
Kết quả thực thi chươn trình:
Dữ liệu ghi xuống file D:\\testdata
Trang 16226
Kết quả đọc và xuất ra Console:
5.4 File truy cập ngẫu nhiên (Random Access Files) ([2] trang 566)
Bên cạnh việc xử lý xuất nhập trên file theo kiểu tuần tự thông qua các luồng, java ũng hỗ trợ truy cập ngẫu nhiên nội dung của một file nà đó ng Ran mA e ile RandomAccessFile không dẫn xuất từ InputStream hay OutputStream mà nó hiện thực các interface DataInput, DataO t t ( ó định nghĩa hương thứ I/O ơ ản) RandomAccessFile hỗ trợ vấn đề định vị con trỏ file bên trong một file ng hương thức seek(long newPos)
Ví dụ: minh họa việc truy cập ngẫ nhiên trên file Chương trình ghi 6 ố kiểu double
xuống file, rồi đọc lên theo thứ tự ngẫu nhiên
Trang 17227
return ; }
// Write values to the file
for(int i=0; i < data.length; i++){
try{
// Now, read back specific values
raf.seek(0); // seek to first double d = raf.readDouble();
System.out.println("First value is " + d);
raf.seek(8); // seek to second double d = raf.readDouble();
System.out.println("Second value is " + d); raf.seek(8 * 3); // seek to fourth double
d = raf.readDouble();
System.out.println("Fourth value is " + d);
System.out.println();
// Now, read every other value
System.out.println("Here is every other value: "); for(int i=0; i < data.length; i+=2){
raf.seek(8 * i); // seek to ith double
d = raf.readDouble();
System.out.print(d + " ");
Trang 18228
} System.out.println("\n");
}catch(IOException exc){
System.out.println("Error seeking or reading.");
} raf.close();
Những hương thứ định nghĩa tr ng lớp trừ tượng Reader và Writer
Reader
abstract void close( ) Đóng luồng
void mark(int numChars) Đ nh dấu vị trí hiện tại trên luồng
boolean markSupported( ) Kiểm tra xem luồng có hỗ trợ thao tác đánh dấu
mark() không?
Trang 19229
int read(char buffer[ ]) Đọc buffer.length ký tự cho vào buffer
abstract int read(char buffer[ ], int
offset, int numChars)
Đọc numChars ký tự cho vào vùng đệm buffer tại
vị trí buffer[offset]
boolean ready( ) Kiểm tra xem luồng có đọc được không?
void reset( ) Dời con trỏ nhập đến vị trí đánh dấu trước đó
long skip(long numChars) Bỏ qua numChars của luồng nhập
Writer
abstract void close( ) Đóng luồng xuất Có lỗi ném ra IOException
abstract void flush( ) Dọn dẹp luồng (buffer xuất)
void write(int ch) Ghi một ký tự
void write(byte buffer[ ]) Ghi một mảng các ký tự
abstract void write(char
buffer[ ], int offset, int numChars) Ghi một phần của mảng ký tự
void write(String str) Ghi một chuỗi
void write(String str, int offset, int
5.5.1 Nhập Console dùng luồng ký tự
Thường thì việc nhập dữ liệu từ Console dùng luồng ký tự thì thuận lợi hơn ng luồng byte Lớp tốt nhất để đọc dữ liệu nhập từ Console là lớp BufferedReader Tuy nhiên chúng ta không thể xây dựng một lớp BufferedReader trực tiếp từ S tem.in Tha và đó chúng ta phải chuyển nó thành một luồng ký tự Để làm điều này chúng ta dùng InputStreamReader chuyển bytes thành ký tự
Để ó được một đối tượng InputStreamReader gắn với System.in ta dùng constructor của InputStreamReader
InputStreamReader(InputStream inputStream)
Tiế the ng đối tượng In tStreamRea er đã tạ ra để tạo ra một BufferedReader dùng constructor BufferedReader
BufferedReader(Reader inputReader)
Ví dụ: Tạo một BufferedReader gắn với Keyboard
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));