để xây dựng những lớp con cháu làm nhiệm vụ đọc và ghi từng byte lên tệp. Các lớp con cài đặt các hàm hoặc được viết đè để:
1. Đọc từng byte từ tệp:
int read() throws IOException
int read(byte[] b) throws IOException
int read(byte[] b, int off, int len) throws IOException
Đọc từng byte, nhưng cho lại giá trị kiểu int. Các byte đọc được sẽ được gán vào 8 bit thấp của kiểu int, những bit còn lại được gán trị 0. Các hàm read() sẽ nhận -1, khi đọc đến cuối tệp. Hàm read(byte[] b) đọc các byte vào mảng b, hàm read(byte[] b, int off, int len) đọc len byte vào mảng b kể từ vị trí tương đối off.
2. Ghi từng byte vào tệp:
void write(int b) throws IOException void write(byte[] b) throws IOException
void write(byte[] b, int off, int len) throws IOException
Hàm đầu tiên ghi giá trị kiểu int và những giá trị kiểu int đó được làm tròn, lấy 8 bit thấp (1 byte) để ghi lên tệp. Hàm write(byte[] b)ghi mảng các byte b, hàm write(byte[] b, int off, int len) ghi mảng b gồm len byte kể từ vị trí off.
3. Đóng tệp:
void close() throws IOException void flush() throws IOException
Hàm close() được sử dụng để đóng tệp. Khi đóng tệp thì các dữ liệu ở buffer tương ứng sẽ được tự động đưa vào tệp, hoặc có thể gọi cụ thể hàm flush() để thực hiện công việc đó.
Lưu ý: Khi xử lý với tệp xong thì phải đóng tệp để khỏi mất dữ liệu và đảm bảo cho hệ thống hoạt động bình thường.
Hình H8-1 Các lớp xử lý tệp theo các byte.
Bảng B8.1 mô tả các lớp đối tượng xử lý xử lý các chức năng đọc dữ liệu từ tệp vào chương trình ứng dụng và bảng B8.2 mô tả các lớp ghi dữ liệu lên tệp.
Bảng B8.2 Các lớp ghi dữ liệu lên tệp
Các lớp xử lý tệp
Các lớp FileInputStream, FileOutputStream định nghĩa các luồng của các byte vào/ra cho các tệp. Chúng có các toán tử tạo lập như sau:
FileInputStream(String name) throws FileNotFoundedException FileInputStream(File file) throws FileNotFoundedException FileInputStream(FileDescriptor fdObj)
Tạo ra một tệp có tên name, một đối tượng tệp file hoặc đối tượng fdObj của FileDescriptor đọc từng byte. Nếu tệp đó không có trên đĩa thì cho qua ngoại lệ FileNotFoundedException để sau đó có thể đón nhận và xử lý theo từng ngữ cảnh ứng dụng.
FileOutputStream(String name) throws FileNotFoundedException FileOutputStream(String name, boolean append) throws
FileNotFoundedException
FileOutputStream(File file) throws IOException FileOutputStream(FileDescriptor fdObj)
Tạo ra một tệp có tên name, một đối tượng tệp file hoặc đối tượng fdObj của FileDescriptor ghi từng byte. Nếu tệp đó không có trên đĩa thì tạo ra tệp mới ở thư mục hiện thời.
Ví dụ 8.2 Viết một chương trình CopyFile để sao một tệp sang tệp khác được thực hiện theo lệnh dạng:
java CopyFile <Tep_cu> <Tep_moi> /* copy a File
Thực hiện theo câu lệnh: java CopyFile <fromfile> <to-file> */
import java.io.*; class CopyFile{
public static void main(String args[]) { FileInputStream fromFile; FileOutputStream toFile;
// Lấy các đối số từ chương trình main() và gán cho các tệp try {
fromFile = new FileInputStream(args[0]); //(1) toFile = new FileOutputStream(args[1]); //(2) } catch(FileNotFoundException e){
System.err.println("File could not be copied:"+e); return;
} catch(ArrayIndexOutOfBoundsException e){
System.err.println("Usage:CopyFile <fromFile> <toFile>"); return;
}
// Sao từng byte từ fromFile sang toFile try{
int i = fromFile.read(); // Đọc một byte từ fromFile while (i != -1) { // Kiểm tra xem đã cuối tệp chưa? toFile.write(i); // Ghi một byte vào toFile
i = fromFile.read(); // Đọc một byte từ fromFile }
} catch (IOException e){ // Xử lý ngoại lệ khi gặp System.err.println("Error reading/wring..."); } // Đóng tệp try { fromFile.close(); toFile.close();
} catch (IOException e) { // Xử lý ngoại lệ khi không đóng được tệp System.err.println("Error closing file.");
} } }
Câu lệnh (1) tạo ra đối tượng là biến tệp: fromFile, có tên lấy từ đối số agrs[0], lệnh (2) tạo ra đối tượng là biến tệp: toFile, có tên lấy từ đối số agrs[1].
Các lớp đọc, ghi dữ liệu nguyên thủy: DataInputStream, DataOutputStream
Gói java.io cung cấp hai giao diện DataInput và DataOutput để cài đặt các hàm đọc/ghi dạng nhị phân của các giá trị nguyên thủy (boolean, char, byte, short, int, long, float, double).
Các hàm đọc được bắt đầu bằng read, các hàm ghi bắt đầu bằng write và sau đó tên của các kiểu nguyên thủy với chữ cái đầu tiên được viết hoa.
Hai hàm readUTF() và writeUTF() được sử dụng để đọc, ghi các xâu ký tự, trong đó UTF là chuẩn để xử lý Unicode. Các ký tự Unicode thường sử dụng mã UTF8 là chuẩn UCS Transformation Format (UCS - Universal Character Set), cùng loại với ASCII.
Để ghi dạng nhị phân của các giá trị nguyên thủy lên tệp chúng ta thực hiện như sau:
2. Tạo ra một đối tượng của DataOutputStream để ghép với outFile:
DataOutputStream outStream = new DataOutputStream(outFile);
3. Ghi các giá trị nguyên thủy vào outStream:
outStream.writeBoolean(true); // Ghi giá trị: true vào outStream outStream.writeChar(‘A’); // Ghi ký tự ‘A’ vào outStream
outStream.writeByte(Byte.MAX_VALUE); // Ghi Byte.MAX_VALUE vào outStream
outStream.writeShort(Short.MIN_VALUE); // Ghi Short.MIN_VALUE vào outStream
outStream.writeInt(41); // Ghi giá trị 41vào outStream
outStream.writeLong(Long.MAX_VALUE); // Ghi Long.MAX_VALUE vào outStream
outStream.writeFloat(Float.MIN_VALUE); // Ghi Float.MIN_VALUE vào outStream
outStream.writeDouble(Math.PI); // Ghi Math.PI vào outStream
4. Đóng tệp
outStream.close();
Để đọc dạng nhị phân của các giá trị nguyên thủy từ tệp chúng ta thực hiện như sau:
1. Tạo ra một đối tượng inFile của FileInputStream:
FileInputStream inFile = new FileInputStream(“primitives.data”);
2. Tạo ra một đối tượng của DataInputStream để ghép với inFile:
DataInputStream inStream = new DataInputStream(outFile);
3. Ghi các giá trị nguyên thủy vào inStream:
booleanb = inStream.readBoolean(); char c = inStream.readChar(); byte bt = inStream.readByte(); short s = inStream.readShort(); int i = inStream.readInt(); long l =inStream.readLong();
float f = inStream.readFloat(Float.MIN_VALUE); double d = inStream.readDouble(Math.PI);
4. Đóng tệp
inStream.close();
Đọc, ghi dữ liệu thông qua buffer: BufferedInputStream, BufferedOutputStream
Hai lớp BufferedInputStream, BufferedOutputStream được sử dụng để đọc, ghi dữ liệu theo từng khối các byte, chứ không phải từng byte như hai lớp DataInputStream,
DataOutputStream. Tất nhiên khi đọc, ghi thông qua buffer thì tốc độ thực hiện sẽ nhanh hơn.
Để ghi theo buffer các byte chúng ta phải tạo ra biến tệp outBuffer:
FileOutputStream outFile = new FileOutputStrâm(“primitives.data”); BufferedOutputStream outBuffer = new BufferedOutputStream(outFile);
DataOutputStream outStream = new DataOutputStream(outBuffer);
Sau đó sử dụng các hàm tương ứng như trên để ghi (writeX()) các giá trị kiểu nguyên thủy vào outStream.
Để đọc theo buffer các byte chúng ta phải tạo ra biến tệp inbuffer:
FileInputStream inFile = new FileInputStream(“primitives.data”); BufferedInputStream inBuffer = new
BufferedInputStream(outFile);
DataInputStream inStream = new DataInputStream(outBuffer);
Sau đó sử dụng các hàm tương ứng như trên để đọc (readX()) các giá trị kiểu nguyên thủy từ inStream.