안녕하세요!~~
이번엔 파일구조와 자바의 자료구조에 대해서 학습하고자
자바로 CSV파일을 읽고 자료구조로 저장, 자료구조로 CSV 파일 생성
자바를 처음 공부하는 수준의 저에겐 자바의 자료구조와 파일에 대해서 조금 공부할 수 있는 기회가 되었습니다.

주로 사용된 기술
- 파일 입출력 (File I/O) 기술
BufferedReader, BufferedWriter를 사용하여 파일을 읽고 쓰는 기능이 있습니다. 파일에서 데이터를 읽을 때 InputStreamReader를 사용해 인코딩을 지정하고, 데이터를 쓸 때 OutputStreamWriter로 동일한 방식을 사용하고 있습니다. - 자료구조 활용
List, Map을 활용하여 CSV 파일 데이터를 저장하고 관리합니다. CSV 파일의 각 라인은 Map<String, Object>로 저장되고, 이러한 Map들을 List에 저장합니다. - 파일 확인 및 생성
파일의 존재 여부를 확인하는 fileExists 메서드와 새 파일을 생성하는 createNewFile 메서드가 있습니다. - CSV 데이터 파싱
CSV 파일의 데이터를 파싱하여 Map 형태로 변환하는 로직이 있습니다. 각 라인의 데이터를 쉼표(,)로 분할하여 Map에 저장하고, 이를 List에 추가합니다.
학습성과
1. 파일 처리
- 파일 경로 다루기: java.io.File 클래스를 사용하여 파일 경로를 설정하고, 해당 디렉토리 내의 파일 목록을 읽는 방법을 익힐 수 있습니다.
- 파일 읽기: FileInputStream, InputStreamReader, BufferedReader를 활용하여 파일을 읽고 데이터를 처리하는 방법을 이해할 수 있습니다.
- 파일 쓰기: FileOutputStream, OutputStreamWriter, BufferedWriter를 사용하여 파일에 데이터를 쓰는 방법을 익힐 수 있습니다.
2. 자료 구조 활용
- List, Map과 같은 자바의 자료구조를 활용하여 데이터를 저장하고 관리하는 방법을 익힐 수 있습니다.
- CSV 파일 데이터를 자료구조에 적절히 담아 처리하고 이를 출력하는 방법을 학습할 수 있습니다.
자바의 입출력 기능을 활용하여 파일을 읽고 쓰는 방법을 이해할 수 있었고, 가장큰 성과는 테이블형식의 자료구조를 이용하고 이를 응용하여 CSV 파일을 읽고 출력하고 생성할 수 있었습니다.
상황
- CSV 폴더 안에 동작하는 소스 CSVHandler 파일 , 그리고 csv 파일이 저장되어있고, 또 csv 파일들은 2개가 있습니다.
- Storage 폴더안에 있는 csv 파일은 위와 같습니다. 왼쪽 : SystemTable.csv, 오른쪽 : SubWayTable.csv
- 이 소스들을 자바소스에서 불러와서 자바의 자료구조로 담아낸다.
- 자바의 자료구조로 담아냈다면 출력을 통해 데이터를 확인한다.
- SubWayTable.csv 의 내용을 새로운 자료구조로 담고, 새로운 CSV 파일 생성때 참조데이터로 사용한다.
전체소스
package Java.File.CSV;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CSVHandler {
private static final String FILE_PATH = "C:\\Users\\zhfld\\git\\Study_java\\src\\Java\\File\\CSV\\Storage";
public static void main(String[] args) {
Map<String, List<Map<String, Object>>> csvData = readCSVFiles(FILE_PATH);
for (Map.Entry<String, List<Map<String, Object>>> entry : csvData.entrySet()) {
System.out.println(entry.getKey() + ": ");
for (Map<String, Object> vals : entry.getValue()) {
for (String key : vals.keySet()) {
System.out.print(vals.get(key) + "\t");
}
System.out.println();
}
}
writeCSV(FILE_PATH + "\\NewCsvFile.csv", csvData.get("SubWayTable.csv"));
}
private static Map<String, List<Map<String, Object>>> readCSVFiles(String folderPath) {
Map<String, List<Map<String, Object>>> csvData = new HashMap<>();
File folder = new File(folderPath);
File[] listOfFiles = folder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
if (file.isFile() && file.getName().endsWith(".csv")) {
List<Map<String, Object>> dataList = readCSV(file);
csvData.put(file.getName(), dataList);
}
}
}
return csvData;
}
private static List<Map<String, Object>> readCSV(File file) {
List<Map<String, Object>> dataList = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "cp949"))) {
String line;
String[] headers = null;
while ((line = reader.readLine()) != null) {
if (headers == null) {
headers = line.split(",");
continue;
}
String[] values = line.split(",");
Map<String, Object> data = new HashMap<>();
for (int i = 0; i < headers.length; i++) {
data.put(headers[i], values[i]);
}
dataList.add(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return dataList;
}
private static void writeCSV(String filePath, List<Map<String, Object>> dataList) {
if (!fileExists(filePath)) {
createNewFile(filePath);
}
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(filePath, true), "cp949"))) {
if (!dataList.isEmpty()) {
Map<String, Object> firstData = dataList.get(0);
StringBuilder header = new StringBuilder();
for (String key : firstData.keySet()) {
header.append(key).append(",");
}
header.deleteCharAt(header.length() - 1);
writer.write(header.toString());
writer.newLine();
for (Map<String, Object> data : dataList) {
StringBuilder line = new StringBuilder();
for (Object value : data.values()) {
line.append(value).append(",");
}
line.deleteCharAt(line.length() - 1);
writer.write(line.toString());
writer.newLine();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static boolean fileExists(String filePath) {
File file = new File(filePath);
return file.exists();
}
private static void createNewFile(String filePath) {
try {
File file = new File(filePath);
if (file.createNewFile()) {
System.out.println("New file created: " + file.getName());
} else {
System.out.println("File already exists.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
소스설명
CSV 파일을 읽어오는 함수 : readCSVFiles
private static Map<String, List<Map<String, Object>>> readCSVFiles(String folderPath) {
Map<String, List<Map<String, Object>>> csvData = new HashMap<>();
File folder = new File(folderPath);
File[] listOfFiles = folder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
if (file.isFile() && file.getName().endsWith(".csv")) {
List<Map<String, Object>> dataList = readCSV(file);
csvData.put(file.getName(), dataList);
}
}
}
return csvData;
}
private static final String FILE_PATH = "C:\\Users\\zhfld\\git\\Study_java\\src\\Java\\File\\CSV\\Storage";
위와같이 하드코딩으로 우선 filePath를 가져와서 해당 경로에 있는 csv 파일을 모두 가져옵니다. 그리고 Map 자료형에 해당 csv 데이터를 넣습니다.
CSV 파일을 자료형으로 변환하는 함수 : readCSV
private static List<Map<String, Object>> readCSV(File file) {
List<Map<String, Object>> dataList = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "cp949"))) {
String line;
String[] headers = null;
while ((line = reader.readLine()) != null) {
if (headers == null) {
headers = line.split(",");
continue;
}
String[] values = line.split(",");
Map<String, Object> data = new HashMap<>();
for (int i = 0; i < headers.length; i++) {
data.put(headers[i], values[i]);
}
dataList.add(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return dataList;
}
이 코드는 CSV 파일을 읽어들여 각 행의 데이터를 Map형태로 가공하여 리스트에 저장하는 메서드입니다. 이 코드를 통해 데이터 구조활용과 문자 인코딩 처리를 학습할 수 있었습니다.
List<Map<String, Object>>를 사용하여 데이터를 저장하는 방법을 익힐 수 있습니다. 각 Map은 CSV 파일의 한 행을 나타내며, 열의 이름과 값을 쌍으로 가지고 있습니다.
HashMap을 사용하여 데이터를 열 이름과 값의 쌍으로 저장하고, ArrayList를 사용하여 이러한 데이터를 리스트에 추가하는 방법을 배울 수 있습니다.
그리고 InputStreamReader를 사용하여 파일의 문자 인코딩을 지정할 수 있습니다. 이를 통해 다양한 문자 인코딩을 다루고 파일을 올바르게 해석하는 방법을 배울 수 있습니다.
CSV 파일을 생성하는 함수 : writeCSV
private static void writeCSV(String filePath, List<Map<String, Object>> dataList) {
if (!fileExists(filePath)) {
createNewFile(filePath);
}
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(filePath, true), "cp949"))) {
if (!dataList.isEmpty()) {
Map<String, Object> firstData = dataList.get(0);
StringBuilder header = new StringBuilder();
for (String key : firstData.keySet()) {
header.append(key).append(",");
}
header.deleteCharAt(header.length() - 1);
writer.write(header.toString());
writer.newLine();
for (Map<String, Object> data : dataList) {
StringBuilder line = new StringBuilder();
for (Object value : data.values()) {
line.append(value).append(",");
}
line.deleteCharAt(line.length() - 1);
writer.write(line.toString());
writer.newLine();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
이 소스는 CSV 파일을 작성하는 메서드로, 리스트로 제공된 데이터를 받아 파일로 저장합니다. 여기서 엄청난 고생을 했습니다.
파일이 존재하지 않는 경우에만 새 파일을 생성하고 있습니다. 기존 파일이 있는 경우에는 기존 파일에 데이터를 추가합니다.
우선 파일 쓸때 BufferedWriter를 사용하여 파일에 데이터를 쓰고 있습니다. 이를 통해 파일 작성 시 버퍼링을 수행하여 I/O 성능을 향상시킬 수 있습니다.
OutputStreamWriter를 사용하여 파일을 'cp949' 인코딩으로 작성하고 있습니다. 이는 한글을 포함한 문자를 지원하기 위한 것입니다.
주어진 List<Map<String, Object>> 형태의 데이터를 CSV 파일 형식으로 변환하여 저장하고 있습니다. 각 Map은 CSV 파일의 한 행을 나타내며, 열의 이름과 값을 쌍으로 가지고 있습니다.
첫 번째 데이터의 키를 CSV 파일의 헤더로 사용하여 열 이름을 작성합니다. 그 후, 각 행의 값을 CSV 형식에 맞게 작성하여 파일에 씁니다.
실행 결과
실행결과입니다.
csv의 파일이름과 해당 파일의 데이터가 빠짐없이 모두 출력되었으며
맨 하단 파일이 성공했을때 나오는 문구도 정상적으로 출력됨에 따라 파일이 생성성공했음을 알 수 있습니다.
마치며
이 코드를 통해 CSV 파일을 작성하는 데 필요한 기본적인 파일 입출력과 데이터 처리 방법을 학습할 수 있습니다. 또한, 문자 인코딩과 자료구조와 같은 프로그래밍의 중요한 측면도 경험할 수 있습니다. 이는 실제로 파일을 다루고 데이터를 가공하는 데 아주 작은 기능과 요소중 하나이지만 차근차근 학습해 나가면서 초보 개발자에서 탈줄하고자 계속 나아가야 겠다고 결심했습니다.

댓글