Công cụ chuyển đổi CSV sang HTML
Tôi đã viết một chương trình nhỏ chuyển đổi tệp CSV sang bảng HTML. Nó hoạt động cho các mục đích của tôi. Nhưng có những phần nào trong mã của tôi có thể được viết rõ ràng hơn không? Bạn có thể cải thiện hiệu suất có thể không? Có thể có bất kỳ lỗi? Tôi đã tìm kiếm lỗi và may mắn thay tôi đã không tìm thấy một số.
Tái bút
Có lẽ tôi nên cung cấp một số thông tin cơ bản: Tôi đang làm việc trên một tài liệu cơ sở dữ liệu mà tôi đang viết dưới dạng tài liệu HTML, bởi vì tôi không thích tài liệu Word. Tuy nhiên, việc tạo mô tả dạng bảng của các cột với hàng chục thẻ là một việc khó khăn. Đó là lý do tại sao tôi viết tập lệnh này: Bây giờ tôi chỉ phải xuất thông tin bảng dưới dạng CSV và có thể chuyển đổi trực tiếp mà không cần phải tự nhập nhiều thẻ. Đây là lý do tại sao không có HTML và thẻ nội dung: Các bảng được tạo không nên là các tài liệu HTML riêng biệt, mà là các phần của một tài liệu HTML lớn, duy nhất.
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();
}
}
}
Cách gọi chương trình:
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>
Trả lời
Triển khai tốt, tìm thấy các đề xuất của tôi nội tuyến.
có thể được viết sạch hơn?
- Lớp
java.nio.file.Filescó một số phương thức hữu ích mà bạn có thể sử dụng:
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
- Hãy xem xét để tạo một hằng số cho ký tự phân cách. Một số tệp CSV được phân cách bằng
;để xử lý các giá trị có chứa dấu phẩy, v.v.:
public static final String DELIMITER_CHAR=",";
- Cung cấp thông báo người dùng và thoát trong trường hợp I / O Exception, ví dụ:
} catch (IOException e) {
System.out.println("Error reading input file: "+e.getMessage());
System.exit(1);
}
- Đóng gói logic để chuyển đổi các dòng thành một phương thức, để việc kiểm tra và sử dụng lại dễ dàng hơn. Ví dụ:
public class CsvToHtmlTable{
public static List<String> convert(List<String> lines){/**/}
public static void main(String[] args){/**/}
}
Bạn có thể cải thiện hiệu suất có thể không?
Giới hạn của việc triển khai này là giới hạn bộ nhớ. Nếu tệp đầu vào lớn, toàn bộ tệp có thể không vừa trong bộ nhớ khả dụng.
Có thể không phải là trường hợp của bạn, nhưng nếu bạn cần xử lý các tệp lớn, hãy xem xét việc đọc và ghi từng dòng tệp.
Có thể có bất kỳ lỗi?
- Kiểm tra xem tệp đầu vào có trống không, nếu
lines.set(0,..)không sẽ không thành công - Như @ Doi9t đã đề cập, logic xác thực đầu vào cần phải xem xét khi không có đối số, một, hai hoặc nhiều hơn.
CSVReader
Đọc tệp CSV có thể là một nhiệm vụ phức tạp. Mặc dù nhiều tệp CSV chỉ là các giá trị được phân tách bằng dấu phẩy, nhưng nếu một giá trị chứa dấu phẩy, nó sẽ được bao quanh bởi dấu ngoặc kép và nếu giá trị chứa dấu ngoặc kép thì bản thân dấu ngoặc kép sẽ được nhân đôi.
Để xử lý những vấn đề này chỉ là tệp CSV cơ bản, bạn thực sự nên sử dụng thư viện CSV, chẳng hạn như OpenCSV (com.opencsv: opencsv: 5.0) hoặc Apache Commons CSV (org.apache.commons: commons-csv: 1.7).
HTML
HTML hợp lệ
Mã của bạn về cơ bản chỉ viết <table>...table data...</table>. Đây không phải là HTML thích hợp. Bạn đang thiếu <html>...</html>các thẻ xung quanh toàn bộ tài liệu và <body>...</body>xung quanh nội dung. Bạn có lẽ cũng nên có một <head>...</head>, có lẽ với một tốt đẹp <title>...</title>.
Bỏ trốn
Nếu dữ liệu CSV của bạn có chứa bất kỳ ký tự đặc biệt, giống như <, >và &, bạn thực sự phải thoát khỏi chúng trong bảng HTML được tạo.
Tiêu đề bảng
Có vẻ như dòng đầu tiên trong bảng của bạn chứa các tiêu đề, không phải dữ liệu. Hàng đầu tiên của bảng có lẽ nên được định dạng bằng <th>...</th>thẻ thay vì <td>...</td>thẻ.
Xử lý từng dòng
Bạn đang đọc toàn bộ tệp CSV vào bộ nhớ và chỉ khi nó đã được tải toàn bộ, bạn mới ghi nó ra giấy dưới dạng HTML. Điều này rất tốn bộ nhớ, đặc biệt nếu tệp CSV lớn!
Thay vào đó, bạn có thể:
- mở CSV
- mở tệp HTML
- viết phần mở đầu HTML
- cho mỗi dòng được đọc từ tệp CSV:
- định dạng và ghi dòng vào tệp HTML
- viết HTML epilog
Chưa được kiểm tra, mã hóa từ đầu, không xử lý trích dẫn trong CSV hoặc thoát bất kỳ thực thể HTML nào trong đầu ra:
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
Bạn có thể muốn xem xét việc tạo một trình dịch CSV sang XML.
Đầu ra XML của bạn có thể trông giống như sau:
<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>
Và sau đó, bạn có thể sử dụng Biểu định kiểu XSLT để dịch XML sang HTML, có thể trong trình duyệt mà không cần ghi HTML vào tệp.
Có thể NullPointerExceptionở hàngif (args[0].equals...
Vui lòng kiểm tra argskích thước đầu vào và nullifyingtrước khi tiếp tục truy cập bất kỳ chỉ mục / mục nào.
Có, điều đó argscó thể được null, như được gọi bởi một lớp được tải khác. Hoặc trống, nếu người dùng quên đặt args.
Tập tin đệm
Tôi nghĩ rằng lưu toàn bộ tệp vào bộ nhớ và sau đó xử lý nó là một ý tưởng hay cho trường hợp của bạn, vì mỗi dòng bạn đọc, bạn có thể chỉ cần xử lý và ghi nó, và tiếp tục cho dòng tiếp theo. (như Xử lý từng dòng được AJNeufeld đề cập)
Tách cột bị hỏng (dấu phân cách)
Về cơ bản, việc tách dữ liệu cột bằng cách sử dụng lines.get(i).replaceAll(",",...)bị hỏng, vì bản thân dữ liệu sẽ có ,nội dung.
Xem xét một dòng là Porsche,"991,991.2,992",70nơi mã của bạn (và thậm chí cả đoạn được cung cấp bởi AJNeufeld) sẽ không thành công, vì 991,991.2,992là một giá trị và những dòng ""đó ở đó để cho trình phân tích cú pháp biết, dữ liệu thoát đang ở phía trước.
Vì vậy, về mặt cá nhân, tôi khuyên bạn nên thực hiện quy trình phân tích cú pháp char-by-char, cho phép bạn bỏ qua bất kỳ ,dấu phân cách nào khi bạn đến phần mở đầu "cho đến "cặp kết thúc của nó .
Các chuỗi không mong đợi
Cũng đang xem xét xác nhận, bỏ qua hoặc chuyển đổi bất kỳ ký tự không mong muốn nào. Ví dụ: chuyển đổi một ký tự NULL( \0) thành 0x00hoặc hiển thị cảnh báo và bỏ qua nó.
Quên tệp
Tôi khuyên bạn không nên khóa ứng dụng của mình để chỉ đọc từ các tệp và lưu vào chúng. Nhiều lần STDIN, và STDOUTlà những cách được hoan nghênh hơn.
Tôi đề nghị hỗ trợ từ cả tệp và STDIN. Ví dụ: sử dụng phải đặt -fincho đầu vào tệp trong đối số hoặc -stdinđể thông báo cho công cụ đọc từ đó STDIN.
Kiểm tra tệp
Kiểm tra tệp (cả vào / ra) trước khi xử lý tệp cũng sẽ rất tuyệt. Để đảm bảo rằng chúng có thể truy cập được.
Quả quyết
Dọn dẹp (hoặc nhắc nhở / có thể thiết lập) kết quả, trong khi có một ngoại lệ IO không mong muốn trong quá trình cũng có thể tốt.
Hy vọng nó giúp.