2010-05-04 37 views
6

Tôi có một servlet cần ghi ra các tệp có tên có thể định cấu hình người dùng. Tôi đang cố gắng sử dụng mã hóa URI để thoát khỏi các ký tự đặc biệt đúng cách, nhưng JRE dường như tự động chuyển đổi các dấu gạch chéo được mã hóa %2F thành các dấu tách đường dẫn.Tại sao Java tự động giải mã% 2F trong tên tệp được mã hóa URI?

Ví dụ:

File dir = new File("C:\Documents and Setting\username\temp"); 
String fn = "Top 1/2.pdf"; 
URI uri = new URI(dir.toURI().toASCIIString() + URLEncoder.encoder(fn, "ASCII").toString()); 
File out = new File(uri); 

System.out.println(dir.toURI().toASCIIString()); 
System.out.println(URLEncoder.encode(fn, "ASCII").toString()); 
System.out.println(uri.toASCIIString()); 
System.out.println(output.toURI().toASCIIString()); 

Đầu ra là:

file:/C:/Documents%20and%20Settings/username/temp/ 
Top+1%2F2.pdf 
file:/C:/Documents%20and%20Settings/username/temp/Top+1%2F2.pdf 
file:/C:/Documents%20and%20Settings/username/temp/Top+1/2.pdf 

Sau khi các đối tượng tập tin mới được khởi tạo, trình tự %2F được tự động chuyển thành một dấu gạch chéo và tôi kết thúc với một con đường không chính xác . Có ai biết cách thích hợp để tiếp cận vấn đề này?

Cốt lõi của vấn đề dường như là

uri.equals(new File(uri).toURI()) == FALSE 

khi có một %2F trong URI.

Tôi đang lập kế hoạch để chỉ sử dụng chuỗi URL được mã hóa đúng nguyên văn chứ không phải cố gắng sử dụng hàm tạo File(uri).

+0

Đó chắc chắn đúng để làm như vậy. Nếu bạn cần một nguyên văn '% 2F' trong tên tệp hơn nó phải được thoát đúng khi được sử dụng trong một URI:'% 252F' – Joey

+0

Tôi nghĩ bạn hiểu lầm. Tôi không muốn mã hóa '% 2F', tôi muốn mã hóa '/' để tôi có thể tạo tên tệp hợp pháp đại diện cho tên do người dùng chỉ định chứa dấu gạch chéo chuyển tiếp. – Lucas

+0

Không quan tâm: Tôi biết đây là các URI tệp, nhưng nếu chúng là các URI http thì máy chủ web không xử lý '% F2' và'/'giống nhau? Ngoài ra: Vì '/' không hợp lệ trong một tên tệp cửa sổ, nên một tệp URI dường như không có ý nghĩa, hoặc? – RoToRa

Trả lời

5

new File(URI) tạo tệp dựa trên đường dẫn như được thu thập bởi URI#getPath() thay vì bạn mong đợi là gì- URI#getRawPath(). Điều này trông giống như một tính năng "theo thiết kế".

Bạn có 2 lựa chọn:

  1. Run URLEncoder#encode() trên fn hai lần (lưu ý: encode(), không encoder()).
  2. Sử dụng new File(String) để thay thế.
+0

Làm cho tinh thần. Nó được ghi lại ở bất cứ nơi nào, hoặc nó được ngụ ý bởi lớp File đảm bảo rằng "new File (f.toURI()). Bằng (f.getAbsoluteFile())"? – Lucas

+0

@Lucas - nó không được ghi lại; xem câu trả lời của tôi –

+0

Đó, và cũng là mã nguồn :) – BalusC

2

Tôi nghĩ rằng @BalusC đã đóng đinh vấn đề trực tiếp trong mã của bạn. Tôi chỉ muốn chỉ ra một số issuse khác là

Các biểu thức dir.toURI().toASCIIString()URLEncoder.encoder(fn, "UTF-8").toString() thực sự làm những thứ khác biệt.

  • Thứ nhất, mã hóa URI dưới dạng chuỗi, áp dụng quy tắc mã hóa URI theo ngữ pháp URI. Vì vậy, ví dụ, một '/' trong thành phần đường dẫn sẽ không được mã hóa nhưng '/' trong thành phần truy vấn hoặc phân đoạn sẽ được mã hóa dưới dạng% 2F.

  • Cách thứ hai, mã hóa chuỗi fn áp dụng các quy tắc mã hóa mà không tham chiếu đến nội dung của chuỗi. lập bản đồ

Các File(URI) constructor của từ một tập tin URI đến một tập tin là system dependent and undocumented. Tôi hơi ngạc nhiên khi nó giải mã %2F, nhưng nó hoạt động như thế nào và @BalusC giải thích tại sao. Việc lấy đi là nó có khả năng có vấn đề khi sử dụng một cơ chế ("file:" URI) mà phụ thuộc hệ thống một cách rõ ràng.

Cuối cùng, kết hợp các chuỗi thành phần URI đó là sai.Nó phải là một trong hai

URI uri = new URI(
     dir.toURI().toString() + 
     URLEncoder.encoder(fn, "UTF-8").toString(); 

hoặc

URI uri = new URI(
     dir.toURI().toASCIIString() + 
     URLEncoder.encoder(fn, "ASCII").toString()); 
Các vấn đề liên quan