Convertisseur CSV en HTML
J'ai écrit un petit programme qui convertit un fichier CSV en une table HTML. Cela fonctionne pour mes besoins. Mais y a-t-il des parties de mon code qui peuvent être écrites plus proprement? Pouvez-vous améliorer peut-être les performances? Y a-t-il peut-être des bugs? J'ai recherché des bugs et heureusement je n'en ai pas trouvé.
Postscript
J'aurais peut-être dû fournir quelques informations de base: je travaille sur une documentation de base de données que j'écris sous forme de document HTML, car je n'aime pas les documents Word. Cependant, créer une description tabulaire des colonnes avec des dizaines de balises est douloureux. C'est pourquoi j'ai écrit ce script: Maintenant, je n'ai plus qu'à exporter les informations de la table au format CSV et je peux les convertir directement sans avoir à saisir moi-même de nombreuses balises. C'est pourquoi il n'y a pas de balises HTML et de corps: les tableaux créés ne doivent pas être des documents HTML séparés, mais des parties d'un seul et grand document 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();
}
}
}
Comment appeler le programme:
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>
Réponses
Belle mise en œuvre, retrouvez mes suggestions en ligne.
peut être écrit plus propre?
- La classe
java.nio.file.Filesa quelques méthodes pratiques que vous pouvez utiliser:
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
- Pensez à créer une constante pour le caractère délimiteur. Certains fichiers CSV sont délimités par
;pour gérer les valeurs contenant des virgules, etc.:
public static final String DELIMITER_CHAR=",";
- Fournissez un message utilisateur et quittez en cas d'exception d'E / S, par exemple:
} catch (IOException e) {
System.out.println("Error reading input file: "+e.getMessage());
System.exit(1);
}
- Encapsulez la logique pour convertir les lignes en une méthode, afin qu'il soit plus facile de tester et de réutiliser. Par exemple:
public class CsvToHtmlTable{
public static List<String> convert(List<String> lines){/**/}
public static void main(String[] args){/**/}
}
Pouvez-vous améliorer peut-être les performances?
La limite de cette implémentation est la contrainte mémoire. Si le fichier d'entrée est volumineux, le fichier entier peut ne pas tenir dans la mémoire disponible.
Ce n'est peut-être pas votre cas, mais si vous devez gérer des fichiers volumineux, envisagez de lire et d'écrire le fichier ligne par ligne.
Y a-t-il peut-être des bugs?
- Vérifiez si le fichier d'entrée est vide, sinon
lines.set(0,..)échoue - Comme @ Doi9t l'a mentionné, la logique de validation d'entrée doit prendre en compte lorsqu'il n'y a pas d'arguments, un, deux ou plus.
CSVReader
La lecture d'un fichier CSV peut être une tâche complexe. Alors que de nombreux fichiers CSV ne sont que des valeurs séparées par des virgules, si une valeur contient une virgule, elle sera entourée de guillemets doubles, et si la valeur contient des guillemets doubles, les guillemets eux-mêmes sont doublés.
Pour gérer ceux-ci plus que de simples fichiers CSV, vous devriez vraiment utiliser une bibliothèque CSV, telle que OpenCSV (com.opencsv: opencsv: 5.0) ou Apache Commons CSV (org.apache.commons: commons-csv: 1.7).
HTML
HTML valide
Votre code écrit essentiellement <table>...table data...</table>. Ce n'est pas du bon HTML. Il vous manque des <html>...</html>balises autour du document entier et <body>...</body>autour du contenu. Vous devriez probablement aussi avoir un <head>...</head>, peut-être avec un joli <title>...</title>.
S'échapper
Si vos données CSV contiennent des caractères spéciaux, tels que <, >et &, vous devez vraiment les échapper dans le tableau HTML généré.
En-têtes de tableau
Il semble que la première ligne de votre tableau contienne des en-têtes, pas des données. La première ligne du tableau devrait probablement être formatée avec des <th>...</th>balises au lieu de <td>...</td>balises.
Traitement ligne par ligne
Vous lisez l'intégralité du fichier CSV en mémoire, et ce n'est que lorsqu'il a été chargé dans son intégralité que vous le réécrivez au format HTML. C'est très gourmand en mémoire, surtout si le fichier CSV est énorme!
Au lieu de cela, vous pouvez:
- ouvrir le CSV
- ouvrez le fichier HTML
- écrire le prologue HTML
- pour chaque ligne lue à partir du fichier CSV:
- formater et écrire la ligne dans un fichier HTML
- écrire un épilogue HTML
Non testé, codage de la hanche, sans gérer les guillemets en CSV ni échapper aux entités HTML en sortie:
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 et XSLT
Vous pouvez envisager de créer un traducteur CSV vers XML.
Votre sortie XML peut ressembler à ceci:
<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>
Et puis vous pouvez utiliser une feuille de style XSLT pour traduire le XML en HTML, éventuellement dans un navigateur sans jamais écrire le HTML dans un fichier.
Possible NullPointerExceptionen ligneif (args[0].equals...
Veuillez vérifier la argstaille d' entrée et nullifyingavant de continuer pour accéder à tout index / élément.
Oui, cela argspourrait être null, comme appelé par une autre classe chargée. Ou vide, si l'utilisateur oublie de définir le args.
Fichier tampon
Je pense que mettre en cache tout le fichier en mémoire, puis le traiter est une bonne idée pour votre cas, car chaque ligne que vous lisez, vous pouvez simplement la traiter, l'écrire et passer à la ligne suivante. (comme traitement ligne par ligne mentionné par AJNeufeld)
Fractionnement de colonne cassée (délimiteur)
Fondamentalement, le fractionnement des données des colonnes à l'aide lines.get(i).replaceAll(",",...)est rompu, car les données elles-mêmes auraient ,pour contenu.
Considérant une ligne comme Porsche,"991,991.2,992",70où votre code (et même celui fourni par AJNeufeld) échouera, car 991,991.2,992c'est une valeur, et celles-ci ""sont là pour dire à l'analyseur, les données échappées sont en avance.
Donc, personnellement, je suggère d'opter pour un processus d'analyse char par caractère, qui vous permet d'en ignorer un ,comme délimiteur lorsque vous atteignez une ouverture "jusqu'à sa "paire de fin .
Caractères inattendus
Envisage également d'affirmer, d'ignorer ou de convertir tout caractère inattendu. Par exemple, convertir un caractère NULL( \0) en 0x00ou afficher l'avertissement et l'ignorer.
Oubliez les fichiers
Je suggère de ne pas verrouiller votre application pour simplement lire des fichiers et les enregistrer. Plusieurs fois STDIN, et STDOUTsont des moyens plus bienvenus.
Je suggère de prendre en charge à la fois un fichier et STDIN. Par exemple, utilisez have to set -finpour une entrée de fichier en argument, ou -stdinpour informer l'outil de lecture STDIN.
Vérification des fichiers
Vérifier les fichiers (à la fois en entrée / en sortie) avant de traiter le fichier sera également très bien. Pour s'assurer qu'ils sont accessibles.
Affirmation
Nettoyer (ou demander / définir) le résultat, alors qu'il y a une exception d'E / S inattendue pendant le processus, pourrait également être bon.
J'espère que cela aide.