JAVA/HIGH JAVA

과제 - POI 라이브러리

아잠만_ 2024. 5. 10. 11:02

Apache POI (Poor Obfuscation Implementation)​​ Java 프로그래밍 언어를 사용하여 Microsoft Office형식의 문서를 읽고 쓰는데 사용되는 라이브러리

1. 라이브러리 파일을 다운받아 수동으로 프로젝트에 라이브러리로 연결​
2. maven 혹은 gradle에서 의존성(dependency)을 추가하여 사용하는 방법

더보기

반드시 필요한 jar 파일은 ​

poi.jar, ​
poi-exelant.jar, ​
poi-ooxml.jar, ​
poi-ooxml-ful.jar, ​

ooxml-lib 폴더의 ​
commons-compress.jar, ​
xmlbeans.jar, ​

lib 폴더의 ​
commons-collections.jar, ​
commons-math.jar, ​
commons-io.jar ,

log4j-api.jar

 

log4j-core.jar

POI라이브러리 에는 HSSF, XSSF, SXSSF 3가지 클래스가 존재​
HSSF : 엑셀 97 ~ 2003버전 xls​
XSSF : 엑셀 2007버전이상  xlsx​
SXSSF : 가장 최근에 나온 성능개선버전 

엑셀 쓰기 / 읽기

package poiTest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.usermodel.FormulaEvaluator;
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.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class Xlsx {
    
    public static void main(String[] args) throws IOException {
        Xlsx x = new Xlsx();
        x.write("d:/d_other", "학생.xlsx");
        
        x.reader("d:/d_other", "학생.xlsx");
    }

    // 엑셀 파일을 생성하고 데이터를 쓰는 메서드
    // createSheet(), createRow(index), createCell(index), setCellValue(value값)
    // 파일저장 workBook객체.write(FileOutputStream객체);
    public void write(String path, String fileName) throws IOException{
        Workbook workBook = new XSSFWorkbook(); // 엑셀 워크북 생성

        // 시트 생성
        // createSheet()
        Sheet sheet0 = workBook.createSheet();
        Sheet sheet1 = workBook.createSheet();
        Sheet sheet2 = workBook.createSheet();
        Sheet sheet3 = workBook.createSheet();

        // 행 생성
        // createRow(index);
        Row row0 = sheet0.createRow(0);
        Row row1 = sheet0.createRow(1);
        Row row2 = sheet0.createRow(2);
        Row row3 = sheet0.createRow(3);
        Row row4 = sheet0.createRow(4);

        
        // 열 생성
        // createCell(index)
        
        // 값 입력
        // setCellValue(value값)
        row0.createCell(0).setCellValue("번호");
        row0.createCell(1).setCellValue("이름");
        row0.createCell(2).setCellValue("나이");
        row0.createCell(3).setCellValue("주소");

        // 데이터 행에 값 쓰기
        row1.createCell(0).setCellValue("1");
        row1.createCell(1).setCellValue("홍길동");
        row1.createCell(2).setCellValue("19");
        row1.createCell(3).setCellValue("대전");

        row2.createCell(0).setCellValue("2");
        row2.createCell(1).setCellValue("이순신");
        row2.createCell(2).setCellValue("24");
        row2.createCell(3).setCellValue("서울");

        row3.createCell(0).setCellValue("3");
        row3.createCell(1).setCellValue("김영희");
        row3.createCell(2).setCellValue("20");
        row3.createCell(3).setCellValue("청주");
        
        row4.createCell(0).setCellValue("4");
        row4.createCell(1).setCellValue("김철수");
        row4.createCell(2).setCellValue("20");
        row4.createCell(3).setCellValue("대전");

        // 파일 출력 스트림 생성 및 엑셀 파일로 저장
        FileOutputStream fout = new FileOutputStream(path+"/"+fileName);
        
        // 파일저장 workBook객체.write(FileOutputStream객체);
        workBook.write(fout);
        fout.close();
    }
    
    // 엑셀 파일을 읽어서 데이터를 출력하는 메서드
    // getNumberOfSheets(), getSheetAt(index)
    // getPhysicalNumberOfRows(), getPhysicalNumberOfCells()
    // getRow(index), getCell(index)
    // getCellType()
    // get[타입]CellValue()
    public void reader(String path, String name) {
        try {
            File file = new File(path+"/"+name);
            FileInputStream fis = new FileInputStream(file);
            XSSFWorkbook workbook = new XSSFWorkbook(fis); // 엑셀 워크북 생성
            
            // 시트 갯수 가져오기
            // getNumberOfSheets()
            int sheetNum = workbook.getNumberOfSheets();
            
            // 각 시트별로 데이터 출력
            for(int s = 0; s < sheetNum; s++) {
                // 시트 가져오기
            	// getSheetAt(index)
                XSSFSheet sheet = workbook.getSheetAt(s);
                
                // 존재하는 행 갯수 가져오기 (반복문을 위해 존재하는 row 갯수를 가져옴)
                // getPhysicalNumberOfRows()
                int rows = sheet.getPhysicalNumberOfRows();
                
                // 각 행별로 데이터 출력
                for(int r = 0 ; r < rows ; r++) {
                    // 행 가져오기
                	// getRow(index)
                    XSSFRow row = sheet.getRow(r);
                    
                    // 행의 셀 갯수 가져오기 (반복문을 위해 존재하는 cell 갯수를 가져옴)
                    // getPhysicalNumberOfCells()
                    int cells = row.getPhysicalNumberOfCells(); 
                    
                    System.out.print("|    "+r+"    |");
                    
                    for(int c = 0 ; c < cells; c++) {
                    	// 각 셀별로 데이터 출력
                    	// getCell(index)
                        XSSFCell cell = row.getCell(c);
                        
                        String value = "";
                        if(cell!=null) {
                            // 셀 타입 확인하기
                        	// getCellType()
                        	// STRING, NUMERIC, FORMULA, BLANK, ERROR
                        	
                            switch(cell.getCellType()) {
                            case STRING: // 텍스트
                            	// getStringCellValue()
                                value = cell.getStringCellValue();
                                break;
                            case NUMERIC: // 숫자
                            	// getNumericCellValue()
                                value = cell.getNumericCellValue()+"";
                                break;
                            case FORMULA: // = 붙은 계산식 처리
								// getCachedFormulaResultType() 결과타입 불러올때 
                            	//value = cell.getCellFormula() 를 사용하면 =123+100 일때 123+100 을 표시한다. 따라서 계산을 하려면 아래코드를 쓴다. 
                            	// 결과값이 필요할 때 FormulaEvaluator객체를 사용한다
								FormulaEvaluator formulaEval = workbook.getCreationHelper().createFormulaEvaluator();
								value = formulaEval.evaluate(cell).formatAsString();
								break;
                            case BLANK: // 빈칸
                            	// getBooleanCellValue()
                                value = cell.getBooleanCellValue()+"";
                                break;
                            case ERROR: // 에러처리
                            	// getErrorCellValue()
                                value = cell.getErrorCellValue()+"";
                                break;
                            }
                        }
                        // 셀의 값 출력
                        System.out.print("\t"+value+"\t|");
                    }
                    System.out.println(); // 한 행 출력 후 줄 바꿈
                }
            }
        } catch(FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e){
            e.printStackTrace();
        }
    }
}

 

활용한 예제 - 전화번호부 관리

package poiTest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

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.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;


/*
	load()와 saveData()메서드에서 POI를 활용한 데이터 저장/출력을 함
 */
public class PhoneBookTest {
	// 띄어쓰기를 쓰면 scanner에서 오류 나중에 알려줌
	Scanner scan;
	private HashMap<String, Phone> phoneMap;
	// 데이터 변경 여부
	private boolean changeChk;

	// 생성자
	public PhoneBookTest() {
		phoneMap = (HashMap<String, Phone>) load();
		scan = new Scanner(System.in);
		changeChk = false;
	}

	public static void main(String[] args) {
		PhoneBookTest p = new PhoneBookTest();
		p.startProgram();
	}

	public void startProgram() {
		// 시작 시 데이터가 있다면 데이터를 phoneMap에 저장함
		load();

		while (true) {
			int choice = menu();
			System.out.println();
			switch (choice) {
			case 1:
				insert();
				break;
			case 2:
				update();
				break;
			case 3:
				delete();
				break;
			case 4:
				search();
				break;
			case 5:
				print();
				break;
			case 6:
				saveData();
				break;
			case 0:
				saveData();
				System.out.println("프로그램을 종료합니다...");
				return;
			default:
				System.out.println("잘못된 입력입니다.");
			}
		}
	}

	private int menu() {
		System.out.println();
		System.out.println("\t메  뉴");
		System.out.println();
		System.out.println("1. 전화번호 등록");
		System.out.println("2. 전화번호 수정");
		System.out.println("3. 전화번호 삭제");
		System.out.println("4. 전화번호 검색");
		System.out.println("5. 전화번호 전체 출력");
		System.out.println("6. 전화번호 저장");
		System.out.println("0. 프로그램 종료");
		System.out.print("메뉴선택 : ");
		return scan.nextInt();
	}

	// 초기에 엑셀 데이터가 있다면 phoneMap에 저장
	// 이름 전화번호 주소
	private Map<String, Phone> load() {
		File file = new File("D:/d_other/phonedata.xlsx");
		// 데이터가 없다면 종료
		if (!file.exists()) {
			return new HashMap<String, Phone>();
		}
		HashMap<String, Phone> pMap = new HashMap<String, Phone>();

		FileInputStream fin =null;
		try {
			fin = new FileInputStream(file);
			
			XSSFWorkbook workbook = new XSSFWorkbook(fin);
			// 시트 가져오기 ( 첫번째 시트에 데이터 저장 )
			XSSFSheet sheet = workbook.getSheetAt(0);
			// 존재하는 행 갯수 가져오기
			int rows = sheet.getPhysicalNumberOfRows();
			
			// 각 행별로 데이터 출력
			// 첫번째 row는 인덱스임으로 포함시키지않음
			for(int r = 1 ; r < rows ; r++) {
				// row번호가 변할 때마다 데이터 초기화
				String name = "";
				Phone phone = new Phone();
				
				// 행 가져오기
				XSSFRow row = sheet.getRow(r);
				
				int cells = row.getPhysicalNumberOfCells(); // 행의 셀 갯수 가져오기
				
				for(int c = 0 ; c < cells; c++) {
					XSSFCell cell = row.getCell(c); // 셀 값 가져오기
					
					String value = "";
					if(cell!=null) {
						// 모든 타입이 String이기때문에 String으로 가져옴
						value = cell.getStringCellValue();
					}
					// 셀의 값 저장
					switch (c) {
					// c = 0 이름
					case 0:
						name = value;
						phone.setName(value);
						break;
					// c = 1 전화번호
					case 1:
						phone.setTelNo(value);
						break;
					// c = 2 주소
					case 2:
						phone.setAddress(value);
						break;
					default:
						break;
					}
				}
				// 해당 phone 객체에 데이터를 모두 저장한 뒤에 하나의 데이터를 map에 저장
				// 맵에 값을 저장
				pMap.put(name, phone);
			}
			
		} catch (Exception e) {
			// TODO: handle exception
		}
		
			 
		return pMap;
	}

	// 데이터 저장
	// 엑셀로 데이터 저장함
	private void saveData() {
		// true값은 변경
		if (!changeChk) {
			System.out.println("변경할 것이 없습니다");
			return;
		}
		// 해당 엑셀을 가져옴
		File file = new File("D:/d_other/phonedata.xlsx");
		FileOutputStream fout = null;
		XSSFWorkbook workbook = new XSSFWorkbook();
		Sheet sheet = workbook.createSheet();
		
		try {
			fout = new FileOutputStream(file);
			
			// 첫번째 row는 인덱스
			Row row0 = sheet.createRow(0);
			row0.createCell(0).setCellValue("이름");
			row0.createCell(1).setCellValue("전화번호");
			row0.createCell(2).setCellValue("주소");
			
			// 1부터 데이터를 찾음
			int rowNum = 1;
			// 데이터 입력
			for(String name : phoneMap.keySet()) {
				// 이름을 꺼내서 저장
				Phone phone = phoneMap.get(name);
				// rowNum 값을 저장한 뒤에 나중에 +1을 해줌
				Row row = sheet.createRow(rowNum++);
				
				String telNo = phone.getTelNo();
				String addr = phone.getAddress();
				
				// 해당 cell번호에 해당하는 값에 데이터 입력
				row.createCell(0).setCellValue(name);
				row.createCell(1).setCellValue(telNo);
				row.createCell(2).setCellValue(addr);
			}
			workbook.write(fout); // workbook을 FileOutputStream을 사용하여 파일에 씁니다.
			System.out.println("저장되었습니다");
			
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(fout!=null) try {
				fout.close(); // 스트림을 닫습니다.
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}
	}

	
	
	
	// 변화 XX
	private void insert() {
		System.out.println("새롭게 등록할 전화번호 정보를 입력하세요.");
		System.out.print("이름 >> ");
		String name = scan.next();
		if (phoneMap.containsKey(name)) {
			System.out.println("'" + name + "'은 이미 등록된 사람입니다.");
			return;
		}
		System.out.print("전화번호 >> ");
		String telNo = scan.next();
		scan.nextLine(); // 입력 버퍼 엔터 비움
		System.out.print("주소 >> ");
		String address = scan.nextLine();
		Phone p = new Phone();
		p.setName(name);
		p.setTelNo(telNo);
		p.setAddress(address);
		phoneMap.put(name, p);
		System.out.println("'" + name + "' 전화번호 등록 완료!!");
		changeChk = true;
	}

	private void update() {
		System.out.println("변경할 이름을 입력해주세요");
		String name = scan.next();
		if (!phoneMap.containsKey(name)) {
			System.out.println("'" + name + "'은 등록되지 않은 사람입니다.");
			return;
		}
		System.out.print("전화번호 >> ");
		String telNo = scan.next();
		scan.nextLine(); // 입력 버퍼 엔터 비움
		System.out.print("주소 >> ");
		String address = scan.nextLine();
		Phone p = new Phone();
		p.setName(name);
		p.setTelNo(telNo);
		p.setAddress(address);
		phoneMap.put(name, p);
		System.out.println("'" + name + "' 전화번호 변경 완료!!");
		changeChk = true;
	}

	private void delete() {
		System.out.println("삭제할 이름을 입력해주세요");
		String name = scan.next();
		if (!phoneMap.containsKey(name)) {
			System.out.println("'" + name + "'은 등록되지 않은 사람입니다.");
			return;
		}
		phoneMap.remove(name);
		System.out.println("'" + name + "' 삭제 완료!!");
		changeChk = true;
	}

	private void search() {
		System.out.println("검색할 이름을 입력해주세요");
		String name = scan.next();
		if (!phoneMap.containsKey(name)) {
			System.out.println("조회 결과가 없습니다.");
			return;
		}
		System.out.println("----------------------------------------");
		System.out.println("이름\t전화번호\t\t주소");
		System.out.println("----------------------------------------");
		System.out.println(name + "\t" + phoneMap.get(name).getTelNo() + "\t" + phoneMap.get(name).getAddress());
		System.out.println("----------------------------------------");
	}

	private void print() {
		System.out.println();
		System.out.println("----------------------------------------");
		System.out.println("번호\t이름\t전화번호\t\t주소");
		System.out.println("----------------------------------------");
		int count = 0;
		if (phoneMap.size() == 0) {
			System.out.println("등록된 전화번호 정보가 하나도 없습니다...");
		} else {
//			for(String name : phoneMap.keySet()) {
//				Phone phone = phoneMap.get(name);
//				String telNo = phone.getTelNo();
//				String address = phone.getAddress();
//				System.out.println(++count + "\t" + name + "\t" + telNo + "\t" + address);
//			}

			for (Map.Entry<String, Phone> entry : phoneMap.entrySet()) {
				String name = entry.getKey();
				Phone phone = entry.getValue();
				String telNo = phone.getTelNo();
				String address = phone.getAddress();
				System.out.println(++count + "\t" + name + "\t" + telNo + "\t" + address);
			}
		}
		System.out.println("----------------------------------------");
		System.out.println("출력 끝...");
		System.out.println();
	}

}

class Phone implements Serializable {
	private String name;
	private String address;
	private String telNo;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getTelNo() {
		return telNo;
	}

	public void setTelNo(String telNo) {
		this.telNo = telNo;
	}

}