221031

서이·2022년 10월 31일

csv파일 한글 깨짐 현상때문에 수많은 검색과 방법을 취했음에도 해결이 되지 않아 헤맬 때 감사히 현규멘토님께서 도와주셨습니다.

메모장을 다른이름저장으로 UTF-8로 저장하거나 인텔리제이에서 UTF-8과 관련된 모든 설정을 해도 깨지게 나올 때엔

구글드라이브에 파일업로드 후에


Google 스프레드시트로 파일을 열어서

csv로 다운로드 후에 메모장으로 열어보면 한글깨짐 현상이 사라져있습니다.

그러나 한글깨짐 파일과 멀쩡한 파일에 차이점인 큰따옴표("") 가 있어서 파싱할 때 Split을

"\",\"" 대신에 ","로 바꿔야 제대로된 값이 나옵니다.


그러나 10만건이 아닌 4만건이 떴습니다. 중간에 예외가 껴서 파싱이 안된 것 같습니다만 아직 해결을 못했습니다.


Hospital

@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor
public class Hospital {

    private int id;
    private String openServiceName;
    private int openLocalGovernmentCode;
    private String managementNumber;
    private LocalDateTime licenseDate;
    private int businessStatus;
    private int businessStatusCode;
    private String phone;
    private String fullAddress;
    private String roadNameAddress;
    private String hospitalName;
    private String businessTypeName;
    private int healthcareProviderCount;
    private int patientRoomCount;
    private int totalNumberOfBeds;
    private float totalAreaSize;
}

@AllArgsConstructor : 모든 필드 값을 파라미터로 받는 생성자를 만듦
@NoArgsConstructor : 기본 생성자를 만들어줌


HospitalParser

public class HospitalParser implements Parser<Hospital> {
    @Override
    public Hospital parse(String str) {

        String[] row =str.split(",");
        Hospital hospital = new Hospital();
        hospital.setId(Integer.parseInt(row[0].replace("\"","")));
        hospital.setOpenServiceName(row[1]);
        hospital.setOpenLocalGovernmentCode(Integer.parseInt(row[3]));
        hospital.setManagementNumber(row[4]);
        int year = Integer.parseInt(row[5].substring(0,4));
        int month = Integer.parseInt(row[5].substring(4,6));
        int day = Integer.parseInt(row[5].substring(6,8));
        hospital.setLicenseDate(LocalDateTime.of(year,month,day,0,0,0));
        hospital.setBusinessStatus(Integer.parseInt(row[7]));
        hospital.setBusinessStatusCode(Integer.parseInt(row[9]));
        hospital.setPhone(row[15]);
        hospital.setFullAddress(row[18]);
        hospital.setRoadNameAddress(row[19]);
        hospital.setHospitalName(row[21]);
        hospital.setBusinessTypeName(row[25]);
        hospital.setHealthcareProviderCount(Integer.parseInt(row[29]));
        hospital.setPatientRoomCount(Integer.parseInt(row[30]));
        hospital.setTotalNumberOfBeds(Integer.parseInt(row[31]));
        hospital.setTotalAreaSize(Float.parseFloat(row[32]));

        return hospital;
    }
}

Parser

public interface Parser<T> {

    T parse(String str);
}

ParserFactory

@Configuration
public class ParserFactory {

    @Bean
    public ReadLineContext<Hospital> hospitalReadLineContext(){
        return new ReadLineContext<Hospital>(new HospitalParser());

    }
}

ReadLineContext

public class ReadLineContext<T>{

    private Parser<T> parser;

    public ReadLineContext(Parser<T> parser) {
        this.parser = parser;
    }

    public List<T> readByLine(String filename) throws IOException {
        
        List<T> result = new ArrayList<>();
        BufferedReader reader = new BufferedReader(
                new FileReader(filename)
        );
        String str;
        while ((str = reader.readLine()) != null) {
            try {
                result.add(parser.parse(str));
            }catch (Exception e){
                System.out.printf("파싱 중 문제가 생겨 이 라인은 넘어갑니다. 파일 내용 : %s\n", str.substring(0,20));
            }
        }
        reader.close();
        return result;
    }
}

@SpringBootTest(classes = ParserFactory.class)
class HospitalParserTest {

    @Autowired
    ReadLineContext<Hospital> hospitalReadLineContext;


    @Test
    @DisplayName("10만건 이상 데이터가 파싱 되는지")
    void oneHundreadThousandRows() throws IOException {
        String filename = "C:\\Users\\proje\\Desktop\\fulldata_01_01_02_P_의원.csv";
        List<Hospital> hospitalList = hospitalReadLineContext.readByLine(filename);
        assertTrue(hospitalList.size() > 1000);
//        assertTrue(hospitalList.size() > 10000);
        for(int i =0; i< 10; i++){
            System.out.println(hospitalList.get(i).getHospitalName());
        }
        System.out.printf("파싱된 데이터 개수 :%d ", hospitalList.size());
    }


    @Test
    @DisplayName("csv 1줄을 Hospital로 잘 만드는지 Test")
    void convertToHospital() {
        HospitalParser hp = new HospitalParser();
        String str = "\"1\",\"의원\",\"01_01_02_P\",\"3620000\",\"PHMA119993620020041100004\",\"19990612\",\"\",\"01\",\"영업/정상\",\"13\",\"영업중\",\"\",\"\",\"\",\"\",\"062-515-2875\",\"\",\"500881\",\"광주광역시 북구 풍향동 565번지 4호 3층\",\"광주광역시 북구 동문대로 24, 3층 (풍향동)\",\"61205\",\"효치과의원\",\"20211115113642\",\"U\",\"2021-11-17 02:40:00.0\",\"치과의원\",\"192630.735112\",\"185314.617632\",\"치과의원\",\"1\",\"0\",\"0\",\"52.29\",\"401\",\"치과\",\"\",\"\",\"\",\"0\",\"0\",\"\",\"\",\"0\",\"\",";
        Hospital hospital = hp.parse(str);

        assertEquals(1, hospital.getId()); // col:0
        assertEquals("의원", hospital.getOpenServiceName());//col:1
        assertEquals(3620000,hospital.getOpenLocalGovernmentCode()); // col: 3
        assertEquals("PHMA119993620020041100004",hospital.getManagementNumber()); // col:4
        assertEquals(LocalDateTime.of(1999, 6, 12, 0, 0, 0), hospital.getLicenseDate()); //19990612 //col:5
        assertEquals(1, hospital.getBusinessStatus()); //col:7
        assertEquals(13, hospital.getBusinessStatusCode());//col:9
        assertEquals("062-515-2875", hospital.getPhone());//col:15
        assertEquals("광주광역시 북구 풍향동 565번지 4호 3층", hospital.getFullAddress()); //col:18
        assertEquals("광주광역시 북구 동문대로 24, 3층 (풍향동)", hospital.getRoadNameAddress());//col:19
        assertEquals("효치과의원", hospital.getHospitalName());//col:21
        assertEquals("치과의원", hospital.getBusinessTypeName());//col:25
        assertEquals(1, hospital.getHealthcareProviderCount()); //col:29
        assertEquals(0, hospital.getPatientRoomCount()); //col:30
        assertEquals(0, hospital.getTotalNumberOfBeds()); //col:31
        assertEquals(52.29f, hospital.getTotalAreaSize()); //col:32

    }
}
profile
작성자 개인이 잊을 때마다 보라고 정리한 글

0개의 댓글