Konverter CSV ke HTML
Saya telah menulis sebuah program kecil yang mengubah CSV-File menjadi HTML-Table. Ini bekerja untuk tujuan saya. Tetapi apakah ada bagian dalam kode saya yang dapat ditulis lebih bersih? Bisakah Anda meningkatkan kinerja? Apakah mungkin ada bug? Saya mencari bug dan untungnya saya tidak menemukan beberapa.
Nota bene
Mungkin saya harus memberikan beberapa informasi latar belakang: Saya sedang mengerjakan dokumentasi database yang saya tulis sebagai dokumen HTML, karena saya tidak suka dokumen Word. Namun, membuat deskripsi tabel dari kolom dengan lusinan tag itu menyakitkan. Itulah mengapa saya menulis skrip ini: Sekarang saya hanya perlu mengekspor informasi tabel sebagai CSV dan dapat mengubahnya secara langsung tanpa harus memasukkan sendiri banyak tag. Inilah sebabnya mengapa tidak ada tag HTML dan badan: Tabel yang dibuat tidak boleh menjadi dokumen HTML terpisah, tetapi bagian dari satu dokumen HTML besar.
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();
}
}
}
Bagaimana memanggil program:
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>
Jawaban
Penerapan yang bagus, temukan saran saya sebaris.
bisa ditulis lebih bersih?
- Kelas
java.nio.file.Filesmemiliki beberapa metode praktis yang dapat Anda gunakan:
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
- Pertimbangkan untuk membuat konstanta untuk karakter pembatas. Beberapa file CSV dibatasi oleh
;untuk menangani nilai yang mengandung koma, dll .:
public static final String DELIMITER_CHAR=",";
- Berikan pesan pengguna dan keluar jika ada Pengecualian I / O, misalnya:
} catch (IOException e) {
System.out.println("Error reading input file: "+e.getMessage());
System.exit(1);
}
- Enkapsulasi logika untuk mengubah garis menjadi metode, sehingga lebih mudah untuk menguji dan menggunakan kembali. Sebagai contoh:
public class CsvToHtmlTable{
public static List<String> convert(List<String> lines){/**/}
public static void main(String[] args){/**/}
}
Bisakah Anda meningkatkan kinerja?
Batasan implementasi ini adalah batasan memori. Jika file masukan besar, seluruh file mungkin tidak muat di memori yang tersedia.
Mungkin bukan kasus Anda, tetapi jika Anda perlu menangani file besar, pertimbangkan membaca dan menulis file baris demi baris.
Apakah mungkin ada bug?
- Periksa apakah file input kosong, jika
lines.set(0,..)tidak gagal - Seperti yang disebutkan @ Doi9t, logika validasi input perlu dipertimbangkan ketika tidak ada argumen, satu, dua atau lebih.
CSVReader
Membaca file CSV bisa menjadi tugas yang rumit. Meskipun banyak file CSV hanya berupa nilai yang dipisahkan koma, jika nilai berisi koma, nilai tersebut akan diapit oleh tanda kutip ganda, dan jika nilai tersebut berisi tanda kutip ganda, tanda kutip ganda itu sendiri digandakan.
Untuk menangani ini lebih dari sekadar file CSV dasar, Anda benar-benar harus menggunakan pustaka CSV, seperti OpenCSV (com.opencsv: opencsv: 5.0) atau Apache Commons CSV (org.apache.commons: commons-csv: 1.7).
HTML
HTML yang valid
Kode Anda pada dasarnya hanya menulis <table>...table data...</table>. Ini bukan HTML yang benar. Anda kehilangan <html>...</html>tag di sekitar seluruh dokumen, dan di <body>...</body>sekitar konten. Anda mungkin juga harus memiliki <head>...</head>, mungkin dengan yang bagus <title>...</title>.
Lolos
Jika data yang CSV Anda berisi karakter khusus, seperti <, >, dan &, Anda benar-benar harus melarikan diri mereka dalam tabel HTML yang dihasilkan.
Judul Tabel
Sepertinya baris pertama tabel Anda berisi judul, bukan data. Baris tabel pertama mungkin harus diformat dengan <th>...</th>tag, bukan <td>...</td>tag.
Pemrosesan baris demi baris
Anda membaca seluruh file CSV ke dalam memori, dan hanya jika telah dimuat secara keseluruhan Anda dapat menuliskannya kembali sebagai HTML. Ini sangat menguras memori, terutama jika file CSV berukuran besar!
Sebaliknya, Anda dapat:
- buka CSV
- buka file HTML
- tulis prolog HTML
- untuk setiap baris dibaca dari file CSV:
- memformat dan menulis baris ke file HTML
- tulis epilog HTML
Belum teruji, membuat kode dari awal, tanpa menangani kutipan dalam CSV atau keluar dari entitas HTML apa pun dalam keluaran:
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
Anda mungkin ingin mempertimbangkan untuk membuat penerjemah CSV ke XML.
Output XML Anda mungkin terlihat seperti:
<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>
Dan kemudian Anda dapat menggunakan XSLT Stylesheet untuk menerjemahkan XML ke HTML, mungkin di browser tanpa pernah menulis HTML ke file.
Mungkin NullPointerExceptionsejalanif (args[0].equals...
Harap periksa argsukuran input dan nullifyingsebelum melanjutkan untuk mengakses indeks / item apa pun.
Ya, itu argsbisa jadi null, seperti yang dipanggil oleh kelas lain yang dimuat. Atau kosong, jika pengguna lupa menyetel args.
File Penyangga
Saya pikir menyimpan seluruh file dalam memori, dan kemudian memprosesnya adalah ide yang bagus untuk kasus Anda, karena setiap baris yang Anda baca, Anda cukup memproses, dan menulisnya, dan melanjutkan ke baris berikutnya. (seperti Line By Line Processing yang disebutkan oleh AJNeufeld)
Pemisahan Kolom Rusak (pembatas)
Pada dasarnya, pemisahan data kolom menggunakan lines.get(i).replaceAll(",",...)rusak, karena data itu sendiri akan memiliki ,konten.
Mempertimbangkan baris sebagai Porsche,"991,991.2,992",70tempat kode Anda (dan bahkan yang disediakan oleh AJNeufeld) akan gagal, karena 991,991.2,992adalah satu nilai, dan nilai ""tersebut ada untuk memberi tahu parser, data yang lolos ada di depan.
Jadi secara pribadi, saya sarankan untuk melakukan proses parsing char-by-char, yang memungkinkan Anda melewatkan apa pun ,sebagai pembatas ketika Anda mencapai pembukaan "hingga "pasangan akhirnya .
Karakter Tak Terduga
Juga mempertimbangkan untuk menegaskan, melewati, atau mengonversi karakter yang tidak terduga. Misalnya mengubah a NULL( \0) char menjadi 0x00atau menampilkan peringatan dan melewatkannya.
Lupakan File
Saya sarankan, untuk tidak mengunci aplikasi Anda hanya untuk membaca dari file, dan menyimpannya. Berkali-kali STDIN, dan STDOUTcara yang lebih diterima.
Saya menyarankan untuk mendukung dari file dan STDIN. Misalnya, gunakan harus disetel -finuntuk input file dalam argumen, atau -stdinuntuk menginformasikan alat yang dibaca STDIN.
Memeriksa File
Memeriksa file (baik masuk / keluar) sebelum memproses file juga akan bagus. Untuk memastikannya dapat diakses.
Tuntutan
Membersihkan (atau meminta / mengatur) hasilnya, sementara ada pengecualian IO yang tidak terduga selama proses bisa jadi bagus juga.
Semoga membantu.