CSV เป็น HTML Converter

Sep 08 2020

ฉันเขียนโปรแกรมเล็ก ๆ น้อย ๆ ที่แปลงไฟล์ CSV เป็น HTML-Table มันทำงานตามวัตถุประสงค์ของฉัน แต่มีบางส่วนในโค้ดของฉันที่สามารถเขียนได้สะอาดกว่านี้ไหม คุณสามารถปรับปรุงประสิทธิภาพได้หรือไม่? อาจมีข้อบกพร่องหรือไม่? ฉันค้นหาจุดบกพร่องและโชคดีที่ไม่พบบางส่วน

Postscript

บางทีฉันควรให้ข้อมูลพื้นฐานบางอย่าง: ฉันกำลังทำงานเกี่ยวกับเอกสารฐานข้อมูลที่ฉันเขียนเป็นเอกสาร HTML เพราะฉันไม่ชอบเอกสาร Word อย่างไรก็ตามการสร้างคำอธิบายแบบตารางของคอลัมน์ที่มีแท็กหลายสิบแท็กนั้นเจ็บปวด นั่นคือเหตุผลที่ฉันเขียนสคริปต์นี้: ตอนนี้ฉันต้องส่งออกข้อมูลตารางเป็น 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 พื้นฐานคุณควรใช้ไลบรารี CSV เช่นOpenCSV (com.opencsv: opencsv: 5.0) หรือApache Commons CSV (org.apache.commons: commons-csv: 1.7)

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 prolog
  • สำหรับแต่ละบรรทัดที่อ่านจากไฟล์ CSV:
    • จัดรูปแบบและเขียนบรรทัดไปยังไฟล์ HTML
  • เขียน HTML epilog

ยังไม่ได้ทดสอบเขียนโค้ดจากสะโพกโดยไม่ต้องจัดการการอ้างอิงใน 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 เป็น 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 Stylesheetเพื่อแปล XML เป็น HTML ซึ่งอาจเป็นในเบราว์เซอร์โดยไม่ต้องเขียน HTML ลงในไฟล์

3 Noname Sep 10 2020 at 23:23

ได้NullPointerExceptionที่ไลน์if (args[0].equals...

โปรดตรวจสอบargsขนาดอินพุตและnullifyingก่อนดำเนินการเข้าถึงดัชนี / รายการใด ๆ
ใช่ซึ่งargsอาจnullเรียกได้ว่าคลาสอื่นที่โหลดไว้ หรือว่างเปล่าหากผู้ใช้ลืมตั้งค่าargs.

ไฟล์บัฟเฟอร์

ฉันคิดว่าการแคชไฟล์ทั้งหมดในหน่วยความจำแล้วประมวลผลเป็นความคิดที่ดีสำหรับกรณีของคุณเนื่องจากแต่ละบรรทัดที่คุณอ่านคุณสามารถประมวลผลและเขียนและดำเนินการต่อในบรรทัดถัดไป ( ตามการประมวลผลแบบ Line By Line ที่กล่าวถึงโดย AJNeufeld)

หักคอลัมน์ (ตัวคั่น)

โดยทั่วไปการแบ่งข้อมูลคอลัมน์โดยใช้lines.get(i).replaceAll(",",...)จะเสียเนื่องจากข้อมูลจะมี,เป็นเนื้อหา

เมื่อพิจารณาถึงบรรทัดPorsche,"991,991.2,992",70ที่โค้ดของคุณ (และแม้แต่โค้ดที่ AJNeufeld ให้มา) จะล้มเหลวเนื่องจาก991,991.2,992เป็นค่าเดียวและ""มีไว้เพื่อบอกตัวแยกวิเคราะห์ข้อมูลที่ถูก Escape จะอยู่ข้างหน้า

โดยส่วนตัวแล้วฉันขอแนะนำให้ใช้กระบวนการแยกวิเคราะห์แบบ char-by-char ซึ่งช่วยให้คุณสามารถข้ามสิ่งใด ๆ ที่,เป็นตัวคั่นเมื่อคุณไปถึงช่องเปิด"จนถึง"คู่ที่สิ้นสุด

Chars ที่ไม่คาดคิด

นอกจากนี้ยังพิจารณาที่จะยืนยันข้ามหรือแปลงอักขระที่ไม่คาดคิด ตัวอย่างเช่นการแปลง a NULL( \0) char เป็น0x00หรือแสดงคำเตือนแล้วข้ามไป

ลืมไฟล์

ฉันขอแนะนำว่าอย่าล็อกแอปของคุณให้อ่านจากไฟล์และบันทึกลงในแอป หลายครั้งSTDINและSTDOUTเป็นวิธีที่น่ายินดีมากขึ้น

ฉันขอแนะนำให้รองรับทั้งไฟล์และSTDIN. ยกตัวอย่างเช่นการใช้งานมีชุด-finสำหรับไฟล์อินพุตในการโต้เถียงหรือที่จะแจ้งให้เครื่องมืออ่านจาก-stdinSTDIN

กำลังตรวจสอบไฟล์

การตรวจสอบไฟล์ (ทั้งเข้า / ออก) ก่อนประมวลผลไฟล์ก็จะดีเช่นกัน เพื่อให้แน่ใจว่าสามารถเข้าถึงได้

การยืนยัน

การล้างผลลัพธ์ (หรือพร้อมต์ / ตั้งค่าได้) ในขณะที่มีข้อยกเว้น IO ที่ไม่คาดคิดในระหว่างกระบวนการอาจดีเช่นกัน

หวังว่าจะช่วยได้