CSV zu HTML Konverter
Ich habe ein kleines Programm geschrieben, das eine CSV-Datei in eine HTML-Tabelle konvertiert. Es funktioniert für meine Zwecke. Aber gibt es Teile in meinem Code, die sauberer geschrieben werden können? Können Sie vielleicht die Leistung verbessern? Gibt es vielleicht irgendwelche Fehler? Ich habe nach Fehlern gesucht und zum Glück keine gefunden.
Nachtrag
Vielleicht hätte ich einige Hintergrundinformationen liefern sollen: Ich arbeite an einer Datenbankdokumentation, die ich als HTML-Dokument schreibe, weil ich Word-Dokumente nicht mag. Das Erstellen einer tabellarischen Beschreibung der Spalten mit Dutzenden von Tags ist jedoch schmerzhaft. Deshalb habe ich dieses Skript geschrieben: Jetzt muss ich nur noch die Tabelleninformationen als CSV exportieren und kann sie direkt konvertieren, ohne selbst viele Tags eingeben zu müssen. Aus diesem Grund gibt es keine HTML- und Body-Tags: Die erstellten Tabellen sollten keine separaten HTML-Dokumente sein, sondern Teile eines einzelnen großen HTML-Dokuments.
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();
}
}
}
So rufen Sie das Programm auf:
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>
Antworten
Gute Implementierung, finde meine Vorschläge inline.
kann sauberer geschrieben werden?
- Die Klasse
java.nio.file.Filesverfügt über einige praktische Methoden, die Sie verwenden können:
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
- Ziehen Sie in Betracht, eine Konstante für das Trennzeichen zu erstellen. Einige CSV-Dateien werden durch
;Werte begrenzt, die Kommas usw. enthalten.
public static final String DELIMITER_CHAR=",";
- Geben Sie eine Benutzernachricht ein und beenden Sie den Vorgang im Falle einer E / A-Ausnahme, zum Beispiel:
} catch (IOException e) {
System.out.println("Error reading input file: "+e.getMessage());
System.exit(1);
}
- Kapselung der Logik zum Konvertieren der Zeilen in eine Methode, damit das Testen und Wiederverwenden einfacher ist. Zum Beispiel:
public class CsvToHtmlTable{
public static List<String> convert(List<String> lines){/**/}
public static void main(String[] args){/**/}
}
Können Sie vielleicht die Leistung verbessern?
Die Grenze dieser Implementierung ist die Speicherbeschränkung. Wenn die Eingabedatei groß ist, passt möglicherweise nicht die gesamte Datei in den verfügbaren Speicher.
Könnte nicht Ihr Fall sein, aber wenn Sie große Dateien verarbeiten müssen, sollten Sie die Datei Zeile für Zeile lesen und schreiben.
Gibt es vielleicht irgendwelche Fehler?
- Überprüfen Sie, ob die Eingabedatei leer ist, andernfalls
lines.set(0,..)schlägt dies fehl - Wie bei @ Doi9t erwähnt, muss die Eingabevalidierungslogik berücksichtigen, wenn keine Argumente vorhanden sind, eins, zwei oder mehr.
CSVReader
Das Lesen einer CSV-Datei kann eine komplexe Aufgabe sein. Während viele CSV-Dateien nur durch Kommas getrennte Werte sind, wird ein Wert, der ein Komma enthält, von doppelten Anführungszeichen umgeben. Wenn der Wert doppelte Anführungszeichen enthält, werden die doppelten Anführungszeichen selbst verdoppelt.
Um diese mehr als nur einfache CSV-Dateien zu verarbeiten, sollten Sie wirklich eine CSV-Bibliothek wie OpenCSV (com.opencsv: opencsv: 5.0) oder Apache Commons CSV (org.apache.commons: commons-csv: 1.7) verwenden.
HTML
Gültiges HTML
Ihr Code schreibt im Wesentlichen nur <table>...table data...</table>. Dies ist kein richtiger HTML-Code. Es fehlen <html>...</html>Tags im gesamten Dokument und <body>...</body>im Inhalt. Du solltest wohl auch eine haben <head>...</head>, vielleicht mit einer schönen <title>...</title>.
Flucht
Wenn Ihre CSV-Daten Sonderzeichen wie <, >und enthalten &, müssen Sie diese wirklich in der generierten HTML-Tabelle maskieren.
Tabellenüberschriften
Es sieht so aus, als ob die erste Zeile Ihrer Tabelle Überschriften enthält, keine Daten. Die erste Tabellenzeile sollte wahrscheinlich mit <th>...</th>Tags anstelle von <td>...</td>Tags formatiert sein .
Zeile für Zeile Verarbeitung
Sie lesen die gesamte CSV-Datei in den Speicher, und erst wenn sie vollständig geladen wurde, schreiben Sie sie wieder als HTML aus. Dies ist sehr speicherintensiv, insbesondere wenn die CSV-Datei sehr groß ist!
Stattdessen könnten Sie:
- Öffnen Sie die CSV
- Öffnen Sie die HTML-Datei
- Schreiben Sie den HTML-Prolog
- für jede aus der CSV-Datei gelesene Zeile:
- Formatieren und Schreiben einer Zeile in eine HTML-Datei
- HTML-Epilog schreiben
Ungetestet, Codierung von der Hüfte aus, ohne das Zitieren in CSV zu handhaben oder HTML-Entitäten in der Ausgabe zu umgehen:
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
Möglicherweise möchten Sie einen CSV-zu-XML-Übersetzer erstellen.
Ihre XML-Ausgabe könnte folgendermaßen aussehen:
<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>
Und dann könnten Sie ein XSLT-Stylesheet verwenden , um das XML in HTML zu übersetzen, möglicherweise in einem Browser, ohne jemals das HTML in eine Datei zu schreiben.
Möglich NullPointerExceptionbei Linieif (args[0].equals...
Bitte überprüfen Sie die Eingabegröße argsund nullifyingbevor Sie fortfahren, um auf einen Index / ein Element zuzugreifen.
Ja, das argskönnte sein null, wie von einer anderen geladenen Klasse aufgerufen. Oder leer, wenn der Benutzer vergisst, das einzustellen args.
Pufferdatei
Ich denke, das Zwischenspeichern der gesamten Datei im Speicher und das anschließende Verarbeiten ist eine gute Idee für Ihren Fall, da Sie jede gelesene Zeile einfach verarbeiten, schreiben und mit der nächsten Zeile fortfahren können. (als von AJNeufeld erwähnte zeilenweise Verarbeitung )
Aufteilung der gebrochenen Spalte (Trennzeichen)
Grundsätzlich ist das Aufteilen der Spaltendaten mit lines.get(i).replaceAll(",",...)unterbrochen, da die Daten selbst ,als Inhalt vorliegen würden .
Wenn man eine Zeile betrachtet, Porsche,"991,991.2,992",70in der Ihr Code (und sogar der von AJNeufeld bereitgestellte) fehlschlägt, da 991,991.2,992es sich um einen Wert handelt und diese ""dem Parser mitteilen sollen, dass Escape- Daten voraus sind.
Ich persönlich schlage daher vor, einen char-by-char-Analyseprozess durchzuführen, bei dem Sie jedes ,als Trennzeichen überspringen können , wenn Sie eine Öffnung "bis zum Endpaar erreichen ".
Unerwartete Zeichen
Erwägen Sie auch, unerwartete Zeichen zu bestätigen, zu überspringen oder zu konvertieren. Konvertieren Sie beispielsweise ein NULL( \0) Zeichen in 0x00oder zeigen Sie die Warnung an und überspringen Sie sie.
Dateien vergessen
Ich schlage vor, Ihre App nicht zu sperren, um nur aus Dateien zu lesen und in diesen zu speichern. Viele Male STDINund STDOUTsind willkommenere Wege.
Ich schlage vor, sowohl von einer Datei als auch von zu unterstützen STDIN. Verwenden Sie beispielsweise "Muss" -finfür eine Dateieingabe im Argument oder -stdinzum Informieren des gelesenen Tools STDIN.
Dateien überprüfen
Das Überprüfen von Dateien (sowohl ein- als auch aus) vor dem Verarbeiten der Datei ist ebenfalls großartig. Um sicherzustellen, dass sie zugänglich sind.
Behauptung
Das Bereinigen (oder Auffordern / Einstellen) des Ergebnisses, während während des Vorgangs eine unerwartete E / A-Ausnahme auftritt, kann ebenfalls gut sein.
Ich hoffe es hilft.