Convertitore da CSV a HTML
Ho scritto un programmino che converte un file CSV in una tabella HTML. Funziona per i miei scopi. Ma ci sono parti nel mio codice che possono essere scritte più pulite? Puoi migliorare forse le prestazioni? Ci sono forse bug? Ho cercato bug e fortunatamente non ne ho trovati.
Post scriptum
Forse avrei dovuto fornire alcune informazioni di base: sto lavorando su una documentazione di database che sto scrivendo come documento HTML, perché non mi piacciono i documenti di Word. Tuttavia, la creazione di una descrizione tabulare delle colonne con dozzine di tag è dolorosa. Ecco perché ho scritto questo script: ora devo solo esportare le informazioni della tabella come CSV e posso convertirle direttamente senza dover inserire molti tag da solo. Questo è il motivo per cui non sono presenti tag HTML e body: le tabelle create non devono essere documenti HTML separati, ma parti di un unico documento HTML di grandi dimensioni.
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();
}
}
}
Come chiamare il programma:
java CsvToHtmlTable ExampleInput.csv ExampleOutput.html
EsempioInput.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>
Risposte
Bella implementazione, trova i miei suggerimenti in linea.
si può scrivere più pulito?
- La classe
java.nio.file.Filesha un paio di metodi utili che puoi usare:
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
- Considera l'idea di creare una costante per il carattere delimitatore. Alcuni file CSV sono delimitati da
;per gestire i valori contenenti virgole, ecc .:
public static final String DELIMITER_CHAR=",";
- Fornisci un messaggio utente ed esci in caso di eccezione I / O, ad esempio:
} catch (IOException e) {
System.out.println("Error reading input file: "+e.getMessage());
System.exit(1);
}
- Incapsula la logica per convertire le linee in un metodo, in modo che sia più facile da testare e riutilizzare. Per esempio:
public class CsvToHtmlTable{
public static List<String> convert(List<String> lines){/**/}
public static void main(String[] args){/**/}
}
Puoi migliorare forse le prestazioni?
Il limite di questa implementazione è il vincolo di memoria. Se il file di input è di grandi dimensioni, l'intero file potrebbe non rientrare nella memoria disponibile.
Potrebbe non essere il tuo caso, ma se hai bisogno di gestire file di grandi dimensioni, valuta la possibilità di leggere e scrivere il file riga per riga.
Ci sono forse bug?
- Controlla se il file di input è vuoto, altrimenti
lines.set(0,..)fallisce - Come menzionato da @ Doi9t, la logica di convalida dell'input deve essere considerata quando non ci sono argomenti, uno, due o più.
CSVReader
La lettura di un file CSV può essere un'attività complessa. Sebbene molti file CSV siano solo valori separati da virgole, se un valore contiene una virgola, sarebbe racchiuso tra virgolette doppie e se il valore contiene virgolette doppie, le virgolette stesse vengono raddoppiate.
Per gestirli più di un semplice file CSV, dovresti davvero usare una libreria CSV, come OpenCSV (com.opencsv: opencsv: 5.0) o Apache Commons CSV (org.apache.commons: commons-csv: 1.7).
HTML
HTML valido
Il tuo codice essenzialmente scrive solo <table>...table data...</table>. Questo non è HTML corretto. Ti mancano i <html>...</html>tag in tutto il documento e <body>...</body>intorno al contenuto. Probabilmente dovresti anche avere un <head>...</head>, forse con un bel <title>...</title>.
Fuggire
Se i dati CSV contiene caratteri speciali, come <, >e &, si deve davvero li fuggire nella tabella HTML generato.
Intestazioni tabella
Sembra che la prima riga della tabella contenga intestazioni, non dati. La prima riga della tabella dovrebbe probabilmente essere formattata con <th>...</th>tag invece che con <td>...</td>tag.
Elaborazione riga per riga
Stai leggendo l'intero file CSV in memoria e solo quando è stato caricato nella sua interezza lo riscrivi come HTML. Questo richiede molta memoria, soprattutto se il file CSV è enorme!
Invece, potresti:
- apri il CSV
- apri il file HTML
- scrivi il prologo HTML
- per ogni riga letta dal file CSV:
- formattare e scrivere la riga nel file HTML
- scrivi epilogo HTML
Non testato, codifica dall'anca, senza gestire le citazioni in CSV o l'escape di qualsiasi entità HTML nell'output:
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 e XSLT
Potresti prendere in considerazione la creazione di un traduttore da CSV a XML.
Il tuo output XML potrebbe essere simile a:
<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>
E poi potresti usare un foglio di stile XSLT per tradurre l'XML in HTML, possibilmente in un browser senza mai scrivere l'HTML su un file.
Possibile NullPointerExceptionin lineaif (args[0].equals...
Si prega di controllare la argsdimensione di input e nullifyingprima di procedere per accedere a qualsiasi indice / elemento.
Sì, argspotrebbe essere null, come chiamato da un'altra classe caricata. O vuoto, se l'utente dimentica di impostare il file args.
File di buffering
Penso che memorizzare nella cache l'intero file in memoria e poi elaborarlo sia una buona idea per il tuo caso, poiché ogni riga che leggi, potresti semplicemente elaborarla e scriverla e procedere con la riga successiva. (come Elaborazione riga per riga menzionata da AJNeufeld)
Divisione colonna spezzata (delimitatore)
Fondamentalmente, la divisione dei dati delle colonne utilizzando lines.get(i).replaceAll(",",...)è interrotta, poiché i dati stessi avrebbero ,come contenuto.
Considerando una riga come Porsche,"991,991.2,992",70dove il tuo codice (e anche quello fornito da AJNeufeld) fallirà, poiché 991,991.2,992è un valore, e quelli ""sono lì per dire al parser, i dati di escape sono avanti.
Quindi, personalmente, suggerisco di utilizzare un processo di analisi carattere per carattere, che ti consente di saltare qualsiasi ,delimitatore quando raggiungi un'apertura "fino alla sua "coppia finale .
Chars inaspettati
Considerando anche di affermare, saltare o convertire qualsiasi carattere imprevisto. Ad esempio, convertire un carattere NULL( \0) in 0x00o mostrare l'avviso e saltarlo.
Dimentica i file
Suggerisco di non bloccare la tua app per leggere solo dai file e salvarli. Molte volte STDINe STDOUTsono modi più graditi.
Suggerisco di supportare sia da un file che da STDIN. Ad esempio, utilizzare deve impostare -finper un file-input in argomento, o -stdinper informare lo strumento letto da STDIN.
Controllo dei file
Anche il controllo dei file (sia in entrata che in uscita) prima di elaborare il file sarà fantastico. Per assicurarti che siano accessibili.
Asserzione
Pulire (o richiedere / impostare) il risultato, anche se c'è un'eccezione IO imprevista durante il processo potrebbe essere buono.
Spero che sia d'aiuto.