CSV'den HTML'ye Dönüştürücü
Bir CSV Dosyasını HTML Tablosuna dönüştüren küçük bir program yazdım. Benim amaçlarım için çalışıyor. Ama kodumda daha temiz yazılabilecek kısımlar var mı? Belki performansı iyileştirebilir misin? Herhangi bir hata olabilir mi? Böcek aradım ve neyse ki bulamadım.
Postscript
Belki de bazı arka plan bilgileri vermeliydim: HTML belgesi olarak yazdığım bir veritabanı belgeleri üzerinde çalışıyorum çünkü Word belgelerini sevmiyorum. Ancak, düzinelerce etiket içeren sütunların tablo şeklinde bir açıklamasını oluşturmak zahmetlidir. Bu yüzden bu komut dosyasını yazdım: Şimdi sadece tablo bilgilerini CSV olarak dışa aktarmam gerekiyor ve birçok etiket girmek zorunda kalmadan doğrudan dönüştürebiliyorum. HTML ve gövde etiketi olmamasının nedeni budur: Oluşturulan tablolar ayrı HTML belgeleri değil, tek, büyük bir HTML belgesinin parçaları olmalıdır.
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();
}
}
}
Program nasıl aranır:
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>
Yanıtlar
Güzel uygulama, önerilerimi satır içi olarak bulun.
daha temiz yazılabilir mi?
- Sınıfın
java.nio.file.Fileskullanabileceğiniz birkaç kullanışlı yöntemi vardır:
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
- Sınırlayıcı karakter için bir sabit oluşturmayı düşünün. Bazı CSV dosyaları,
;virgül vb. İçeren değerleri işlemek için ile sınırlandırılmıştır :
public static final String DELIMITER_CHAR=",";
- G / Ç İstisnası durumunda bir kullanıcı mesajı sağlayın ve çıkın, örneğin:
} catch (IOException e) {
System.out.println("Error reading input file: "+e.getMessage());
System.exit(1);
}
- Çizgileri bir yönteme dönüştürmek için mantığı kapsülleyin, böylece test edilmesi ve yeniden kullanılması daha kolay olur. Örneğin:
public class CsvToHtmlTable{
public static List<String> convert(List<String> lines){/**/}
public static void main(String[] args){/**/}
}
Belki performansı iyileştirebilir misin?
Bu uygulamanın sınırı bellek kısıtlamasıdır. Girdi dosyası büyükse, dosyanın tamamı kullanılabilir belleğe sığmayabilir.
Sizin durumunuz olmayabilir, ancak büyük dosyaları işlemeniz gerekiyorsa, dosyayı satır satır okuyup yazmayı düşünün.
Herhangi bir hata olabilir mi?
- Giriş dosyasının boş olup olmadığını kontrol edin, aksi takdirde
lines.set(0,..)başarısız olur - @ Doi9t'un bahsettiği gibi, girdi doğrulama mantığının bir, iki veya daha fazla argüman olmadığında dikkate alınması gerekir.
CSVReader
Bir CSV dosyasını okumak karmaşık bir görev olabilir. Birçok CSV dosyası virgülle ayrılmış değerler olsa da, bir değer virgül içeriyorsa, çift tırnak içine alınır ve değer çift tırnak içeriyorsa, çift tırnaklar iki katına çıkar.
Bunları basit bir CSV dosyalarından daha fazlasını işlemek için, OpenCSV (com.opencsv: opencsv: 5.0) veya Apache Commons CSV (org.apache.commons: commons-csv: 1.7) gibi bir CSV kitaplığı kullanmalısınız .
HTML
Geçerli HTML
Kodunuz aslında sadece yazıyor <table>...table data...</table>. Bu uygun HTML değil. <html>...</html>Belgenin tamamında ve <body>...</body>içeriğin etrafında etiketler eksik . Muhtemelen bir <head>...</head>, belki de bir güzel ile almalısın <title>...</title>.
Kaçan
CSV veri özel karakterler içeriyorsa, gibi <, >ve &, gerçekten oluşturulan HTML tabloda kaçmak gerekir.
Tablo Başlıkları
Görünüşe göre tablonuzun ilk satırı veri değil, başlık içeriyor. İlk tablo satırı muhtemelen <th>...</th>etiketler yerine etiketlerle biçimlendirilmelidir <td>...</td>.
Satır satır işleme
CSV dosyasının tamamını belleğe okuyorsunuz ve yalnızca tamamı yüklendiğinde onu HTML olarak geri yazıyorsunuz. Bu, özellikle CSV dosyası çok büyükse bellek yoğun bir işlemdir!
Bunun yerine şunları yapabilirsiniz:
- CSV'yi aç
- HTML dosyasını aç
- HTML prologunu yaz
- CSV dosyasından okunan her satır için:
- Biçimlendir ve HTML dosyasına satır yaz
- HTML epilog yaz
Test edilmemiş, en sondan kodlama, CSV'de alıntı yapmadan veya çıktıdaki herhangi bir HTML öğesinden kaçmadan:
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 ve XSLT
CSV'den XML'e çevirici oluşturmayı düşünebilirsiniz.
XML çıktınız şöyle görünebilir:
<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>
Ve sonra , muhtemelen HTML'yi bir dosyaya yazmadan bir tarayıcıda, XML'i HTML'ye çevirmek için bir XSLT Stil Sayfası kullanabilirsiniz .
NullPointerExceptionHatta mümkünif (args[0].equals...
Lütfen giriş argsboyutunu kontrol nullifyingedin ve herhangi bir dizine / öğeye erişmeden önce.
Evet, bu başka bir yüklü sınıf tarafından çağrıldığı gibi argsolabilir null. Veya kullanıcı args.
Arabelleğe Alınan Dosya
Bence tüm dosyayı bellekte önbelleğe almak ve sonra onu işlemek sizin durumunuz için iyi bir fikirdir, okuduğunuz her satırı basitçe işleyebilir, yazabilir ve sonraki satıra geçebilirsiniz. ( AJNeufeld tarafından belirtilen Satır İşlemi gibi )
Kırık Sütun (sınırlayıcı) Bölme
Temel olarak, lines.get(i).replaceAll(",",...)verilerin kendisi ,içeriğe sahip olacağından , sütun verilerini kullanarak bölmek bozulur .
Bir satırı Porsche,"991,991.2,992",70, kodunuzun (ve hatta AJNeufeld tarafından sağlananın) başarısız olacağı bir yer olarak düşünürsek, çünkü 991,991.2,992tek bir değerdir ve ""bunlar ayrıştırıcıya kaçan verilerin önde olduğunu söylemek içindir.
Bu yüzden şahsen, bitiş çiftine kadar ,bir açıklığa ulaştığınızda herhangi birini sınırlayıcı olarak atlamanıza izin veren bir karakter ayrıştırma işlemine gitmenizi öneririm .""
Beklenmeyen Karakterler
Ayrıca beklenmedik karakterleri öne sürmeyi, atlamayı veya dönüştürmeyi düşünür. Örneğin bir NULL( \0) karakterini 0x00uyarıya dönüştürmek veya göstermek ve atlamak.
Dosyaları Unut
Sadece dosyalardan okumak ve dosyalara kaydetmek için uygulamanızı kilitlememenizi öneririm. Çoğu zaman STDINve STDOUTdaha hoş karşılanan yollar.
Hem bir dosyadan hem de STDIN. Örneğin, -finargümanda bir dosya girdisi için set -stdinetmek zorunda veya araca okuma bilgisi vermek için kullanma STDIN.
Dosyaları Kontrol Etme
Dosyayı işlemeden önce dosyaları kontrol etmek (hem içeri / dışarı) da harika olacaktır. Erişilebilir olduklarından emin olmak için.
İddia
İşlem sırasında beklenmedik bir GÇ istisnası varken sonucu temizlemek (veya istenir / ayarlanabilir) de iyi olabilir.
Umarım yardımcı olur.