Tôi đang thử nghiệm với trường hợp cạnh mà chúng ta đang thấy trong quá trình sản xuất. Chúng tôi có một mô hình kinh doanh nơi khách hàng tạo tệp văn bản và sau đó FTP chúng vào máy chủ của chúng tôi. Chúng tôi nhập các tệp đó và xử lý chúng trên chương trình phụ trợ Java của chúng tôi (chạy trên các máy CentOS). Hầu hết (95% +) khách hàng của chúng tôi biết để tạo ra các tệp này trong UTF-8, đó là những gì chúng tôi muốn. Tuy nhiên chúng tôi có một vài khách hàng cứng đầu (nhưng các tài khoản lớn) tạo ra các tệp này trên máy Windows với bộ ký tự CP1252. Không có vấn đề mặc dù, chúng tôi đã cấu hình libs bên thứ 3 của chúng tôi (đó là những gì làm hầu hết các "chế biến" làm việc cho chúng tôi) để xử lý đầu vào trong bất kỳ ký tự thiết lập thông qua một số doo ma thuật doo.Java không thể xem tệp trên hệ thống tệp có chứa các ký tự không hợp lệ
Thỉnh thoảng, chúng tôi thấy một tập tin xuất hiện có ký tự UTF-8 bất hợp pháp (CP1252) trong tên của nó. Khi phần mềm của chúng tôi cố gắng đọc những tập tin từ máy chủ FTP các phương pháp thông thường của file nghẹn đọc và ném một FileNotFoundException
:
File f = getFileFromFTPServer();
FileReader fReader = new FileReader(f);
String line = fReader.readLine();
// ...etc.
Các trường hợp ngoại lệ giống như thế này:
java.io.FileNotFoundException: /path/to/file/some-text-blah?blah.xml (No such file or directory) at java.io.FileInputStream.open(Native Method) at
java.io.FileInputStream.(FileInputStream.java:120) at java.io.FileReader.(FileReader.java:55) at com.myorg.backend.app.InputFileProcessor.run(InputFileProcessor.java:60) at
java.lang.Thread.run(Thread.java:662)
Vì vậy, những gì tôi nghĩ đang xảy ra là bởi vì các tập tin tên chính nó chứa ký tự không hợp pháp, chúng tôi thậm chí không bao giờ thậm chí có thể đọc nó ở nơi đầu tiên. Nếu chúng ta có thể, thì bất kể nội dung của tập tin, phần mềm của chúng ta sẽ có thể xử lý nó một cách chính xác. Vì vậy, đây thực sự là một vấn đề với việc đọc các tên tập tin với các ký tự UTF-8 bất hợp pháp trong chúng. Là một trường hợp thử nghiệm, tôi đã tạo một "ứng dụng Java" rất đơn giản để triển khai trên một trong các máy chủ của chúng tôi và kiểm tra một số thứ (mã nguồn được cung cấp bên dưới). Sau đó tôi đăng nhập vào máy Windows và tạo một tệp thử nghiệm và đặt tên là test£.txt
. Chú ý ký tự sau "test" trong tên tập tin. Đây là Alt-0163. Tôi FTP này đến máy chủ của chúng tôi, và khi tôi chạy ls -ltr
trên thư mục mẹ của nó, tôi đã ngạc nhiên khi thấy nó được liệt kê là test?.txt
.
Trước khi tôi đi thêm nữa, đây là Java "ứng dụng" tôi đã viết để thử nghiệm/tái tạo vấn đề này:
public Driver {
public static void main(String[] args) {
Driver d = new Driver();
d.run(args[0]); // I know this is bad, but its fine for our purposes here
}
private void run(String fileName) {
InputStreamReader isr = null;
BufferedReader buffReader = null;
FileInputStream fis = null;
String firstLineOfFile = "default";
System.out.println("Processing " + fileName);
try {
System.out.println("Attempting UTF-8...");
fis = new FileInputStream(fileName);
isr = new InputStreamReader(fis, Charset.forName("UTF-8"));
buffReader = new BufferedReader(isr);
firstLineOfFile = buffReader.readLine();
System.out.println("UTF-8 worked and first line of file is : " + firstLineOfFile);
}
catch(IOException io1) {
// UTF-8 failed; try CP1252.
try {
System.out.println("UTF-8 failed. Attempting Windows-1252...(" + io1.getMessage() + ")");
fis = new FileInputStream(fileName);
// I've also tried variations "WINDOWS-1252", "Windows-1252", "CP1252", "Cp1252", "cp1252"
isr = new InputStreamReader(fis, Charset.forName("windows-1252"));
buffReader = new BufferedReader(isr);
firstLineOfFile = buffReader.readLine();
System.out.println("Windows-1252 worked and first line of file is : " + firstLineOfFile);
}
catch(IOException io2) {
// Both UTF-8 and CP1252 failed...
System.out.println("Both UTF-8 and Windows-1252 failed. Could not read file. (" + io2.getMessage() + ")");
}
}
}
}
Khi tôi chạy từ nhà ga (java -cp . com/Driver t*
), tôi nhận được kết quả như sau:
Processing test�.txt
Attempting UTF-8...
UTF-8 failed. Attempting Windows-1252...(test�.txt (No such file or directory))
Both UTF-8 and Windows-1252 failed. Could not read file.(test�.txt (No such file or directory))
test�.txt
?!?! Tôi đã làm một số nghiên cứu và thấy rằng "�" là ký tự thay thế Unicode \uFFFD
. Vì vậy, tôi đoán điều đang xảy ra là máy chủ CentOS FTP không biết cách xử lý Alt-0163 (£
) và do đó nó thay thế bằng \uFFFD
(�
). Nhưng tôi không hiểu tại sao ls -ltr
hiển thị một tệp có tên là test?.txt
...
Trong mọi trường hợp, dường như giải pháp là thêm một số logic tìm kiếm sự tồn tại của ký tự này trong tên tệp và nếu tìm thấy , đổi tên tệp thành một thứ khác (như có thể thực hiện một chuỗi replaceAll("\uFFFD", "_")
hoặc một cái gì đó tương tự) mà hệ thống có thể đọc và xử lý.
Vấn đề là Java thậm chí không xem tệp này trên hệ thống tệp. CentOS biết tập tin là có (test?.txt
), nhưng khi tập tin đó được truyền vào Java, Java diễn giải nó là test�.txt
và vì một số lý do No such file or directory
...
Tôi làm cách nào để có được Java để xem tệp này để tôi có thể thực hiện File::renameTo(String)
trên đó? Xin lỗi cho cốt truyện ở đây nhưng tôi cảm thấy nó có liên quan vì mọi chi tiết đều có trong kịch bản này. Cảm ơn trước!
để bạn không thể liệt kê các tệp trong thư mục, sau đó xem có "ký tự lẻ" trong tên của chúng và đổi tên chúng thành "dấu thời gian + random.something" với tệp.renameTo? –
@MarkusMikkolainen - bạn đang nói về việc này bằng tay? Nếu bạn không nói ngôn ngữ/kịch bản nào? – IAmYourFaja
Tôi khuyên bạn nên sử dụng đối tượng Tệp thay vì truyền tên tệp. mà có thể sẽ ngăn chặn bất kỳ tham nhũng tên tập tin. –