공공부하자개발 · 영어 학습 노트
자바
실무 확장Excel · 파일 업로드 · DB 연동0/22 완료
  • 01Excel(XLSX) 구조와 순수 JDK로 읽기/쓰기
  • 02Apache POI로 Excel 업로드/다운로드
  • 03파일 업로드/다운로드 서버 (HttpServer)
  • 04JDBC 기초와 트랜잭션 (H2)
  • 05MyBatis 어노테이션 매퍼로 쿼리 연동
  • 06MyBatis XML 매퍼 · Oracle 방언 · PageHelper · Spring Boot
  • 07REST API 서버와 JSON
  • 08Vue 3 SPA 와 Java 서버 연동
  • 09@Scheduled 운영
  • 10로깅 실무: 레벨·계층, MDC 추적, 예외·성능, 마스킹, 롤링, JSON 로그
  • 11외부 API 연동
  • 12테스트 실무
  • 13암호화·개인정보 보호
  • 14인코딩·한글 실무
  • 15@Transactional 심화
  • 16긴 작업 비동기 처리와 진행률
  • 17SFTP·FTP 파일 연계
  • 18로컬 캐시와 @Cacheable
  • 19메일·알림 발송
  • 20웹 보안 체크리스트
  • 21빌드 도구와 폐쇄망 의존성 반입
  • 22성능 측정: p50·p95·p99, 측정 계층, JFR, JMH 함정, 자체 부하 테스트, 병목 순위
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 실무 확장 › 14 / 22

인코딩·한글 실무

UTF-8·EUC-KR·CP949, BOM, 깨진 글자 진단, 바이트 길이, 파일명
섹션 7진행 0 / 22
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

6. 연습 문제

문제 1. 주어진 바이트가 어느 인코딩인지 추정하기

바이트 ED 95 9C EA B8 80을 UTF-8, EUC-KR, CP949 세 가지로 각각 디코딩해보고 어떤 인코딩일 때 정상적으로 "한글"이 나오는지 확인하는 코드를 작성하세요.

java
byte[] b = {(byte)0xED,(byte)0x95,(byte)0x9C,
            (byte)0xEA,(byte)0xB8,(byte)0x80};
for (Charset cs : List.of(StandardCharsets.UTF_8,
        Charset.forName("EUC-KR"), Charset.forName("MS949"))) {
    System.out.println(cs.name() + ": " + new String(b, cs));
}

UTF-8 로 디코딩할 때만 "한글"이 정상적으로 나옵니다. EUC-KR·CP949 는 3바이트 단위를 2바이트씩 잘못 읽어 다른 글자나 대체 문자가 나옵니다.

문제 2. CSV export 메서드에 BOM 옵션 추가

문자열 리스트를 CSV 파일로 쓰는 메서드에 boolean withBom 매개변수를 추가해, true일 때만 UTF-8 BOM 을 파일 맨 앞에 쓰도록 하세요.

java
static void writeCsv(Path file, List<String> lines, boolean withBom)
        throws IOException {
    try (OutputStream out = Files.newOutputStream(file)) {
        if (withBom) {
            out.write(new byte[]{(byte)0xEF,(byte)0xBB,(byte)0xBF});
        }
        for (String line : lines) {
            out.write((line + "\n").getBytes(StandardCharsets.UTF_8));
        }
    }
}

Excel 로 열 CSV 는 withBom=true, 다른 프로그램이 파싱할 CSV 는 withBom=false로 호출을 나눠 쓰면 됩니다.

문제 3. 바이트 길이 검증 메서드 작성

String과 int maxBytes를 받아, UTF-8 기준 바이트 길이가 maxBytes를 넘으면 IllegalArgumentException을 던지는 validateByteLength 메서드를 작성하세요.

java
static void validateByteLength(String value, int maxBytes) {
    int len = value.getBytes(StandardCharsets.UTF_8).length;
    if (len > maxBytes) {
        throw new IllegalArgumentException(
                "바이트 길이 초과: " + len + " > " + maxBytes);
    }
}

DB insert 전 검증 로직에 그대로 끼워 넣을 수 있고, Main.truncateByBytes와 짝을 이뤄 "자를지 거부할지"를 상황에 맞게 고를 수 있습니다.

문제 4. 파일명 정규화 유틸 작성

업로드된 파일명을 저장하기 전에 항상 NFC 로 정규화하는 normalizeFileName(String rawName) 메서드를 작성하세요.

java
static String normalizeFileName(String rawName) {
    return Normalizer.normalize(rawName, Normalizer.Form.NFC);
}

업로드 컨트롤러의 파일 저장 로직 맨 앞에서 이 메서드를 거치게 하면, macOS 에서 온 NFD 파일명과 Windows/Linux 의 NFC 파일명이 하나로 통일됩니다.

문제 5. EUC-KR 인코딩 불가 문자 걸러내기

문자열에서 EUC-KR 로 인코딩할 수 없는 문자(확장 한글 등)만 골라 ?로 치환하는 sanitizeForEucKr(String s) 메서드를 작성하세요. 힌트: 한 글자씩 canEncode로 검사합니다.

java
static String sanitizeForEucKr(String s) {
    Charset eucKr = Charset.forName("EUC-KR");
    StringBuilder sb = new StringBuilder();
    s.codePoints().forEach(cp -> {
        String ch = new String(Character.toChars(cp));
        sb.append(eucKr.newEncoder().canEncode(ch) ? ch : "?");
    });
    return sb.toString();
}

레거시 EUC-KR 전문으로 나가기 직전, 확장 한글이 포함된 값을 통째로 실패시키지 않고 ?로 대체해 전송을 계속하고 싶을 때 씁니다.

연습 문제
    이전 섹션5 자주 하는 실수 (Tip)6 / 7다음 섹션7 정리