Hướng Dẫn Chi Tiết Đọc File Excel Trong Java: Các Thư Viện, Phương Pháp Và Ví Dụ Thực Tế

1. Giới thiệu chung

Trong nhiều ứng dụng doanh nghiệp, dữ liệu thường được lưu trữ và chia sẻ dưới dạng bảng tính Excel. Khi xây dựng các hệ thống quản lý, báo cáo, hoặc tích hợp dữ liệu, nhà phát triển Java thường cần truy cập và xử lý nội dung của các file Excel (.xls, .xlsx). Việc đọc file Excel trong Java không những giúp tự động hóa quy trình nhập dữ liệu mà còn giảm thiểu sai sót khi người dùng nhập tay.

Trong bài viết này, chúng ta sẽ đi sâu vào:

  • Các định dạng file Excel phổ biến và những đặc trưng của chúng.
  • Các thư viện Java phổ biến hỗ trợ đọc file Excel.
  • Cách cài đặt và cấu hình môi trường phát triển.
  • Các ví dụ chi tiết: từ cách đọc dữ liệu đơn giản, xử lý dữ liệu phức tạp, tới các trường hợp đặc biệt như định dạng thời gian, số tiền, công thức.
  • Mẹo tối ưu hiệu năng và xử lý lỗi.
  • Các nguồn tài nguyên và lưu ý khi triển khai production.

2. Hiểu rõ định dạng file Excel

2.1. XLS vs XLSX

Đặc tínhXLS (BIFF)XLSX (Office Open XML)
Định dạng fileBinary Interchange File Format (BIFF)Zip archive chứa XML
Kích thước tối đa65,535 dòng, 256 cột (để ý 2007 trở lên vẫn hỗ trợ)1,048,576 dòng, 16,384 cột
Tính năngGiới hạn, không hỗ trợ công thức phức tạpHỗ trợ đầy đủ, công thức, định dạng, macro
Tốc độ đọcNhanh hơn, nhưng hạn chế hơnĐòi hỏi giải nén, có thể chậm hơn
Độ tương thíchCần trình duyệt hỗ trợ legacyHỗ trợ rộng rãi, chuẩn mở
Thư viện hỗ trợApache POI HSSF, JExcelApiApache POI XSSF, SXSSF, JExcelApi không hỗ trợ

Khi quyết định thư viện, bạn cần xem xét kích thước file, tính năng cần dùng và môi trường triển khai.

2.2. Các thành phần trong file Excel

  • Workbook: Tập hợp các Sheet.
  • Sheet: Mỗi bảng tính có tên, có thể lưu trữ dữ liệu dạng 2 chiều.
  • Row: Chứa các Cell.
  • Cell: Có thể chứa dữ liệu kiểu String, Numeric, Boolean, Formula, Error.
  • Style: Định dạng (font, màu, alignment).
  • Comment: Ghi chú trong ô.

Việc hiểu rõ cấu trúc giúp viết code linh hoạt hơn.

3. Các thư viện Java hỗ trợ đọc Excel

Thư việnĐịnh dạng hỗ trợĐặc trưngThư viện chínhCách cài đặt
Apache POIXLS, XLSXThư viện chuẩn, mạnh mẽHSSF (xls), XSSF (xlsx), SXSSF (stream)Maven/Gradle
JExcelApiXLSNhỏ gọn, nhanh nhưng hạn chếJExcelApiMaven/Gradle
Excel4JXLSXDựa trên POI nhưng API dễ dùngExcel4JMaven
EasyExcelXLSXĐọc/ghi nhanh, hỗ trợ streamingEasyExcelMaven
SheetJS (Java port)XLSXDựa trên JavaScript, dễ mở rộngSheetJSJAR

Tối ưu lựa chọn: Nếu dự án chỉ cần đọc file Excel đơn giản, EasyExcel hoặc Apache POI XSSF là lựa chọn hàng đầu. Nếu cần xử lý file lớn (> 100k dòng) thì SXSSF (streaming) hay EasyExcel giúp giảm bộ nhớ.

4. Cài đặt môi trường

4.1. Sử dụng Maven

<dependencies> <!-- Apache POI --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.5</version> </dependency> <!-- EasyExcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.2.5</version> </dependency>
</dependencies>

4.2. Sử dụng Gradle

dependencies { implementation 'org.apache.poi:poi-ooxml:5.2.5' implementation 'com.alibaba:easyexcel:3.2.5'
}

4.3. Thư viện JExcelApi (đối với XLS)

<dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</artifactId> <version>2.6.12</version>
</dependency>

5. Cách đọc file Excel với Apache POI

5.1. Đọc file XLSX (XSSF)

import org.apache.poi.ss.usermodel.;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileInputStream;
import java.io.IOException;
import java.util.; public class ExcelReaderXSSF { public static void main(String args) throws IOException { String filePath = "data.xlsx"; try (FileInputStream fis = new FileInputStream(filePath); Workbook workbook = new XSSFWorkbook(fis)) { Sheet sheet = workbook.getSheetAt(0); // Sheet đầu tiên Iterator<Row> rowIterator = sheet.iterator(); while (rowIterator.hasNext()) { Row row = rowIterator.next(); Iterator<Cell> cellIterator = row.cellIterator(); List<String> cellValues = new ArrayList<>(); while (cellIterator.hasNext()) { Cell cell = cellIterator.next(); cellValues.add(getCellValueAsString(cell)); } System.out.println(cellValues); } } } private static String getCellValueAsString(Cell cell) { DataFormatter formatter = new DataFormatter(); return formatter.formatCellValue(cell); }
}

Giải thích:

  • DataFormatter tự động chuyển đổi dữ liệu theo định dạng hiển thị trong Excel (định dạng số, ngày tháng).
  • sheet.iterator() duyệt từng hàng, cellIterator() duyệt từng ô.

5.2. Đọc file XLS (HSSF)

import org.apache.poi.hssf.usermodel.HSSFWorkbook; public static void readXLS(String filePath) throws IOException { try (FileInputStream fis = new FileInputStream(filePath); Workbook workbook = new HSSFWorkbook(fis)) { // Tương tự như XSSF }
}

5.3. Đọc file lớn với SXSSF (streaming)

import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.ss.usermodel.; public static void readLargeFile(String filePath) throws IOException { try (InputStream is = new FileInputStream(filePath); Workbook workbook = new SXSSFWorkbook(new XSSFWorkbook(is))) { Sheet sheet = workbook.getSheetAt(0); // Xử lý như bình thường, SXSSF tự động flush rows ra disk khi đạt giới hạn }
}

Lưu ý: SXSSF chỉ hỗ trợ viết file, đọc vẫn phải dùng XSSF. Tuy nhiên, bạn có thể đọc bằng XSSFReader để tránh tải toàn bộ workbook vào bộ nhớ.

6. Đọc file Excel với EasyExcel

6.1. Định nghĩa POJO

Read Excel File In Java
Read Excel File In Java
import com.alibaba.excel.annotation.ExcelProperty; public class User { @ExcelProperty("Tên") private String name; @ExcelProperty("Tuổi") private Integer age; @ExcelProperty("Email") private String email; // getters & setters
}

6.2. Đọc dữ liệu

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener; import java.util.List; public class EasyExcelDemo { public static void main(String args) { String filePath = "users.xlsx"; EasyExcel.read(filePath, User.class, new PageReadListener<User>(list -> { // list: danh sách User trong một trang list.forEach(user -> System.out.println(user)); })).sheet().doRead(); }
}

Ưu điểm:

  • Không cần xử lý từng ô, chỉ cần ánh xạ tới POJO.
  • Hỗ trợ đọc file lớn với streaming (PageReadListener).
  • Hỗ trợ ghi file nhanh.

6.3. Đọc dữ liệu tùy chỉnh (row/column index)

EasyExcel.read(filePath, new AnalysisEventListener<Map<Integer, Object>>() { @Override public void invoke(Map<Integer, Object> data, AnalysisContext context) { // data: key là columnIndex, value là giá trị System.out.println(data); } @Override public void doAfterAllAnalysed(AnalysisContext context) {}
}).sheet().doRead();

7. Xử lý dữ liệu phức tạp trong Excel

7.1. Định dạng ngày tháng

  • POI:
    java if (DateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); } else { Date date = DataFormatter.formatCellValue(cell, formatter); // chuyển thành string rồi parse }

  • EasyExcel: Định nghĩa @ExcelProperty với converter = DateConverter.class (tự viết converter).

7.2. Định dạng số tiền

  • Sử dụng DataFormatter với pattern "#,##0.00".

7.3. Đọc công thức

if (cell.getCellType() == CellType.FORMULA) { FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); CellValue cellValue = evaluator.evaluate(cell); // xử lý cellValue
}

7.4. Đọc dữ liệu có merge cells

CellRangeAddress mergedRegion = sheet.getMergedRegion(0);
int firstRow = mergedRegion.getFirstRow();
int lastRow = mergedRegion.getLastRow();
int firstCol = mergedRegion.getFirstColumn();
int lastCol = mergedRegion.getLastColumn();

8. Tối ưu hiệu năng và bộ nhớ

Khía cạnhMẹo
Đọc file lớnSử dụng SXSSF (streaming) hoặc EasyExcel với PageReadListener.
Định dạng ngàyCách DateUtil.isCellDateFormatted nhanh hơn DataFormatter.
Đọc nhiều sheetNếu chỉ cần một sheet, tránh gọi workbook.getSheetAt(0) nhiều lần.
Đóng tài nguyênLuôn đóng FileInputStream và Workbook trong try-with-resources.
Đếm dòng nhanhsheet.getLastRowNum() + sheet.getPhysicalNumberOfRows() (có thể trùng).
Giảm số lượng đối tượng POJOChỉ tạo POJO khi cần, tránh lưu trữ toàn bộ dữ liệu trong bộ nhớ.

9. Xử lý lỗi và ngoại lệ

LỗiNguyên nhânGiải pháp
FileNotFoundExceptionĐường dẫn file sai hoặc không tồn tạiKiểm tra đường dẫn, quyền đọc.
EncryptedDocumentExceptionFile được bảo vệ bằng mật khẩuSử dụng WorkbookFactory.create(is, password)
IOExceptionLỗi IO khi mở/đọc fileĐảm bảo file không bị khóa, có thể thực hiện retry.
IllegalStateException: sheet is not foundSheet không tồn tạiKiểm tra tên sheet, số thứ tự.
IndexOutOfBoundsExceptionTruy cập cell ngoài phạm viKiểm tra row.getLastCellNum().

10. Ví dụ thực tế: Tải dữ liệu từ Excel vào cơ sở dữ liệu

Giả sử chúng ta có file employees.xlsx với cột: ID, Name, Position, Salary.

public class ImportEmployees { public static void main(String args) { String filePath = "employees.xlsx"; try (FileInputStream fis = new FileInputStream(filePath); Workbook workbook = new XSSFWorkbook(fis)) { Sheet sheet = workbook.getSheet("Sheet1"); for (Row row : sheet) { if (row.getRowNum() == 0) continue; // skip header Employee emp = new Employee(); emp.setId((int) row.getCell(0).getNumericCellValue()); emp.setName(row.getCell(1).getStringCellValue()); emp.setPosition(row.getCell(2).getStringCellValue()); emp.setSalary(row.getCell(3).getNumericCellValue()); // Ghi vào DB saveToDB(emp); } } catch (IOException e) { e.printStackTrace(); } } private static void saveToDB(Employee emp) { // JDBC hoặc JPA }
}

Tip: Đối với file lớn, nên batch insert với JDBC addBatch().

11. Thêm tính năng: Ghi file Excel

11.1. Sử dụng POI

Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Report");
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("ID");
header.createCell(1).setCellValue("Name"); for (int i = 0; i < data.size(); i++) { Row row = sheet.createRow(i + 1); row.createCell(0).setCellValue(data.get(i).getId()); row.createCell(1).setCellValue(data.get(i).getName());
}
try (FileOutputStream fos = new FileOutputStream("report.xlsx")) { workbook.write(fos);
}

11.2. Sử dụng EasyExcel

EasyExcel.write("report.xlsx", User.class).sheet("Users").doWrite(userList);

12. Mẹo và best practice

  1. Sử dụng DataFormatter khi cần hiển thị dữ liệu gốc. Nếu bạn chỉ cần giá trị, dùng cell.getNumericCellValue(), cell.getStringCellValue() để tránh xử lý chuỗi.
  2. Đọc file một lần, xử lý ngay. Tránh lưu trữ toàn bộ dữ liệu trong bộ nhớ nếu không cần.
  3. Sử dụng try-with-resources để tự động đóng InputStream và Workbook.
  4. Xử lý MergedRegion khi cần dữ liệu gạt ngang hoặc dọc.
  5. Kiểm tra CellType trước khi lấy giá trị. Không nên gọi getStringCellValue() trên cell kiểu số.
  6. Đặt sheet.getFirstRowNum() và sheet.getLastRowNum() để biết phạm vi dữ liệu thực tế.
  7. Định nghĩa POJO với @ExcelProperty để tránh lỗi mapping khi tên cột thay đổi.
  8. Sử dụng ThreadPoolExecutor khi đọc nhiều file đồng thời, tránh chặn thread chính.

13. Tổng kết

  • Apache POI là thư viện chuẩn, hỗ trợ cả định dạng XLS và XLSX, nhưng có thể tốn bộ nhớ khi đọc file lớn.
  • EasyExcel tối ưu cho thao tác đọc/ghi nhanh, đặc biệt khi làm việc với file lớn, nhờ streaming và API đơn giản.
  • JExcelApi phù hợp khi chỉ cần xử lý các file XLS cũ và muốn thư viện nhẹ.
  • Đối với file lớn, hãy sử dụng SXSSF hoặc EasyExcel với streaming.
  • Luôn kiểm tra kiểu cell, xử lý ngày tháng, công thức, merge region đúng cách.
  • Tối ưu bộ nhớ, đóng tài nguyên và xử lý lỗi cẩn thận.

Với những kiến thức và ví dụ trên, bạn đã có thể tự tin triển khai chức năng đọc file Excel trong dự án Java của mình, từ ứng dụng nhỏ đến hệ thống enterprise lớn. Happy coding!

⚠️
LƯU Ý QUAN TRỌNG: Miễn trừ trách nhiệm: Mặc dù chúng tôi luôn nỗ lực để đảm bảo tính chính xác và cập nhật của thông tin, nhưng các quy định về giáo dục và tuyển sinh có thể thay đổi theo thời gian. BigSchool không chịu trách nhiệm về bất kỳ sai sót nào hoặc kết quả phát sinh từ việc sử dụng thông tin trên trang này. Độc giả nên liên hệ trực tiếp với nhà trường hoặc cơ quan chức năng để có thông tin mới nhất. Ngoài ra, BigSchool tuyệt đối không bán sản phẩm, khóa học hay cung cấp dịch vụ được nhắc đến trong bài.

Viết một bình luận