Java: несоответствия File.exists () при установке «user.dir» - PullRequest
9 голосов
/ 16 февраля 2010

JRE 6, в Windows XP.

Создание двух объектов File с разными конструкторами приводит к противоречивым результатам в методе File.exists().

Отказ от ответственности: приведенный ниже код является абстрактным, а не фактическим кодом. Я не верю, что это проблема File.separator вообще. Сначала я попросил получить ранние реакции, если я пропустил хорошо понятую проблему. Теперь кажется, что сброс системного свойства user.dir является одной из причин этой проблемы. Код ниже теперь воспроизводим и может использоваться как есть. Вы можете скопировать / вставить класс Java и попробовать его, он должен работать в соответствии с тем, что я перечислил в качестве результатов.

Установка:

Создание архитектуры папок C:\toto\tmp\sub.

Запустите следующий класс из любой папки, которая не содержит архитектуру подпапок tmp/sub.

Код:

public class TestFileExists {

    public static void main(String[] args) {

        System.setProperty("user.dir", "C:\\toto\\");

        File root = new File("tmp");

        File sub_a = new File(root, "sub");

        File sub_b = new File(root.getAbsolutePath()+"/sub");

        System.out.println("sub_a path ? "+sub_a.getAbsolutePath());
        System.out.println("sub_a exists ? "+sub_a.exists());
        System.out.println("sub_b path ? "+sub_b.getAbsolutePath());
        System.out.println("sub_b exists ? "+sub_b.exists());
        System.out.println("Path equals ? "+ (sub_a.getAbsolutePath().equals(sub_b.getAbsolutePath())));
        System.out.println("Obj equals ? "+ (sub_a.equals(sub_b)));

    }

}

Результат:

sub_a path ? C:\toto\tmp\sub
sub_a exists ? false
sub_b path ? C:\toto\tmp\sub
sub_b exists ? true
Path equals ? true
Obj equals ? false

Я не понимаю строки sub_a exists ? false, , и результат не согласуется с машиной к машине, ни с корневым начальным путем , и теперь результат согласуется с машиной к машине.

Теперь, если вы повторно выполните класс, вызвав java из командной строки, из папки, которая содержит архитектуру подпапок tmp/sub (например, если вы вызываете ее из D:\, имея D:\tmp\sub), вы будете получить ожидаемое:

sub_a path ? C:\toto\tmp\sub
sub_a exists ? true
sub_b path ? C:\toto\tmp\sub
sub_b exists ? true
Path equals ? true
Obj equals ? false

Но существование sub_a явно является ложным срабатыванием, поскольку оно проверяет наличие другой папки, отличной от той, которая описана getAbsolutePath().

Поэтому я сильно подозреваю, что File.exists() зависит от фактического пути выполнения Java, и что существование файла не согласуется с абсолютным путем, и exists() использует другой путь, чем системное свойство "user.dir", чтобы проверить файловая система.

Есть идеи, откуда возникла эта проблема?

Ответы [ 7 ]

10 голосов
/ 17 февраля 2010

Настройка user.dir не поддерживается. Его следует рассматривать только для чтения.

Например, оценка Ошибка 4117557 в параде Sun Bug содержит этот текст:

"user.dir", который инициализируется при запуске jvm, должен использоваться как Информативное / только для чтения системное свойство, попробуйте настроить его через командную строку -Duser.dir = xyz закончится зависимым от реализации / неуказанным поведением.

Хотя этот текст о настройке в командной строке, его установка с помощью setProperty(), скорее всего, также не определена.

Если вы можете воспроизвести проблему без , установив user.dir вручную, то вы обнаружили настоящую проблему.

2 голосов
/ 17 февраля 2010

Добавьте следующие строки в ваш тест:

System.out.println("sub_a = " + sub_a);
System.out.println("sub_b = " + sub_b);

Выводы:

1) sub_a - относительный путь, а sub_b - абсолютный.

2) exists() не использует абсолютный путь

3) установка переменной среды user.dir не меняет текущий каталог пользователя, используемый exists()

4) getAbsolutePath использует переменную user.dir вместо реального текущего каталога пользователя! По крайней мере, для Windows (см. Win32FileSystem.getuserPath). Это проблема! (Ошибка?)

1 голос
/ 16 февраля 2010

File может представлять абстрактный путь. Создание File для tmp и одного из абсолютного пути tmp не будет равно File объектам, хотя их абсолютные пути равны.

Я не совсем уверен в сценарии, где sub_a не будет существовать, но sub_b будет, но я сомневаюсь, что это проблема разделителя. Я подозреваю, что это как-то связано с этим заявлением из javadoc для File (File, String) :

каждая строка пути преобразуется в абстрактный путь, а дочерний абстрактный путь разрешается относительно родительского.

Я не знаю ситуации в файловых системах на основе Unix, где из /full/path/to будет существовать ./tmp/sub, но /full/path/to/tmp не будет.

Если проблема согласована между системами, ее можно понять более четко, если вывести больше данных о состоянии каждого File объекта, а не просто печатать сравнения.

0 голосов
/ 16 февраля 2010

Эти результаты должны быть детерминированными для всех машин. Позвольте мне разбить это на строку:

System.out.println("sub_a exists ? "+sub_a.exists());

Здесь вы спрашиваете, существует ли этот файл в файловой системе. Это должно всегда возвращать то же самое, предполагая, что файл существует.

System.out.println("sub_b exists ? "+sub_b.exists());

То же самое. Вы проверяете, существует ли этот файл на самом деле.

System.out.println("Path equals ? "+ (sub_a.getAbsolutePath().equals(sub_b.getAbsolutePath())));

Здесь вы видите, совпадает ли AbsolutePath .

System.out.println("Obj equals ? "+ (sub_a.equals(sub_b)));

И здесь вы выполняете сравнение объектов с помощью .equals (), которая изнутри вызовет класс FileSystem для сравнения () объектов path двух объектов, а не их AbsolutePath .

Скорее всего, неверный разделитель файлов. Попробуйте заменить File.separator в конструкции sub_b, например так:

File sub_b = new File(root.getAbsolutePath()+File.separator+"sub");
0 голосов
/ 16 февраля 2010

Это может быть проблема с разделителем файлов. В Windows стандартным разделителем файлов является обратная косая черта (\). Когда вы создаете sub_b, вы создаете имя пути (как String), которое содержит как косую черту, так и обратную косую черту. Система может запутаться в этом.

0 голосов
/ 16 февраля 2010

Я думаю, что это разделитель каталогов, поскольку Windows обычно использует обратную косую черту "\", а Linux использует обычную косую черту "/".

Попробуйте изменить строку на:

File sub_b = new File(root.getAbsolutePath() + System.getProperty("file.separator") + "sub");
0 голосов
/ 16 февраля 2010

В этой строке:

File sub_b = new File(root.getAbsolutePath()+"/sub");

Вы должны использовать константу File.separator (зависит от базовой системы), а не жестко заданный слеш.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...