본문 바로가기

Java/JAVA

JAVA CSV 파일 입출력

반응형

Java CSV 파일 입출력

CSV 파일은 Comma Separated Values 이름 그대로 콤마(,)로 구분하는 데이터 저장 형식이다.

개인적으로 엑셀파일에 데이터가 있을 때 엑셀의 다른이름으로 저장에서 파일형식을 .csv 로 바꿔서 입출력했다.

R프로그래밍을 했을 때도 입출력했던 기억이 있다.

1. csv파일 읽기

[csv 파일 샘플]

엑셀에 적고 .csv파일로 저장한 다음에 메모장을 통해 csv파일을 열어보았을 때 화면이다.

그냥 메모장에서 샘플파일을 만들어 저장해도 무관.

* 주의할 점은 UTF-8 형식의 유니코드로 저장해야 에러가 없다. (에러나면 메모장에서 UTF-8로 저장하고하면 됨.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.tistory.jeongpro;
 
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
public class ReadCsv {
    public static void main(String[] args){
        //반환용 리스트
        List<List<String>> ret = new ArrayList<List<String>>();
        BufferedReader br = null;
        
        try{
            br = Files.newBufferedReader(Paths.get("C:\\Users\\world\\Desktop\\employee1.csv"));
            //Charset.forName("UTF-8");
            String line = "";
            
            while((line = br.readLine()) != null){
                //CSV 1행을 저장하는 리스트
                List<String> tmpList = new ArrayList<String>();
                String array[] = line.split(",");
                //배열에서 리스트 반환
                tmpList = Arrays.asList(array);
                System.out.println(tmpList);
                ret.add(tmpList);
            }
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try{
                if(br != null){
                    br.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}
 
cs

직접 코딩하면서 UTF-8문제 때문에 employee1.csv 파일로 교체했다.

결과가 깨름칙하다. 사원번호 앞에 '?' 가 붙는다. 왜 붙는지는 아직도 모르겠다.

코드는 bufferedReader로 한 줄씩 읽고 읽은 문자열에서 콤마(,)로 스플릿을 통해 나뉜 요소를 가진 배열을 만든다.

그 배열을 리스트화시켜서 넣는 것을 줄마다 반복.


2. csv 파일 쓰기

이번에는 아까 읽기한 내용 뒤에 하나의 열(주소)을 쓰기해보겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.tistory.jeongpro;
 
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
public class WriteCsv {
    public static void main(String[] args){
        //출력 스트림 생성
        BufferedWriter bufWriter = null;
        try{
            bufWriter = Files.newBufferedWriter(Paths.get("C:\\Users\\world\\Desktop\\employee2.csv"),Charset.forName("UTF-8"));
            
            //csv파일 읽기
            List<List<String>> allData = readCSV();
            
            for(List<String> newLine : allData){
                List<String> list = newLine;
                for(String data : list){
                    bufWriter.write(data);
                    bufWriter.write(",");
                }
                //추가하기
                bufWriter.write("주소");
                //개행코드추가
                bufWriter.newLine();
            }
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try{
                if(bufWriter != null){
                    bufWriter.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
    
    public static List<List<String>> readCSV(){
        //반환용 리스트
        List<List<String>> ret = new ArrayList<List<String>>();
        BufferedReader br = null;
        
        try{
            br = Files.newBufferedReader(Paths.get("C:\\Users\\world\\Desktop\\employee1.csv"));
            //Charset.forName("UTF-8");
            String line = "";
            
            while((line = br.readLine()) != null){
                //CSV 1행을 저장하는 리스트
                List<String> tmpList = new ArrayList<String>();
                String array[] = line.split(",");
                //배열에서 리스트 반환
                tmpList = Arrays.asList(array);
                System.out.println(tmpList);
                ret.add(tmpList);
            }
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try{
                if(br != null){
                    br.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
        return ret;
    }
}
 
cs

코드가 길어보이지만 아래(readCSV)함수는 아까 csv파일 읽기 소스를 그대로 옮겨서 함수로 바꾼 것뿐이다.

1. 쓰기형식(bufferdWriter)으로 파일을 열고

2. 기존 읽기코드로 읽은 내용을 한줄 한줄마다 값 넣고 콤마(,) 넣고 값 넣고 콤마(,)넣고를 반복한다.

3. 한 줄을 다 적었을 때 추가할 값을 넣는다.

4. 잘 생성되었는지 확인한다.

[결과]





반응형
  • 이리온 2020.02.26 17:08

    21라인과 57라인의 Charset.forName("UTF-8"); 은 사족이에요.
    지워주세요..
    Charset.forName() 메소드가 구현된 걸 보면 charsetName으로 Charset을 찾아서 리턴해주는 것 밖에 안해요.
    ```
    public static Charset forName(String charsetName) {
    Charset cs = lookup(charsetName);
    if (cs != null)
    return cs;
    throw new UnsupportedCharsetException(charsetName);
    }
    ```
    인코딩을 지정해서 파일을 읽고 싶으면
    Files.newBufferedWriter("파일패스","인코딩")을 지정해서 읽어 주세요.

    • Favicon of https://jeong-pro.tistory.com BlogIcon JEONG_AMATEUR 2020.02.27 09:52 신고

      잘못된 것을 바로 잡아주셔서 감사합니다.
      주석처리했습니다.
      이리온님 말씀대로 Files.newBufferedReader(Path path, Charset cs),
      Files.newBufferedWriter(Path path, Charset cs)
      을 이용해서 인코딩 지정해서 읽고 쓰면 될 것 같습니다.

  • 지나가던 osy 2021.08.14 18:59

    오래된 글인 만큼 지금은 글쓴이 분이 훨씬 더 알고 계시겠지만..
    어쩌다 방문하는 나와 같은 초보들을 위해서 부연설명하고 갑니다.

    사원번호 앞에 ?는 UTF-8 BOM의 흔적입니다.

    String array[] = line.split(","); 을
    String array[] = line.replace("\uFEFF", "").split(","); 으로 수정하여 제거할 수있습니다.

    또한 내용에 쉼표(,)와 큰따옴표(")가 포함되는 경우가 있으니
    단순히 쉼표(,)로 분리하는 것은 나중에 에러가 많이 나타날거에요.

  • 지나가던 osy 2021.08.14 19:10

    또한 메모장이 기본 저장형식이 ANSI(euc-kr)으로 지정되어있고,
    CSV파일을 만드는 사람마다 인코딩이 달라 오류가 빈번히 발생합니다.

    ------------------------------------------------------------------------------------
    UniversalDetector detector = new UniversalDetector(null);
    int nread;
    while ((nread = fis.read(buf)) > 0 && !detector.isDone()) {
    detector.handleData(buf, 0, nread);
    }
    detector.dataEnd();
    String encoding = detector.getDetectedCharset();
    ---------------------------파일 인코딩을 가져와서-------------------------------
    ( juniversalchardet-1.0.3.jar 라이브러리 필요)


    ---------------------------------------------------------------------------------------
    Path p = Paths.get(filePath);
    ByteBuffer bb = ByteBuffer.wrap(Files.readAllBytes(p));
    CharBuffer cb = Charset.forName("현재인코딩").decode(bb);
    bb = Charset.forName("UTF-8").encode(cb);
    Files.write(p, bb.array());
    -----------------------------으로 파일 인코딩을 UTF-8로 변환한 후에 작업하면 좋아요--------------------------

    • Favicon of https://jeong-pro.tistory.com BlogIcon JEONG_AMATEUR 2021.08.17 19:58 신고

      이 역시도 좋은 내용 감사합니다!
      파일 인코딩 상태도 항상 체크해야할 필요가 있습니다!
      utf8mb4를 사용하여 이모지까지 처리해주면 더 좋겠죠?!