HTML 변환기에 CSV

Sep 08 2020

CSV 파일을 HTML 테이블로 변환하는 작은 프로그램을 작성했습니다. 내 목적을 위해 작동합니다. 하지만 내 코드에 더 깔끔하게 작성할 수있는 부분이 있습니까? 성능을 향상시킬 수 있습니까? 버그가 있습니까? 나는 버그를 검색했지만 다행히도 일부를 찾지 못했습니다.

추신

배경 정보를 제공해야했을 수도 있습니다. 저는 Word 문서를 좋아하지 않기 때문에 HTML 문서로 작성중인 데이터베이스 문서를 작업하고 있습니다. 그러나 수십 개의 태그가있는 열에 대한 표 형식 설명을 만드는 것은 어렵습니다. 이것이 제가이 스크립트를 작성한 이유입니다. 이제 테이블 정보를 CSV로 내보내기 만하면되고 많은 태그를 직접 입력하지 않고도 직접 변환 할 수 있습니다. 이것이 HTML 및 본문 태그가없는 이유입니다. 생성 된 테이블은 별도의 HTML 문서가 아니라 하나의 큰 HTML 문서의 일부 여야합니다.

CsvToHtmlTable.java

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.FileWriter;
import java.util.List;
import java.util.ArrayList;

public class CsvToHtmlTable {
    public static void main(String[] args) {
        // print info and show user how to call the program if needed
        System.out.println("This program is tested only for UTF-8 files.");
        if (args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("-help") || args.length != 2) {
            System.out.println("java CsvToHtmlTable <input file> <output file>");
            System.out.println("Example: java CsvToHtmlTable nice.csv nice.html");
            System.exit(0);
        }
        
        String csvFile = args[0];
        String outputFile = args[1];
        
        // read lines of csv to a string array list
        List<String> lines = new ArrayList<String>();
        try (BufferedReader reader = new BufferedReader(new FileReader(csvFile))) {
            String currentLine;
            while ((currentLine = reader.readLine()) != null) {
                lines.add(currentLine);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //embrace <td> and <tr> for lines and columns
        for (int i = 0; i < lines.size(); i++) {
            lines.set(i, "<tr><td>" + lines.get(i) + "</td></tr>");
            lines.set(i, lines.get(i).replaceAll(",", "</td><td>"));
        }
        
        // embrace <table> and </table>
        lines.set(0, "<table border>" + lines.get(0));
        lines.set(lines.size() - 1, lines.get(lines.size() - 1) + "</table>"); 
        
        // output result
        try (FileWriter writer = new FileWriter(outputFile)) {
            for (String line : lines) {
                writer.write(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

프로그램 호출 방법 :

java CsvToHtmlTable ExampleInput.csv ExampleOutput.html

ExampleInput.csv

Name,Vorname,Alter
Ulbrecht,Klaus Dieter,12
Meier,Bertha,102

ExampleOutput.html

<table border><tr><td>Name</td><td>Vorname</td><td>Alter</td></tr>
<tr><td>Ulbrecht</td><td>Klaus Dieter</td><td>12</td></tr>
<tr><td>Meier</td><td>Bertha</td><td>102</td></tr></table>

답변

4 Marc Sep 09 2020 at 03:25

좋은 구현, 내 제안을 인라인으로 찾으십시오.


더 깨끗하게 쓸 수 있습니까?

  • 이 클래스 java.nio.file.Files에는 사용할 수있는 몇 가지 편리한 메서드가 있습니다.
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
  • 구분 문자에 대한 상수를 만드는 것을 고려하십시오. 일부 CSV 파일은 ;쉼표 등을 포함하는 값을 처리하기 위해 로 구분됩니다 .
public static final String DELIMITER_CHAR=",";
  • 사용자 메시지를 제공하고 I / O 예외가 발생한 경우 종료합니다. 예 :
} catch (IOException e) {
    System.out.println("Error reading input file: "+e.getMessage());
    System.exit(1);
}
  • 로직을 캡슐화하여 라인을 메소드로 변환하여 테스트하고 재사용하기 쉽도록하십시오. 예를 들면 :
public class CsvToHtmlTable{
    public static List<String> convert(List<String> lines){/**/}
    public static void main(String[] args){/**/}
}

성능을 향상시킬 수 있습니까?

이 구현의 한계는 메모리 제약입니다. 입력 파일이 크면 전체 파일이 사용 가능한 메모리에 맞지 않을 수 있습니다.

귀하의 경우가 아닐 수도 있지만 대용량 파일을 처리해야하는 경우 파일을 한 줄씩 읽고 쓰는 것을 고려하십시오.


버그가 있습니까?

  • 입력 파일이 비어 있는지 확인하십시오. 그렇지 않으면 lines.set(0,..)실패합니다.
  • @ Doi9t가 언급했듯이 입력 유효성 검사 논리는 인수가 하나, 둘 또는 그 이상 없을 때 고려해야합니다.
5 AJNeufeld Sep 09 2020 at 03:02

CSVReader

CSV 파일을 읽는 것은 복잡한 작업이 될 수 있습니다. 많은 CSV 파일은 쉼표로 구분 된 값이지만 값에 쉼표가 포함 된 경우 큰 따옴표로 묶이고 값에 큰 따옴표가 포함 된 경우 큰 따옴표 자체가 큰 따옴표로 표시됩니다.

기본 CSV 파일보다 더 많은 것을 처리하려면 OpenCSV (com.opencsv : opencsv : 5.0) 또는 Apache Commons CSV (org.apache.commons : commons-csv : 1.7) 와 같은 CSV 라이브러리를 사용해야합니다 .

HTML

유효한 HTML

코드는 기본적으로 <table>...table data...</table>. 이것은 적절한 HTML이 아닙니다. <html>...</html>전체 문서와 <body>...</body>콘텐츠 주변에 태그 가 없습니다 . 당신은 아마 <head>...</head>좋은 <title>...</title>.

탈출

CSV 데이터에 <,, >등의 특수 문자가 포함 &된 경우 생성 된 HTML 테이블에서 실제로 이스케이프해야합니다.

표 제목

표의 첫 번째 줄에 데이터가 아닌 제목이 포함 된 것 같습니다. 첫 번째 테이블 행은 <th>...</th>태그 대신 태그 로 형식을 지정해야 <td>...</td>합니다.

라인 별 처리

전체 CSV 파일을 메모리로 읽고 전체가로드 된 경우에만 HTML로 다시 작성합니다. 이것은 특히 CSV 파일이 큰 경우 메모리 집약적입니다!

대신 다음을 수행 할 수 있습니다.

  • CSV 열기
  • HTML 파일 열기
  • HTML 프롤로그 작성
  • CSV 파일에서 읽은 각 행에 대해 :
    • 형식을 지정하고 HTML 파일에 줄 쓰기
  • HTML 에필로그 작성

CSV에서 인용을 처리하거나 출력에서 ​​HTML 엔티티를 이스케이프하지 않고 테스트되지 않은 힙에서 코딩 :

        try (BufferedReader reader = new BufferedReader(new FileReader(csvFile));
             FileWriter writer = new FileWriter(outputFile)) {

            writer.write("<html><body><table border>\n");

            String currentLine;
            while ((currentLine = reader.readLine()) != null) {
                writer.write("<tr>");

                for(String field: currentLine.split(","))
                    writer.write("<td>" + field + "</td>");

                writer.write("</tr>\n");
            }

            writer.write("</table></body></html>\n");

        } catch (IOException e) {
            e.printStackTrace();
        }

XML 및 XSLT

CSV to XML 변환기 작성을 고려할 수 있습니다.

XML 출력은 다음과 같습니다.

<data input-file='ExampleInput.csv'>
  <person>
    <Name>Ulbrecht</Name>
    <Vorname>Klaus Dieter</Vorname>
    <Alter>12</Alter>
  </person>
  <person>
    <Name>Meier</Name>
    <Vorname>Bertha</Vorname>
    <Alter>102</Alter>
  </person>
</data>

그런 다음 XSLT 스타일 시트 를 사용하여 파일에 HTML을 작성하지 않고도 브라우저에서 XML을 HTML로 변환 할 수 있습니다 .

3 Noname Sep 10 2020 at 23:23

NullPointerException라인에서 가능if (args[0].equals...

인덱스 / 항목에 액세스하기 전에 입력 args크기를 확인하십시오 nullifying.
예, 다른로드 된 클래스에서 호출 args할 수 있습니다 null. 또는 사용자가 args.

버퍼링 파일

전체 파일을 메모리에 캐싱 한 다음 처리하는 것이 귀하의 경우에 좋은 생각이라고 생각합니다. 읽은 각 줄을 간단히 처리하고 쓰고 다음 줄로 진행할 수 있습니다. ( AJNeufeld가 언급 한 Line By Line Processing )

깨진 열 (구분자) 분할

기본적으로 lines.get(i).replaceAll(",",...)데이터 자체가 ,콘텐츠로 포함 되므로 사용하는 열 데이터 분할 이 손상 됩니다.

Porsche,"991,991.2,992",70코드 (및 AJNeufeld에서 제공 한 코드까지도)가 실패 할 위치를 줄로 고려하면 991,991.2,992하나의 값 ""이 있고 파서에게 이스케이프 된 데이터가 앞서 있음을 알려줍니다.

따라서 개인적 으로 끝 쌍 까지 ,시작 부분에 도달 할 때 구분 기호로 건너 뛸 수있는 문자 단위 구문 분석 프로세스를 사용하는 것이 좋습니다 .""

예기치 않은 문자

또한 예기치 않은 문자를 어설 션, 건너 뛰기 또는 변환하는 것을 고려합니다. 예를 들어 NULL( \0) 문자를 0x00경고 로 변환 하거나 경고를 표시하고 건너 뜁니다.

파일 삭제

파일에서 읽고 저장하도록 앱을 잠그지 않는 것이 좋습니다. 여러 번 STDIN, STDOUT더 환영받는 방법입니다.

나는 파일과 STDIN. 예를 들어, 사용 설정해야 -fin인수에 파일 입력, 또는 -stdin에서 도구 읽기를 알려 STDIN.

파일 확인

파일을 처리하기 전에 파일 (인 / 아웃 모두)을 확인하는 것도 좋습니다. 액세스 할 수 있는지 확인합니다.

역설

프로세스 중에 예기치 않은 IO 예외가 발생하는 동안 결과를 정리 (또는 프롬프트 / 설정 가능)하는 것도 좋을 수 있습니다.

도움이 되었기를 바랍니다.