Trong phát triển Java, chúng ta thường gặp trường hợp cần xác định loại tệp, chẳng hạn trong chức năng tải tệp lên, cần xác định tệp người dùng tải lên có thuộc loại yêu cầu hay không. Bài viết này sẽ giới thiệu chi tiết các cách lấy thông tin loại tệp bằng Java.
Một、Sử dụng phần mở rộng tên tệp để xác định loại tệp
Cách xác định loại tệp phổ biến nhất là dựa vào phần mở rộng của tệp. Phần lớn tệp trong hệ điều hành đều có phần mở rộng riêng, chẳng hạn phần mở rộng của tệp văn bản thường là.txt,phần mở rộng của tệp ảnh thường là.jpg hoặc.png vân vân.
Lấy phần mở rộng của tệp bằng chương trình Java rất đơn giản, chỉ cần sử dụng String của lớp substring là đủ, mã như sau:
public static String getFileExtension(File file) {
String fileName = file.getName();
if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
} else {
return "";
}
}Phương thức này nhận một File đối tượng làm tham số, sau đó sử dụng lastIndexOf phương thức tìm vị trí dấu chấm cuối cùng trong tên tệp, tức vị trí bắt đầu của phần mở rộng, sau đó sử dụng substring Phương thức lấy chuỗi phần mở rộng rồi trả về. Nếu tệp không có phần mở rộng thì trả về chuỗi rỗng.
Có thể dùng đoạn mã sau để kiểm tra phương thức này:
File file = new File("C:/path/to/file.txt");
String extension = getFileExtension(file);
System.out.println(extension);Kết quả chạy là:
txt
Sử dụng phương pháp này để xác định loại tệp có các ưu điểm sau:
Đơn giản, dễ sử dụng, mã triển khai ngắn gọn。
Có hiệu quả với đại đa số tệp, vì đại đa số tệp đều có phần mở rộng.
Tuy nhiên, phương pháp này cũng có một số nhược điểm:
Phần mở rộng của tệp có thể đã bị thay đổi, khiến kết quả xác định bị sai.
Một số tệp không có phần mở rộng, chẳng hạn như tệp thực thi không có phần mở rộng.
Để xác định loại tệp chính xác hơn, chúng ta có thể kết hợp kiểm tra số ma thuật của tệp.

II、Dùng số ma thuật của tệp để xác định loại tệp
Magic number của tệp là một số byte đặc trưng nằm trong vài byte đầu tiên của tệp, dùng để nhận diện loại tệp. Bằng cách nhận diện magic number, chúng ta có thể xác định chính xác loại tệp mà không bị ảnh hưởng bởi phần mở rộng.
Trong Java, có thể lấy magic number của tệp bằng cách đọc dữ liệu nhị phân của tệp.
2.1 Đọc dữ liệu nhị phân của tệp
Chúng ta có thể sử dụng FileInputStream để đọc dữ liệu nhị phân của tệp bằng lớp này. Phương thức dưới đây sẽ trả về một mảng byte chứa dữ liệu nhị phân của tệp:
public static byte[] readFileToByteArray(File file) throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
byte[] data = new byte[(int)file.length()];
fis.read(data);
return data;
} finally {
if (fis != null) {
fis.close();
}
}
}Phương pháp trên đã sử dụng FileInputStream để mở tệp, đọc dữ liệu và lưu dữ liệu vào một mảng byte. Lưu ý rằng sau khi đọc tệp xong, cần gọi close phương thức đóng luồng tệp để giải phóng tài nguyên hệ thống.
2.2 Dùng số ma thuật của tệp để xác định loại tệp
Có dữ liệu nhị phân của tệp, chúng ta có thể xác định loại tệp. Mỗi loại tệp đều có một số ma thuật riêng, dựa vào số ma thuật này có thể xác định loại tệp. Dưới đây là số ma thuật của một số loại tệp phổ biến cùng phương pháp xác định tương ứng:
Số magic của tệp văn bản(.txt)là
EF BB BF(đầu tệp mã hóa UTF-8 có chuỗi byte này), có thể dùng phương thức sau để xác định:public static boolean isTextFile(byte[] data) { if (data.length >= 3 && data[0] == -17 && data[1] == -69 && data[2] == -65) { return true; } return false; }Số ma thuật của ảnh JPEG(.jpg)là
FF D8 FF,có thể dùng phương pháp sau để xác định:public static boolean isJPEGFile(byte[] data) { if (data.length >= 3 && data[0] == -1 && data[1] == -40 && data[2] == -1) { return true; } return false; }Số ma thuật của ảnh PNG (.png) là
89 50 4E 47 0D 0A 1A 0A,có thể dùng phương pháp sau để xác định:public static boolean isPNGFile(byte[] data) { if (data.length >= 8 && data[0] == -119 && data[1] == 80 && data[2] == 78 && data[3] == 71 && data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10) { return true; } return false; }
Tùy nhu cầu, có thể thêm nhiều loại tệp và phương thức nhận diện số magic tương ứng hơn.
2.3 Ví dụ đầy đủ
Dưới đây là một ví dụ đầy đủ, minh họa cách dùng số ma thuật của tệp để xác định loại tệp:
import java.io.File;import java.io.FileInputStream;import java.io.IOException;public class FileTypeChecker {
public static void main(String[] args) {
File file = new File("C:/path/to/file.jpg");
try {
byte[] data = readFileToByteArray(file);
if (isJPEGFile(data)) {
System.out.println("This is a JPEG file.");
} else if (isPNGFile(data)) {
System.out.println("This is a PNG file.");
} else if (isTextFile(data)) {
System.out.println("This is a text file.");
} else {
System.out.println("Unknown file type.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] readFileToByteArray(File file) throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
byte[] data = new byte[(int)file.length()];
fis.read(data);
return data;
} finally {
if (fis != null) {
fis.close();
}
}
}
public static boolean isTextFile(byte[] data) {
if (data.length >= 3 && data[0] == -17 && data[1] == -69 && data[2] == -65) {
return true;
}
return false;
}
public static boolean isJPEGFile(byte[] data) {
if (data.length >= 3 && data[0] == -1 && data[1] == -40 && data[2] == -1) {
return true;
}
return false;
}
public static boolean isPNGFile(byte[] data) {
if (data.length >= 8 && data[0] == -119 && data[1] == 80 && data[2] == 78 && data[3] == 71 &&
data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10) {
return true;
}
return false;
}
}Đoạn mã ví dụ trên sẽ xác định loại tệp dựa vào mã nhận dạng đầu tệp và xuất kết quả tương ứng.
III、Sử dụng thư viện bên thứ ba để xác định loại tệp
Ngoài các phương pháp trên, còn có thể dùng thư viện bên thứ ba để xác định loại tệp. Java có một số thư viện mã nguồn mở của bên thứ ba giúp chúng ta lấy thông tin loại tệp thuận tiện hơn.
3.1 Tika
Tika là một dự án của Apache Software Foundation, cung cấp thư viện Java mã nguồn mở để phân tích nhiều định dạng tệp, bao gồm văn bản, hình ảnh, âm thanh, video, v.v. Dùng Tika có thể trích xuất siêu dữ liệu của tệp, bao gồm loại tệp.
Trước tiên, cần thêm thư viện phụ thuộc Tika. Nếu dùng Maven để xây dựng dự án, có thể trong pom.xml thêm các phần phụ thuộc sau vào tệp:
<dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> <version>1.27</version> </dependency>
Sau đó, có thể dùng đoạn mã sau để lấy loại tệp:
import org.apache.tika.Tika;
public class FileTypeChecker {
public static void main(String[] args) {
Tika tika = new Tika();
try {
File file = new File("C:/path/to/file.jpg");
String fileType = tika.detect(file);
System.out.println("File type: " + fileType);
} catch (IOException e) {
e.printStackTrace();
}
}
}Chạy đoạn mã trên sẽ xuất ra loại của tệp.
Tika dùng nhiều phương pháp để nhận diện loại tệp, bao gồm phần mở rộng, số ma thuật, v.v. Nó còn hỗ trợ bộ phát hiện tùy chỉnh, cho phép bổ sung các quy tắc xác định loại tệp theo nhu cầu.
3.2 FileTypeDetector
Java cung cấp một API tiêu chuẩn để phát hiện loại tệp, đó là FileTypeDetector giao diện và ProbeContentType lớp. Bằng cách triển khai giao diện này, có thể tùy chỉnh bộ phát hiện loại tệp.
Dưới đây là một ví dụ về bộ phát hiện loại tệp tùy chỉnh:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.spi.FileTypeDetector;
public class CustomFileTypeDetector extends FileTypeDetector {
@Override
public String probeContentType(Path path) throws IOException {
String extension = getFileExtension(path.toFile());
if ("txt".equals(extension)) {
return "text/plain";
} else if ("jpg".equals(extension) || "jpeg".equals(extension)) {
return "image/jpeg";
} else if ("png".equals(extension)) {
return "image/png";
} else {
return null;
}
}
private String getFileExtension(File file) {
String fileName = file.getName();
if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
} else {
return "";
}
}
}Trong ví dụ này, chúng ta xác định loại tệp dựa trên phần mở rộng và trả về kiểu MIME tương ứng.
Để sử dụng bộ dò loại tệp tùy chỉnh, hãy thêm đoạn mã sau vào điểm vào của chương trình:
File file = new File("C:/path/to/file.jpg");
Path path = file.toPath();
String fileType = Files.probeContentType(path);
System.out.println("File type: " + fileType);Chạy đoạn mã trên sẽ xuất ra loại của tệp.
Xin lưu ý, với một số loại tệp đặc biệt, chẳng hạn tệp thực thi không có phần mở rộng, phương pháp dựa trên phần mở rộng này có thể không đủ chính xác, vì vậy nên ưu tiên phương pháp dựa trên số ma thuật của tệp đã giới thiệu phía trước.
Bốn、Tổng kết
Bài viết này giới thiệu một số cách xác định loại tệp trong Java. Có thể xác định loại tệp qua phần mở rộng hoặc số ma thuật của tệp. Sử dụng thư viện bên thứ ba như Tika giúp việc xác định loại tệp thuận tiện hơn. Với các loại tệp đặc biệt, có thể dùng bộ phát hiện loại tệp tùy chỉnh để xác định chính xác.
Việc lựa chọn phương pháp phù hợp để xác định loại tệp phụ thuộc vào tình huống ứng dụng và yêu cầu cụ thể. Trong quá trình phát triển thực tế, hãy chọn phương pháp xác định phù hợp nhất dựa trên đặc điểm của tệp và yêu cầu, đồng thời cân nhắc khả năng mở rộng và tính tương thích.