Kí hiệu e khi ghi file trong java là gì năm 2024

Chào các bạn! Có lẽ đã có quá nhiều những bài viết hướng dẫn các bạn làm việc với file trong Java. Thế nhưng đừng vội bỏ qua chuỗi bài viết này!

Nếu các bạn là những người mới bắt đầu làm quen với Java, hay mới chỉ tìm hiểu Java IO qua những ví dụ rời rạc, thì bài viết này của mình được tạo ra chính bởi mong muốn cho các bạn 1 cái nhìn tổng quan và rồi sau đó đi vào chi tiết nhất có thể, để các bạn có thể dễ hình dung hơn, dễ nắm bắt hơn, cũng như hiểu sâu hơn về Java IO. Từ đó, JavaIO sẽ trở nên thật dễ dàng

Kí hiệu e khi ghi file trong java là gì năm 2024

Trong bài viết này, chúng ta sẽ cover các API của vào - ra trong Java ( hay Java IO). Chúng ta sẽ học cách để truy cập vào file hay thư mục và làm sao để đọc, ghi file. Chúng ta cũng đi tìm hiểu sâu hơn về từng lớp trong cây phân cấp trong Java IO để hiểu xem chúng làm gì và vì sao nó được sinh ra, nó mang lại ưu và có nhược điểm gì. Bài viết này cũng sẽ cho các bạn thấy cơ chế serialization đối tượng (), thứ mà sẽ giúp bạn lưu trữ đối tượng một cách thật dễ dàng, dễ như cách mà bạn làm với dữ liệu chữ hay số vậy. Mình cũng cung cấp cho bạn source code demo tương ứng để cho các bạn tiện theo dõi và thực hành.

Trong quá trình đọc series về JavaIO này của mình, nếu có bất cứ thắc mắc gì liên quan, vui lòng liên hệ mình theo các địa chỉ

Đồng thời, nếu có điểm gì sai sót, mong các bạn bớt chút thời gian feedback lại, để bài viết có thể được đầy đủ hơn, hoàn thiện hơn, giúp các mới về sau có được những hướng dẫn đầy đủ, chính xác nhưng lại dễ hiểu nhất có thể nhé. Bởi vì khi viết series này, mình cũng chỉ mới tìm hiểu lại về JavaIO thôi

Kí hiệu e khi ghi file trong java là gì năm 2024

I. Sơ lược về Java IO.

Java IO (gói java.io) là tập hợp của các lớp và interface mà ta có thể sử dụng để thực hiện hầu như mọi thao tác vào - ra thông qua ứng dụng java.

1. Stream (luồng) là gì?

Trong Java API, một đối tượng từ đó chúng ta đọc được một dãy bytes được gọi là input stream (luồng vào). Một đối tượng để chúng ta có thể ghi một dãy bytes được gọi là output stream (luồng ra). Các nguồn và đích đến của các chuỗi byte này có thể hoặc thường là các file, nhưng chúng cũng có thể là các kết nối mạng (network connection) thậm chí là các khối (block) của bộ nhớ. Các lớp trừu tượng InputStreamOutputStream hình thành cơ sở cho cây phân cấp của các lớp vào ra (IO classes)

Byte-oriented streams (Hay luồng hướng byte / luồng hướng tới việc xử lý dạng byte) là không thuận lợi cho việc xử lý thông tin được lưu dưới dạng Unicode (nhắc lại rằng Unicode sử dụng nhiều bytes cho mỗi một ký tự). Do đó, một cây phân cấp tách biệt cung cấp các lớp cho việc xử lý ký tự Unicode được sinh ra, các lớp này được kế thừa từ các lớp trừu tượng ReaderWriter. Các lớp này có các thao tác đọc ghi được dựa trên đơn vị 2-bytes mã Unicode thay vì dự trên 1 byte ký tự.

2. Cây phân cấp trong JavaIO

Xem chi tiết thêm tại https://docs.oracle.com/javase/7/docs/api/java/io/package-tree.html

Kí hiệu e khi ghi file trong java là gì năm 2024

Hình 1: Cây phân cấp trong Java IO top-level

Kí hiệu e khi ghi file trong java là gì năm 2024

Hình 2: Cây phân cấp trong Java IO của byte-oriented stream

Kí hiệu e khi ghi file trong java là gì năm 2024

Hình 3: Cây phân cấp trong Java IO của character-oriented stream (Cái cuối là PrintWriter nhé. Mình sẽ đổi hình sau)

Trong bài học trước tôi đã giới thiệu về luồng vào ra nhị phân (input-output binary stream), trong bài này chúng ta tiếp tục tìm hiểu về luồng vào ra ký tự (input-output character stream) trong Java. Như bạn đã biết uồng nhị phân (binary stream), mỗi một lần đọc/ghi một byte (Tương đương với 8 bit), trong khi đó luồng ký tự (character stream) mỗi lần đọc/ghi một ký tự, tùy thuộc vào kiểu mã hóa (encoding) ( UTF-8, UTF-16,..) mà ký tự đó tương đương với 1, 2 hoặc 3 byte.

Trong Java, có nhiều lớp hỗ trợ các thao tác với luồng ký tự và các lớp này được dẫn đầu bởi 2 class Reader và Writer:

  • java.io.Reader: được sử dụng để đọc dữ liệu từ một nguồn (source).
  • java.io.Writer: được sử dụng để ghi dữ liệu đến đích (destination).

Kí hiệu e khi ghi file trong java là gì năm 2024

Nội dung

Đọc chuỗi từ console

Ví dụ nhập một chuỗi từ bàn phím và hiển thị chuỗi ra màn hình

package com.gpcoder.characterstream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class ReadConsole { public static void main(String[] args) throws IOException {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
  System.out.print("Enter your name: ");
  String name = br.readLine();
  if (name.equalsIgnoreCase("Exit")) {
    System.out.println("Finished!");
    break;
  }
  System.out.println("Hello " + name);
}
} }

Kết quả thực thi chương trình trên:

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

Sử dụng lớp FileReader và FileWriter

Ví dụ ghi file sử dụng lớp FileWriter

import java.io.FileWriter; public interface FileWriterExample { public static void main(String args[]) {

try {
  FileWriter fw = new FileWriter("data/test.txt");
  fw.write("gpcoder.com");
  fw.close();
} catch (Exception e) {
  System.out.println(e);
}
System.out.println("Success...");
} }

Thực thi chương trình trên, một file test.txt được tạo ra trong thư mục data với nội dung gpcoder.com

Ví dụ đọc file sử dụng lớp FileReader

package com.gpcoder.characterstream; import java.io.FileReader; public class FileReaderExample { public static void main(String args[]) throws Exception {

FileReader fr = new FileReader("data/test.txt");
int i;
while ((i = fr.read()) != -1) {
  System.out.print((char) i);
}
fr.close();
} }

Kết quả thực thi chương trình trên:

gpcoder.com

Chuyển một luồng nhị phân thành luồng ký tự

Ví dụ chuyển từ OutputStream sang Writer

package com.gpcoder.characterstream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; public class OutputStreamWriterExample { public static void main(String[] args) throws IOException {

// Tạo một OutputStream (luồng đầu ra) để ghi dữ liệu vào file.
OutputStream out = new FileOutputStream("data/test.txt");
// Tạo một Character Stream (luồng ghi ký tự) với mã hóa (encoding) là UTF-8.
Writer writer = new OutputStreamWriter(out, "UTF-8");
String s = "Lập trình Java";
writer.write(s);
writer.close();
} }

Ví dụ chuyển từ InputStream sang Reader

package com.gpcoder.characterstream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; public class InputStreamReaderExample { public static void main(String[] args) throws IOException {

// Tạo một binary Stream (luồng nhị phân), để đọc file.
InputStream in = new FileInputStream("data/test.txt");
// Tạo một Character stream (luồng ký tự) với mã hóa (encoding) là UTF-8.
Reader reader = new InputStreamReader(in, "UTF-8");
int i = 0;
// Đọc lần lượt từng ký tự.
while ((i = reader.read()) != -1) {
  // Ép kiểu (cast) thành một ký tự và in ra màn hình.
  System.out.println((char) i + " " + i);
}
reader.close();
} }

Sử dụng FilterInputStream và FilterOutputStream

Lớp FilterOutputStream trong java extends lớp OutputStream. Nó cung cấp các lớp con khác nhau như BufferedOutputStream và DataOutputStream để cung cấp các chức năng bổ sung. Vì vậy, nó ít được sử dụng riêng lẻ.

Lớp FilterInputStream trong java extends lớp InputStream. Nó cung cấp các lớp con khác nhau như BufferedInputStream và DataInputStream để cung cấp chức năng bổ sung. Vì vậy, nó ít được sử dụng riêng lẻ.

Ví dụ ghi file sử dụng lớp FilterOutputStream

package com.gpcoder.characterstream; import java.io.File; import java.io.FileOutputStream; import java.io.FilterOutputStream; import java.io.IOException; public class FilterOutputStreamExample { public static void main(String[] args) throws IOException {

FileOutputStream file = null;
FilterOutputStream filter = null;
try {
  file = new FileOutputStream(new File("data/test.txt"));
  filter = new FilterOutputStream(file);
  String s = "gpcoder.com";
  byte b[] = s.getBytes();
  filter.write(b);
  filter.flush();
  System.out.println("Success...");
} finally {
  filter.close();
  file.close();
}
} }

Ví dụ đọc file sử dụng lớp FilterInputStream

package com.gpcoder.characterstream; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FilterInputStream; import java.io.IOException; public class FilterInputStreamExample { public static void main(String[] args) throws IOException {

FileInputStream file = null;
FilterInputStream filter = null;
try {
  file = new FileInputStream(new File("data/test.txt"));
  filter = new BufferedInputStream(file);
  int k = 0;
  while ((k = filter.read()) != -1) {
    System.out.print((char) k);
  }
} catch (IOException ex) {
  ex.printStackTrace();
}
file.close();
filter.close();
} }

Sử dụng lớp BufferedReader và BufferedWriter

Lớp BufferedWriter trong java được sử dụng để cung cấp bộ đệm cho các các thể hiện của lớp Writer. Nó giúp hiệu suất nhanh. Nó thừa kế lớp Writer. Các ký tự đệm được sử dụng để cung cấp việc ghi dữ liệu hiệu quả với các mảng đơn, các ký tự và chuỗi.

Lớp BufferedReader trong java được sử dụng để đọc văn bản từ một input stream dựa trên các ký tự (character stream). Nó có thể được sử dụng để đọc dữ liệu theo dòng (line by line) bằng phương thức readLine(). Nó giúp hiệu suất nhanh. Nó kế thừa lớp Reader.

Ví dụ ghi file sử dụng BufferedWriter

package com.gpcoder.characterstream; import java.io.BufferedWriter; import java.io.FileWriter; public class BufferedWriterExample { public static void main(String[] args) throws Exception {

FileWriter writer = new FileWriter("data/test.txt");
BufferedWriter buffer = new BufferedWriter(writer);
buffer.write("gpcoder.com");
buffer.close();
System.out.println("Success...");
} }

Ví dụ đọc file sử dụng BufferedReader

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

0

Sử dụng lớp CharArrayReader và CharArrayWriter

CharArrayReader gồm có hai từ: CharArray và Reader. Lớp CharArrayReader trong java được sử dụng để đọc mảng ký tự như là một trình đọc (Reader). Nó kế thừa lớp Reader.

Lớp CharArrayWriter trong java có thể được sử dụng để ghi dữ liệu chung cho nhiều file. Lớp này thừa kế lớp Writer. Bộ đệm của nó tự động phát triển khi dữ liệu được ghi vào stream này. Gọi phương thức close() đối với đối tượng này không có hiệu lực.

Ví dụ đọc một ký tự sử dụng lớp Java CharArrayReader

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

1

Kết quả thực thi chương trình trên:

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

2

Ví dụ ghi một dữ liệu chung ra nhiều file

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

3

Thực thi chương trình trên, 4 file f1.txt, f2.txt, f3.txt, f4.txt được tạo ra trong thư mục data và có cùng nội dung gpcoder.com

Sử dụng lớp StringReader và StringWriter

Lớp StringWriter trong java là một charater stream thu thập dữ liệu từ bộ đệm chuỗi, có thể được sử dụng để xây dựng một chuỗi. Lớp StringWriter kế thừa lớp Writer. Trong lớp StringWriter, các tài nguyên hệ thống như các network socket và file không được sử dụng, do đó việc đóng StringWriter là không cần thiết.

Lớp StringReader trong java là một character stream với chuỗi như một nguồn dữ liêu. Nó lấy một chuỗi đầu vào và thay đổi nó vào character stream. Nó kế thừa lớp Reader. Trong lớp StringReader, các tài nguyên hệ thống như các network socket và các file không được sử dụng, do đó việc đóng StringReader là không cần thiết.

Ví dụ StringWriter sử dụng BufferedReader để đọc file từ luồng (stream)

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

4

Ví dụ StringReader đọc chuỗi như luồng ký tự (stream)

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

5

Ghi file với lớp PrintStream

Lớp PrintStream trong java cung cấp các phương thức để ghi dữ liệu vào một stream khác. Lớp PrintStream tự động làm sạch dữ liệu vì vậy không cần gọi phương thức flush(). Hơn nữa, các phương thức của nó không ném ngoại lệ IOException.

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

6

Ghi file với lớp PrintWriter

Lớp PrintWriter trong java là bản cài đặt của lớp Writer. Nó được sử dụng để ghi các định dạng đại diện của các đối tượng vào stream hướng văn bản.

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

7

Thực thi chương trình trên, một dòng chữ Data to write on Console using PrintWriter trong Console và một file test.txt được tạo ra trong thư mục data của project với nội dung Data to write in File using PrintWriter.

Sử dụng lớp PushbackInputStream

Lớp PushbackInputStream trong java ghi đè các phương thức của lớp InputStream và cung cấp thêm chức năng mở rộng cho một input stream khác. Nó có thể unread một byte đã được đọc và đẩy trở lại một byte.

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

8

Kết quả thực thi chương trình trên:

Enter your name: gpcoder.com Hello gpcoder.com Enter your name: exit Finished!

9

Sử dụng lớp PushbackReader

Lớp PushbackReader trong java ghi đè các phương thức của lớp FilterReader và cung cấp thêm các chức năng mở rộng. Nó được sử dụng để đọc một luồng ký tự và có thể đẩy trở lại một ký tự vào stream.

import java.io.FileWriter; public interface FileWriterExample { public static void main(String args[]) {

try {
  FileWriter fw = new FileWriter("data/test.txt");
  fw.write("gpcoder.com");
  fw.close();
} catch (Exception e) {
  System.out.println(e);
}
System.out.println("Success...");
} }

0

Kết quả thực thi chương trình trên:

import java.io.FileWriter; public interface FileWriterExample { public static void main(String args[]) {

try {
  FileWriter fw = new FileWriter("data/test.txt");
  fw.write("gpcoder.com");
  fw.close();
} catch (Exception e) {
  System.out.println(e);
}
System.out.println("Success...");
} }

1

Sử dụng lớp PipedReader và PipedWriter

Đặt ra một tình huống bạn có 2 luồng một luồng đầu vào và một luồng đầu ra. Chẳng hạn luồng dữ liệu đầu vào X đọc một file, lấy thông tin từ luồng này ghi vào luồng dữ liệu Y đầu ra là một file khác. Hai luồng X và Y trong tình huống này là tách riêng nhau. Vì vậy trong ứng dụng bạn phải có 3 thao tác:

  • Tạo luồng dữ liệu đọc X
  • Tạo luồng ghi dữ liệu Y
  • Đọc từ X ghi vào Y

Hai thao tác đầu phải có, nhưng bạn muốn bỏ đi thao tác thứ 3, nghĩa là có một cái gì đó liên hệ ngầm với nhau giữa 2 luồng ,để sao cho những ký tự xuất hiện trên luồng đầu đọc X lập tức luồng đầu ra Y biết được và đọc luôn các ký tự đó vào luồng của mình. Đó được gọi là liên hệ đường ngầm giữa 2 luồng vào và ra.

Điều này còn thực sự có ý nghĩa hơn khi biết rằng (với hiệu ứng đường ngầm này) khi luồng đầu ra khi đã đọc hết các ký tự trên luồng đầu vào nó tự động chờ đợi các ký tự nào đó xuất hiện trên luồng đầu vào và lại đọc hết vào luồng đầu ra.

Thật vậy hiệu ứng đường ngầm này chỉ sử dụng hiệu quả trong một vài tình huống không phải tất cả , và khi sử dụng nó thường được sử dụng đi đôi với xử lý đa luồng (Mulit-thread).