2013-01-02 30 views
12

Khi một giá trị rỗng được bắt gặp trong một tên tệp trong java.io.File, ký tự đó và tất cả các ký tự sau khi bị bỏ qua, dẫn đến một số hành vi lạ trong File.exists().Các ký tự rỗng trong java.io.File có hợp lệ để kiểm tra tồn tại không?

Hành vi này có một số khía cạnh của java.io.File.exists() mà tôi đã bỏ lỡ không?

Ví dụ:

package os; 

import java.io.File; 
import java.io.IOException; 

public class FileNullCheck 
{ 
    public static void main(String[] args) 
    { 
     File tmp = new File("a.txt"); 
     try 
     { 
      tmp.createNewFile(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
      return; 
     } 

     String a = "a.txt"; 
     System.out.printf("a.txt exists: %b (len=%d)%n",new File(a).exists(),a.length()); 

     String anull = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00 }); 
     System.out.printf("a.txt (null) exists: %b (len=%d)%n",new File(anull).exists(),anull.length()); 

     String anullx = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00, 'x' }); 
     System.out.printf("a.txt (nullx) exists: %b (len=%d)%n",new File(anullx).exists(),anullx.length()); 
    } 
} 

Kết quả của hoạt động này.

 
a.txt exists: true (len=5) 
a.txt (null) exists: true (len=6) 
a.txt (nullx) exists: true (len=7) 

Hệ thống Linux có JVM sau.

 
Java(TM) SE Runtime Environment (build 1.7.0_10-b18) 
Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode) 

Hành vi có vẻ giống như C và chuỗi được sử dụng để xác thực tệp trên hệ thống tệp bị cắt ngắn tại giá trị rỗng.

Nhưng tôi mong đợi hành vi ở Java sẽ trả về false cho File.exists() về các tên tệp không hợp lệ này.

Cập nhật: 19 tháng 9 năm 2013

Java 1.7.0 cập nhật 40 đã cố định này như một phần của lỗi JDK-8014846 : File and other classes in java.io do not handle embedded nulls properly

+1

Đó là một sự tương tác thú vị với các API bản địa. Ít nhất nó có hoạt động không? I E. không mở các tập tin với tên sai làm việc là tốt? –

+0

Có, bạn thậm chí có thể mở đọc/ghi tệp bằng cách sử dụng tên tệp không hợp lệ. –

+0

Tôi muốn gọi đây là một tạo phẩm triển khai, có thể là một lỗi. Chắc chắn không phải thứ tôi muốn. Trong thực tế, U + 0000 là về nhân vật duy nhất mà tôi không bao giờ cho phép trong một tên tập tin (ngay cả khi hệ điều hành cơ bản sẽ cho phép nó, mà tôi nghi ngờ nhiều người làm). –

Trả lời

3

On RHEL dường như byte nul chấm dứt tên tập tin (như bạn có thể mong đợi trong C)

System.out.println("a exists " + new File("a").exists()); 
FileOutputStream fos = new FileOutputStream(new File("a\u0000aa")); 
fos.close(); 
System.out.println("a exists " + new File("a").exists()); 

in

a exists false 
a exists true 

Tôi nghi ngờ Java sẽ ngăn không cho bạn cố gắng sử dụng tên tệp với byte nul.

0

Vâng, đây là lần thử thứ 3 của tôi. Tôi đã kiểm tra mã của bạn dưới Windows (Win 7, JDK 7 64 bit). Nó gây ra kết quả tương tự:

a.txt exists: true (len=5) 
a.txt (null) exists: true (len=6) 
a.txt (nullx) exists: true (len=7) 

Trong nguồn java chúng ta có thể nhìn thấy, mà nó sử dụng native thi hành getBooleanAttributes(File f) phương pháp. Nó có nghĩa là JVM tương tác với các thư viện c/C++ của JVM. Trong trường hợp đó tất cả các chuỗi có ký hiệu 0x00 trong nó sẽ được diễn giải trong các thư viện như chuỗi chỉ trước biểu tượng 0x00 ('\ 0').

Giả định này có thể được kiểm tra như thế nào? Tôi đã thực hiện thí nghiệm đơn giản. Nếu giả định của tôi về việc cắt các chuỗi này bên trong thư viện OS là đúng, thì mã này:

String anull = new String(new byte[] { 'a',0x00 , '.', 't', 'x', 't', 0x00 }); 
    System.out.printf("a.txt (null) exists: %b (len=%d)%n",new File(anull).exists(),anull.length()); 

sẽ trả lại false.Và vâng, nó là như vậy:

a.txt (null) exists: false (len=7) 

UPD:

này:

String anull = new String(new byte[] { 'a',0x00 , '.', 't', 'x', 't', 0x00 }); 
new File(anull).createNewFile(); 

sẽ tạo ra file có tên chỉ a mà không cần bất kỳ phần mở rộng.

0

Chỉ được xác định bởi hệ điều hành và tệp hệ thống cơ bản. Khi bạn tạo File với một tên có chứa số không, tên tập tin này là không thay đổi trong quá trình thi của File:

String anull = new String(new byte[] {'a', 0x00, '.', 't', 'x', 't', 0x00}); 
System.out.println(anull); 
System.out.println(new File(anull).getPath()); 

Đầu ra là giống hệt nhau và chứa số không.

Khi File hoạt động với tệp, tệp này sử dụng hệ thống tệp (ví dụ: java.io.FileSystem), triển khai nào phụ thuộc vào hệ điều hành và JDK (đó là lớp nội bộ). Trong Windows JDK, hầu như tất cả các hàm đều có nguồn gốc, vì vậy trong trường hợp này, hành vi này được xác định bởi hệ điều hành bên dưới (hoặc các tệp JDK dll).

0

Nếu sử dụng JDK 1.7+ các java.nio.files.Paths.get (URI) có thể được sử dụng để kiểm tra Nul (có vẻ như)

Một sửa đổi để các cuộc thử nghiệm ban đầu tạo ra một ngoại lệ hữu ích

package os; 

import java.io.File; 
import java.io.IOException; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 

public class FileNullCheck 
{ 
    public static void main(String[] args) throws Exception 
    { 
     File tmp = new File("a.txt"); 
     try 
     { 
      tmp.createNewFile(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
      return; 
     } 

     String a = "a.txt"; 
     testExists("a.txt", a); 

     String anull = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00 }, "UTF-8"); 
     testExists("a.txt (null)", anull); 

     String anullx = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00, 'x' }, "UTF-8"); 
     testExists("a.txt (nullx)", anullx); 
    } 

    private static void testExists(String label, String filename) throws IOException 
    { 
     File file = new File(filename); 
     System.out.printf("%s exists: %b%n", label, file.exists()); 
     System.out.printf(" filename.length = %d%n", filename.length()); 
     Path path = Paths.get(file.toURI()); 
     boolean symlink = Files.isSymbolicLink(path); 
     System.out.printf(" nio issymlink = %b%n",symlink); 
    } 
} 

Kết quả trong đầu ra

 
a.txt exists: true 
    filename.length = 5 
    nio issymlink = false 
a.txt (null) exists: true 
    filename.length = 6 
Exception in thread "main" java.nio.file.InvalidPathException: Nul character not allowed: /home/joakim/code/Stackoverflow/a.txt 
    at sun.nio.fs.UnixPath.checkNotNul(UnixPath.java:93) 
    at sun.nio.fs.UnixPath.normalizeAndCheck(UnixPath.java:83) 
    at sun.nio.fs.UnixPath.(UnixPath.java:71) 
    at sun.nio.fs.UnixFileSystem.getPath(UnixFileSystem.java:281) 
    at java.io.File.toPath(File.java:2069) 
    at sun.nio.fs.UnixUriUtils.fromUri(UnixUriUtils.java:61) 
    at sun.nio.fs.UnixFileSystemProvider.getPath(UnixFileSystemProvider.java:97) 
    at java.nio.file.Paths.get(Paths.java:138) 
    at os.FileNullCheck.testExists(FileNullCheck.java:39) 
    at os.FileNullCheck.main(FileNullCheck.java:28) 

Các vấn đề liên quan