Trang chủHướng dẫnSử dụng Apache POI để làm việc với file Excel trong Java
Java

Sử dụng Apache POI để làm việc với file Excel trong Java

CyStack blog 7 phút để đọc
CyStack blog24/06/2025
Locker Avatar

Bao Tran

Web Developer

Locker logo social
Reading Time: 7 minutes

Đôi khi chúng ta cần đọc dữ liệu hoặc tạo báo cáo ở định dạng Excel, chủ yếu cho mục đích kinh doanh hoặc tài chính. Vì Java không có công cụ tích hợp sẵn để làm việc với các file Excel nên chúng ta sẽ cần dùng các API mã nguồn mở cho mục đích này.

Apache Poi trong Java

Cụ thể, JExcel và Apache POI là hai lựa chọn được cộng đồng Java đề xuất nhiều nhất. Sau khi tìm hiểu kỹ hơn, chúng tôi nhận thấy Apache POI là lựa chọn tối hơn ưu vì một vài lý do:

  • Được hậu thuẫn bởi tổ chức Apache Foundation.
  • JExcel không hỗ trợ định dạng xlsx, trong khi đó POI hỗ trợ cả định dạng xls lẫn xlsx.
  • Apache POI cung cấp cơ chế xử lý dựa trên stream (stream-based processing), phù hợp với các file lớn và cần ít bộ nhớ hơn.

Apache POI

Apache POI hỗ trợ các tài liệu Microsoft Excel một cách tuyệt vời với khả năng xử lý cả hai định dạng bảng tính là xls và xlsx. Dưới đây là một số điểm quan trọng về API này:

  1. Apache POI bao gồm triển khai HSSF cho định dạng file Excel ’97(-2007), tức là .xls.
  2. Triển khai XSSF của Apache POI nên được dùng cho định dạng file Excel 2007 OOXML (.xlsx).
  3. API HSSF và XSSF của Apache POI cung cấp các cơ chế đọc, ghi và chỉnh sửa bảng tính Excel.
  4. Apache POI cũng cung cấp SXSSF API, một extension của XSSF để làm việc với các sheet Excel rất lớn. SXSSF API cần ít bộ nhớ hơn và phù hợp hơn khi làm việc với các bảng tính rất lớn và bộ nhớ heap có hạn.
  5. Có hai model (cấu trúc biểu diễn dữ liệu và logic) để lựa chọn: event model và user model. Event model cần ít bộ nhớ hơn vì file Excel được đọc dưới dạng các token cần được phải xử lý. User model có tính hướng đối tượng cao hơn, dễ sử dụng hơn, và chúng ta sẽ dùng model này trong các ví dụ ở dưới.
  6. Apache POI hỗ trợ tốt các tính năng bổ sung của Excel như làm việc với công thức, tạo format cho cell bằng cách tô màu và kẻ viền, tùy chỉnh font, header và footer, xác thực dữ liệu, chèn hình ảnh, hyperlink, v.v.

Các dependency của Maven cho Apache POI

Nếu bạn đang sử dụng Maven, hãy thêm các dependency dưới đây cho Apache POI:

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>3.10-FINAL</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.10-FINAL</version>
</dependency>

Phiên bản Apache POI tại thời điểm viết bài là 3.10-FINAL. Nếu bạn có ứng dụng Java chạy riêng, thêm các file JAR trong hình dưới đây.

Các file jar phụ thuộc của ứng dụng ví dụng dùng Apache POI

Ví dụ Apache POI: Đọc file Excel

Giả sử chúng ta có một file Excel tên là “Sample.xlsx” gồm hai sheet và chứa dữ liệu như hình minh họa bên dưới. Chúng ta muốn đọc file Excel này và tạo ra một danh sách các đối tượng Country. Sheet1 có một số dữ liệu không liên quan. Chúng ta sẽ bỏ qua phần dữ liệu này khi đọc nó.

File .xlsx mẫu

File .xlsx mẫu

Code cho Java bean Country.java của chúng ta như sau:

package com.journaldev.excel.read;

public class Country {

	private String name;
	private String shortCode;
	
	public Country(String n, String c){
		this.name=n;
		this.shortCode=c;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getShortCode() {
		return shortCode;
	}
	public void setShortCode(String shortCode) {
		this.shortCode = shortCode;
	}
	
	@Override
	public String toString(){
		return name + "::" + shortCode;
	}
	
}

Chương trình ví dụ sử dụng Apache POI để đọc file Excel và lưu dữ liệu vào danh sách các đối tượng Country có code như dưới:

package com.journaldev.excel.read;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ReadExcelFileToList {

	public static List<Country> readExcelData(String fileName) {
		List<Country> countriesList = new ArrayList<Country>();
		
		try {
			//Create the input stream from the xlsx/xls file
			FileInputStream fis = new FileInputStream(fileName);
			
			//Create Workbook instance for xlsx/xls file input stream
			Workbook workbook = null;
			if(fileName.toLowerCase().endsWith("xlsx")){
				workbook = new XSSFWorkbook(fis);
			}else if(fileName.toLowerCase().endsWith("xls")){
				workbook = new HSSFWorkbook(fis);
			}
			
			//Get the number of sheets in the xlsx file
			int numberOfSheets = workbook.getNumberOfSheets();
			
			//loop through each of the sheets
			for(int i=0; i < numberOfSheets; i++){
				
				//Get the nth sheet from the workbook
				Sheet sheet = workbook.getSheetAt(i);
				
				//every sheet has rows, iterate over them
				Iterator<Row> rowIterator = sheet.iterator();
				while (rowIterator.hasNext()) 
		        {
					String name = "";
					String shortCode = "";
					
					//Get the row object
					Row row = rowIterator.next();
					
					//Every row has columns, get the column iterator and iterate over them
					Iterator<Cell> cellIterator = row.cellIterator();
		             
		            while (cellIterator.hasNext()) 
		            {
		            	//Get the Cell object
		            	Cell cell = cellIterator.next();
		            	
		            	//check the cell type and process accordingly
		            	switch(cell.getCellType()){
		            	case Cell.CELL_TYPE_STRING:
		            		if(shortCode.equalsIgnoreCase("")){
		            			shortCode = cell.getStringCellValue().trim();
		            		}else if(name.equalsIgnoreCase("")){
		            			//2nd column
		            			name = cell.getStringCellValue().trim();
		            		}else{
		            			//random data, leave it
		            			System.out.println("Random data::"+cell.getStringCellValue());
		            		}
		            		break;
		            	case Cell.CELL_TYPE_NUMERIC:
		            		System.out.println("Random data::"+cell.getNumericCellValue());
		            	}
		            } //end of cell iterator
		            Country c = new Country(name, shortCode);
		            countriesList.add(c);
		        } //end of rows iterator
				
				
			} //end of sheets for loop
			
			//close file input stream
			fis.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return countriesList;
	}

	public static void main(String args[]){
		List<Country> list = readExcelData("Sample.xlsx");
		System.out.println("Country List\\n"+list);
	}

}

Chương trình này gồm các bước chính sau:

  1. Tạo instance Workbook phù hợp với loại file: XSSFWorkbook cho định dạng .xlsx và HSSFWorkbook cho định dạng .xls. Lưu ý rằng chúng ta có thể tạo một lớp wrapper sử dụng Factory pattern để lấy instance Workbook dựa trên tên file.
  2. Sử dụng phương thức getNumberOfSheets() của Workbook để lấy tổng số sheet, sau đó dùng vòng lặp for để duyệt qua từng sheet. Lấy instance Sheet bằng phương thức getSheetAt(int i).
  3. Lấy iterator cho Row rồi từ đó lấy iterator cho Cell để truy cập đối tượng Cell. Ở đây Apache POI sử dụng Iterator pattern.
  4. Sử dụng switch-case để xác định kiểu dữ liệu của Cell và xử lý sao cho phù hợp.

Khi chạy chương trình ví dụ Apache POI ở trên, output trên console sẽ như sau:

Random data::1.0
Random data::2.0
Random data::3.0
Random data::4.0
Country List
[India::IND, Afghanistan::AFG, United States of America::USA, Anguilla::AIA, 
Denmark ::DNK, Dominican Republic ::DOM, Algeria ::DZA, Ecuador ::ECU]

Ví dụ Apache POI: Ghi file Excel

Việc ghi file Excel bằng Apache POI cũng tương tự như việc đọc, chỉ khác là ở đây chúng ta cần tạo Workbook trước. Sau đó, ta tạo các sheet, row, cell và gán giá trị cho chúng, rồi dùng FileOutputStream để ghi Workbook ra file.

Chúng ta hãy xem một ví dụ Apache POI đơn giản, trong đó ta sẽ sử dụng danh sách các đối tượng Country từ ví dụ đọc ở trên để lưu vào một sheet của một file Excel khác.

package com.journaldev.excel.read;

import java.io.FileOutputStream;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class WriteListToExcelFile {

	public static void writeCountryListToFile(String fileName, List<Country> countryList) throws Exception{
		Workbook workbook = null;
		
		if(fileName.endsWith("xlsx")){
			workbook = new XSSFWorkbook();
		}else if(fileName.endsWith("xls")){
			workbook = new HSSFWorkbook();
		}else{
			throw new Exception("invalid file name, should be xls or xlsx");
		}
		
		Sheet sheet = workbook.createSheet("Countries");
		
		Iterator<Country> iterator = countryList.iterator();
		
		int rowIndex = 0;
		while(iterator.hasNext()){
			Country country = iterator.next();
			Row row = sheet.createRow(rowIndex++);
			Cell cell0 = row.createCell(0);
			cell0.setCellValue(country.getName());
			Cell cell1 = row.createCell(1);
			cell1.setCellValue(country.getShortCode());
		}
		
		//lets write the excel data to file now
		FileOutputStream fos = new FileOutputStream(fileName);
		workbook.write(fos);
		fos.close();
		System.out.println(fileName + " written successfully");
	}
	
	public static void main(String args[]) throws Exception{
		List<Country> list = ReadExcelFileToList.readExcelData("Sample.xlsx");
		WriteListToExcelFile.writeCountryListToFile("Countries.xls", list);
	}
}

Khi chạy ví dụ ở trên, file Excel được tạo ra sẽ có dạng như hình minh họa bên dưới.

File .xlsx mẫu

Ví dụ Apache POI: Đọc công thức trong Excel

Đôi khi chúng ta cần xử lý các file Excel phức tạp chứa nhiều công thức. Hãy cùng xem một ví dụ Apache POI đơn giản để đọc nội dung công thức của một cell cũng như giá trị được tính toán từ công thức đó.

File .xlsx mẫu

package com.journaldev.excel.read;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ReadExcelFormula {

	public static void readExcelFormula(String fileName) throws IOException{
		
		FileInputStream fis = new FileInputStream(fileName);
		
		//assuming xlsx file
		Workbook workbook = new XSSFWorkbook(fis);
		Sheet sheet = workbook.getSheetAt(0);
		Iterator<Row> rowIterator = sheet.iterator();
		while (rowIterator.hasNext()) 
        {
			Row row = rowIterator.next();
			Iterator<Cell> cellIterator = row.cellIterator();
            
            while (cellIterator.hasNext()) 
            {
            	Cell cell = cellIterator.next();
            	switch(cell.getCellType()){
            	case Cell.CELL_TYPE_NUMERIC:
            		System.out.println(cell.getNumericCellValue());
            		break;
            	case Cell.CELL_TYPE_FORMULA:
            		System.out.println("Cell Formula="+cell.getCellFormula());
            		System.out.println("Cell Formula Result Type="+cell.getCachedFormulaResultType());
            		if(cell.getCachedFormulaResultType() == Cell.CELL_TYPE_NUMERIC){
            			System.out.println("Formula Value="+cell.getNumericCellValue());
            		}
            	}
            }
        }
	}
	
	public static void main(String args[]) throws IOException {
		readExcelFormula("FormulaMultiply.xlsx");
	}
}

Khi chạy ví dụ ở trên, chúng ta sẽ nhận được output như sau:

1.0
2.0
3.0
4.0
Cell Formula=A1*A2*A3*A4
Cell Formula Result Type=0
Formula Value=24.0

Ví dụ Apache POI: Ghi công thức vào Excel

Đôi khi, chúng ta cần thực hiện một số phép tính rồi mới ghi giá trị vào cell. Ta có thể sử dụng công thức của Excel để thực hiện việc tính toán này. Cách này sẽ giúp đảm bảo tính chính xác cao hơn, vì giá trị của cell chứa công thức sẽ tự động cập nhật nếu các cell tham chiếu trong công thức bị thay đổi.

Hãy xem một ví dụ đơn giản về cách ghi công thức vào file Excel bằng Apache POI API.

package com.journaldev.excel.read;

import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class WriteExcelWithFormula {

	public static void writeExcelWithFormula(String fileName) throws IOException{
		Workbook workbook = new XSSFWorkbook();
		Sheet sheet = workbook.createSheet("Numbers");
		Row row = sheet.createRow(0);
		row.createCell(0).setCellValue(10);
		row.createCell(1).setCellValue(20);
		row.createCell(2).setCellValue(30);
		//set formula cell
		row.createCell(3).setCellFormula("A1*B1*C1");
		
		//lets write to file
		FileOutputStream fos = new FileOutputStream(fileName);
		workbook.write(fos);
		fos.close();
		System.out.println(fileName + " written successfully");
	}
	
	public static void main(String[] args) throws IOException {
		writeExcelWithFormula("Formulas.xlsx");
	}
}

File Excel được tạo ra từ chương trình trên sẽ có dạng như hình bên dưới.

File .xlsx kết quả

Trên đây là toàn bộ nội dung hướng dẫn về Apache POI để làm việc với file Excel. Bạn có thể tìm hiểu thêm các tính năng khác của Apache POI bằng cách xem qua tài liệu chính thức về các class và method của thư viện này. Chúc bạn nhanh chóng làm chủ Apache POI và các khả năng mà nó mang lại.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất