Khám phá công nghệ

Khám phá các công cụ và kỹ thuật hữu ich cho Lập trình viên

Làm việc với thư mục và file trong Java

Thắng Nguyễn

Thu, 18 Jul 2024

Làm việc với thư mục và file trong Java

Trong các ứng dụng, bạn cần thao tác thường xuyên với tập tin (file) và thư mục (folder) trong hệ thống. Các thao tác này bao gồm: liệt kê danh sách tập tin, thư mục, thêm/đổi tên, xóa thư mục, v.v. Trong bài viết này sẽ hướng dẫn một số thao tác với tập tin và thư mục trong Java. Java cung cấp 2 class hỗ trợ những việc này bao gồm:

  • Lớp java.io.File đại diện cho một tập tin (file) hoặc một thư mục (directory) của hệ thống, nó được đưa vào Java từ phiên bản 1.0.
  • Lớp java.nio.file.Files cung cấp các phương thức static và native để thao tác với tập tin và thư mục, nó được bổ sung vào từ phiên bản Java 7.0. Lớp này thường được sử dụng khi maintain/optimize chương trình để tăng hiệu suất chương trình Java. Khả năng tăng hiệu suất chương trình của NIO không chỉ phụ thuộc vào hệ điều hành mà còn phụ thuộc vào phiên bản JVM, hệ thống máy chủ, ổ cứng, hay thậm chí dữ liệu.

1. Đường dẫn (Path) là gì?

Một hệ thống tập tin lưu trữ và tổ chức các tập tin trên một số loại phương tiện lưu trữ, thường là một hoặc nhiều ổ đĩa cứng, theo cách sao cho chúng có thể dễ dàng lấy ra.

Hầu hết các hệ thống tập tin được sử dụng ngày hôm nay lưu trữ các tập tin trong một cây (hoặc cấu trúc phân cấp). Ở đầu cây là một (hoặc nhiều hơn) các nút gốc. Dưới nút gốc, có các tệp và thư mục (thư mục trong Microsoft Windows). Mỗi thư mục có thể chứa các tệp tin và các thư mục con, do đó có thể chứa các tệp và thư mục con, v.v … có khả năng lưu trữ một chiều sâu gần như vô hạn.

Microsoft Windows hỗ trợ nhiều nút gốc. Mỗi nút gốc ánh xạ tới một phân vùng, chẳng hạn như C:\ hoặc D:\. Hệ điều hành Solaris (Linux) hỗ trợ một nút gốc, được biểu thị bởi ký tự dấu gạch chéo /.

Một tập tin được xác định bởi đường dẫn của nó thông qua hệ thống tập tin, bắt đầu từ nút gốc. Ví dụ, tập tin statusReport trong hình trên được mô tả bằng ký hiệu sau:

  • Trong Hệ điều hành Solaris: /home/user2/statusReport
  • Trong Microsoft Windows: C:\home\user2\statusReport

Ký tự được sử dụng để phân cách các tên thư mục cho hệ thống tập tin:

  • Hệ điều hành Solaris sử dụng dấu gạch chéo (/).
  • Microsoft Windows sử dụng dấu gạch chéo ngược (\). Tuy nhiên, vẫn có thể sử dụng dấu gạch chéo (/) trên Microsoft Window.

Đường dẫn tương đối và tuyệt đối

  • Một đường dẫn tuyệt đối luôn chứa các phần tử gốc và danh sách thư mục đầy đủ cần thiết để định vị tệp tin. Ví dụ, /home/user2/statusReport là một đường dẫn tuyệt đối. Tất cả thông tin cần thiết để định vị tệp tin được chứa trong chuỗi đường dẫn.
  • Một đường dẫn tương đối cần phải được kết hợp với một đường dẫn khác để truy cập một tập tin. Ví dụ, user1/foo là một đường dẫn tương đối. Nếu không có thêm thông tin, một chương trình không thể xác định chính xác vị trí thư mục user2/statusReport trong hệ thống tập tin.

2. Giới thiệu lớp Java.io.File

Lớp java.io.File đại diện cho một tập tin hoặc một thư mục trong hệ thống, nó đại diện cho một đường dẫn (path). Đường dẫn này có thể không thực sự tồn tại trên hệ thống. Nếu tồn tại thì nó có thể là một thư mục (directory) hoặc là một tập tin (file).

Ví dụ tạo một đối tượng File đại diện cho một đường dẫn, và kiểm tra sự tồn tại của nó, ghi ra các thông tin cơ bản của File.

public static void main(String[] args) {
        // Tạo một đối tượng File đại diện cho một đường dẫn
    File file = new File("D:/WorkSpace/data/test.txt");

    // Kiểm tra sự tồn tại.
    System.out.println("Path exists : " + file.exists());

    if (file.exists()) {
        // Kiểm tra có phải có phải là một folder hay không?
        System.out.println("isDirectory : " + file.isDirectory());

        // Kiểm tra có phải là một đường dẫn ẩn hay không?
        System.out.println("isHidden : " + file.isHidden());

        // Lấy tên file/ folder
        System.out.println("Simple Name: " + file.getName());

        // Đường dẫn tuyêt đối.
        System.out.println("Absolute Path: " + file.getAbsolutePath());

        // Kiểm tra kích thước file:
        System.out.println("Length : " + file.length() + " (bytes)");

        // Thời điểm sửa lần cuối
        long lastMofifyInMillis = file.lastModified(); // milliseconds
        Date lastModifyDate = new Date(lastMofifyInMillis);
        System.out.println("Last modify date: " + lastModifyDate);
    }
}

3. Tạo thư mục

Lớp File cung cấp 2 phương thức để tạo môt thư mục:

  • mkdir(): Tạo thư mục cho bởi đường dẫn nếu thư mục cha tồn tại.
  • mkdirs(): Tạo thư mục cho bởi đường dẫn, bao gồm cả các thư mục cha nếu nó không tồn tại.

Ví dụ:

 public static void main(String[] args) {
    File dir = new File("D:/WorkSpace/data/created1/child1");
    System.out.println("Pathname: " + dir.getAbsolutePath());
    System.out.println("Path exists:  " + dir.exists()); // false
    System.out.println("Parent Path exists: " + dir.getParentFile().exists()); // false

    // Với mkdir(), thư mục chỉ được tạo ra nếu thư mục cha tồn tại.
    boolean created = dir.mkdir();
    System.out.println("Directory created: " + created); // false

    System.out.println();

    File dir2 = new File("D:/WorkSpace/data/created2/child2");
    System.out.println("Pathname: " + dir2.getAbsolutePath());
    System.out.println("File exists: " + dir2.exists()); // false

    // Với mkdirs(), thư mục được tạo ra bao gồm cả các thư mục cha nếu nó không tồn tại.
    created = dir2.mkdirs();
    System.out.println("Directory created: " + created); // true
}

 4. Xóa tập tin

Sử dụng phương thức delete() để xóa tập tin và thư mục. Lưu ý: phương thức delete() chỉ cho phép xóa thư mục rỗng.

public static void main(String[] args) {
    File file = new File("D:/WorkSpace/data/test.txt");
    if (file.delete()) {
        System.out.println(file.getName() + " is deleted!");
    } else {
        System.out.println("Delete operation is failed.");
    }
}

5. Xóa thư mục

a) Xóa thư mục rỗng

public static void main(String[] args) {
    File folder = new File("D:/WorkSpace/data/created4");
    if (folder.delete()) {
        System.out.println(folder.getName() + " is deleted!");
    } else {
        System.out.println("Delete operation is failed.");
    }
}

b) Xóa thư mục có chưa thư mục con và tập tin bằng đệ quy

public static void main(String[] args) {
    File folder = new File("D:/WorkSpace/gpcoder/data/created3");
    delete(folder);
}

public static void delete(File file) {

    if (file.isDirectory()) {
        // directory is empty, then delete it
        if (file.list().length == 0) {
            file.delete();
            System.out.println("Directory is deleted : " + file.getAbsolutePath());
        } else {
            // list all the directory contents
            String files[] = file.list();
            for (String temp : files) {
                // construct the file structure
                File fileDelete = new File(file, temp);

                // recursive delete
                delete(fileDelete);
            }

            // check the directory again, if empty then delete it
            if (file.list().length == 0) {
                file.delete();
                System.out.println("Directory is deleted : " + file.getAbsolutePath());
            }
        }

    } else {
        // if file, then delete it
        file.delete();
        System.out.println("File is deleted : " + file.getAbsolutePath());
    }
}

6. Đọc và ghi file trong java – Các thao tác xử lý dữ liệu

  • Bước 1: Tạo đối tượng luồng và liên kết với nguồn dữ liệu.
  • Bước 2: Thao tác dữ liệu (đọc hoặc ghi hoặc cả hai).
  • Bước 3: Đóng luồng

a) Xử lý nhập xuất dữ liệu sử dụng luồng byte

Sử dụng luồng byte trong các trường hợp như nhập xuất kiểu dữ liệu nguyên thủy (như kiểu int, float, double, boolean), nhập xuất kiểu dữ liệu kiểu đối tượng (object)

Ví dụ 1: Ghi dữ liệu vào d:/mydata.bin với DataOutputStream

public static void main(String[] args) {
  try {
   //Bước 1: Tạo đối tượng luồng và liên kết nguồn dữ liệu
   FileOutputStream fos = new FileOutputStream("d:/file/mydata.bin");
   DataOutputStream dos = new DataOutputStream(fos);
   //Bước 2: Ghi dữ liệu
   dos.writeInt(100);
   dos.writeDouble(9.5);
   //Bước 3: Đóng luồng
   fos.close();
   dos.close();
   System.out.println("Done!");
  } catch (IOException ex) {
    ex.printStackTrace();
  }
}

Ví dụ 2: Đọc dữ liệu chứa trong tập tin d:/mydata.bin với DataInputStream

public static void main(String[] args) {
  try {
   //Bước 1: Tạo đối tượng luồng và liên kết nguồn dữ liệu
   FileInputStream fis = new FileInputStream("d:/file/mydata.bin");
   DataInputStream dis = new DataInputStream(fis);
   //Bước 2: Đọc dữ liệu
   int n = dis.readInt();
   double m = dis.readDouble();
   //Bước 3: Đóng luồng
   fis.close();
   dis.close();
   //Hiển thị nội dung đọc từ file
   System.out.println("Số nguyên: " + n);
   System.out.println("Số thực: " + m);
  } catch (IOException ex) {
    ex.printStackTrace();
  }
}

b) Xử lý nhập xuất dữ liệu bằng luồng character

Luồng byte rất mạnh mẽ và linh hoạt. Tuy nhiên nếu bạn muốn lưu trữ file chứa văn bản Unicode thì luồng character là lựa chọn tốt nhất vì ưu điểm của luồng character là nó thao tác trực tiếp trên ký tự Unicode. Tất cả các luồng character đều được kế thừa từ 2 lớp Reader và Writer

Ví dụ 1: Ghi dữ liệu với FileWriter

public static void main(String[] args) {
   try {
     //Bước 1: Tạo đối tượng luồng và liên kết nguồn dữ liệu
     File f = new File("d:/mydata3.txt");
     FileWriter fw = new FileWriter(f);
     //Bước 2: Ghi dữ liệu
     fw.write("Ghi dữ liệu bằng luồng character");
     //Bước 3: Đóng luồng
     fw.close();
   } catch (IOException ex) {
     System.out.println("Loi ghi file: " + ex);
 }
}

Ví dụ 2: Đọc dữ liệu với FileReader

public static void main(String[] args) {
   try {
     //Bước 1: Tạo đối tượng luồng và liên kết nguồn dữ liệu
     File f = new File("d:/mydata3.txt");
     FileReader fr = new FileReader(f);
     //Bước 2: Đọc dữ liệu
     BufferedReader br = new BufferedReader(fr);
     String line;
     while ((line = br.readLine()) != null){
       System.out.println(line);
     }
     //Bước 3: Đóng luồng
     fr.close();
     br.close();
    } catch (Exception ex) {
      System.out.println("Loi doc file: "+ex);
  }
}

0 Comments

Để lại một bình luận