2013-01-02 14 views
12

Po napotkaniu wartości pustej w nazwie pliku w java.io.File, ten znak i wszystkie znaki po nim są ignorowane, powodując dziwne zachowanie w File.exists().Czy są puste znaki w pliku java.io.File ważne, czy istnieje?

Czy to zachowanie, które przeoczyłem, to jakiś aspekt java.io.File.exists()?

przykład:

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()); 
    } 
} 

Wyniki prowadzenia tego.

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

System Linux ma następującą wirtualną maszynę wirtualną.

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

zachowanie wydaje się być C-jak i łańcuch używany do sprawdzania poprawności pliku w systemie plików jest obcięty na null.

Ale oczekiwałbym, że zachowanie w Javie zwróci false dla File.exists() na tych niepoprawnych nazwach plików.

Aktualizacja: 19 września 2013

Java 1.7.0 Aktualizacja 40 ustaliła to jako część bug JDK-8014846 : File and other classes in java.io do not handle embedded nulls properly

+1

To ciekawe interakcje z natywnym API. Czy to przynajmniej działa konsekwentnie? To znaczy. czy otwieranie plików o błędnych nazwach również działa? –

+0

Tak, można nawet otworzyć plik, używając niepoprawnych nazw plików. –

+0

Nazwałbym to artefaktem implementacji, prawdopodobnie błędem. Zdecydowanie nie jest to coś, na czym bym się opierał. W rzeczywistości U + 0000 jest jedyną postacią, której nigdy nie pozwoliłbym w nazwie pliku (nawet jeśli bazowy system operacyjny pozwoliłby na to, co wątpię w wiele). –

Odpowiedz

3

Na RHEL wydaje się, że bajt nul wypowie nazwę pliku (jak ty może oczekiwać w 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()); 

drukuje

a exists false 
a exists true 

Podejrzewam, że Java powinna uniemożliwić ci użycie nazwy pliku z nultem.

0

Cóż, to moja trzecia próba. Sprawdziłem twój kod pod Windows (Win 7, JDK 7 64 bit). To powoduje, że ten sam rezultat:

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

w źródłach java widać, że używa native realizację getBooleanAttributes(File f) metody. Oznacza to, że JVM współdziała z bibliotekami JVM c/C++. W takim przypadku wszystkie łańcuchy z symbolem 0x00 będą interpretowane w bibliotekach takich jak łańcuchy tylko przed symbolem 0x00 ("\ 0").

Jak to założenie można sprawdzić? Zrobiłem prosty eksperyment. Jeśli moje założenie o cięcie to ciągi wewnątrz bibliotek OS jest prawdą, to ten kod:

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()); 

powróci false.I tak, to jest tak:

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

UPD:

to:

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

utworzy plik o nazwie po prostu a bez rozszerzenia.

0

Jest określany tylko przez system operacyjny i system plików. Podczas tworzenia File z nazwą, która zawiera same zera, to nazwa pliku nie zmienia się w trakcie budowy z File:

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

Wyjście jest identyczny i zawiera zera.

Gdy File działa z plikami, używa systemu plików (np. java.io.FileSystem), którego implementacja zależy od systemu operacyjnego i JDK (jego klasy wewnętrznej). W systemie Windows JDK prawie wszystkie funkcje są natywne, więc w tym przypadku zachowanie to jest określane przez podstawowy system operacyjny (lub biblioteki DLL JDK).

0

przypadku korzystania JDK 1.7+ z java.nio.files.Paths.get (URI) może być wykorzystane do testowania Nul (wydaje)

Modyfikacja oryginalnych badań wytwarza użyteczną wyjątek

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); 
    } 
} 

Wyniki w wyjściu

 
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) 

Powiązane problemy