Подтвердить что ты не робот

Как Java разрешает относительный путь в новом файле()?

Я пытаюсь понять, как Java разрешает относительный путь при создании объекта File.

Используемая ОС: Windows

Для нижеприведенного фрагмента я получаю IOException, поскольку он не может найти путь:

@Test
public void testPathConversion() {
        File f = new File("test/test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());    
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
}

Мое понимание здесь: Java рассматривает путь, указанный как абсолютный, и возвращает ошибку, когда путь не существует. Так что это имеет смысл.

Когда я обновляю приведенный выше код для использования относительного пути:

@Test
    public void testPathConversion() {
        File f = new File("test/../test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());    
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }    
    }

Создает новый файл и предоставляет следующий результат:

test\..\test.txt
C:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt

В этом случае мое предположение, даже если указанный путь не существует, поскольку путь содержит "/../", java рассматривает это как относительный путь и создает файл в user.dir. Таким образом, это также имеет смысл.

Но если я обновляю относительный путь, как показано ниже:

   @Test
    public void testPathConversion() {
        File f = new File("test/../../test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Затем я получаю IOException: доступ запрещен.

Мои вопросы:

  • Почему "test/../test.txt" рассматривается как относительный путь и создает файл в "user.dir", но "test/../../test.txt" возвращает ошибку? Где он пытается создать файл для пути "test/../../test.txt"?
  • Если указанный относительный путь не найден, файл создается в user.dir. Итак, мне кажется, что следующие два сценария делают одно и то же:

    //scenario 1
    File f = new File("test/../test.txt");
    f.createNewFile();
    
    //scenario 2
    File f = new File("test.txt");
    f.createNewFile();
    

Итак, существует ли реальный случай, когда можно использовать сценарий 1 вместо сценария 2?

Я полагаю, что я упускаю что-то очевидное здесь или принципиально неправильно понял относительные пути. Я просмотрел документы Java для файла, и я не могу найти объяснения этого. В Qaru имеется довольно много вопросов относительно относительных путей, но те, которые я искал, касались конкретных сценариев, а не точно, как разрешены относительные пути.

Будет здорово, если кто-нибудь сможет объяснить мне, как это работает или указывать на некоторые связанные ссылки?

4b9b3361

Ответ 1

Существует концепция working directory.
Этот каталог представлен . (точка).
В относительных путях все остальное относительно этого.

Просто поставьте . (рабочий каталог), где вы запускаете свою программу.
В некоторых случаях рабочий каталог может быть изменен, но в целом это что представляет точка. Я думаю, что это C:\JavaForTesters\ в вашем случае.

Итак test\..\test.txt означает: подкаталог test
в моем рабочем каталоге, затем на один уровень вверх, затем на файл test.txt. Это в основном то же самое, что только test.txt.

Подробнее читайте здесь.

http://docs.oracle.com/javase/7/docs/api/java/io/File.html

http://docs.oracle.com/javase/tutorial/essential/io/pathOps.html

Ответ 2

Когда ваш путь начинается с корня dir i.e. C:\ в Windows или / в Unix или в пути ресурсов java, он считается абсолютным путем. Все остальное относительное, поэтому

new File("test.txt") is the same as new File("./test.txt")

new File("test/../test.txt") is the same as new File("./test/../test.txt")

Основное различие между getAbsolutePath и getCanonicalPath заключается в том, что первый объединяет родительский и дочерний пути, поэтому он может содержать точки: .. или .. getCanonicalPath всегда возвращает тот же путь для определенного файла.

Примечание: File.equals использует абстрактную форму пути (getAbsolutePath) для сравнения файлов, поэтому это означает, что два объекта File для одного и того же могут быть не равными и File небезопасны для использования в коллекциях например, Map или Set.

Ответ 3

Рабочий каталог является общей концепцией практически для всех операционных систем и языков программирования и т.д. Это каталог, в котором работает ваша программа. Обычно это (но не всегда, есть способы изменить его) в каталоге, в котором находится приложение.

Относительные пути - это те, которые начинаются без спецификатора диска. Поэтому в Linux они не начинаются с /, в Windows они не начинаются с C:\ и т.д. Они всегда начинаются с вашего рабочего каталога.

Абсолютные пути - это те, которые начинаются с спецификатора диска (или машины для сетевых путей). Они всегда идут от начала этого диска.

Ответ 4

Относительные пути лучше понять, если вы знаете, как работает Java.

При запуске программ на Java существует концепция рабочего каталога. Предполагая, что у вас есть класс, скажем, FileHelper который выполняет IO в разделе /User/home/Desktop/projectRoot/src/topLevelPackage/.

В зависимости от случая, когда вы вызываете java для запуска программы, у вас будет другой рабочий каталог. Если вы запустите свою программу изнутри и из среды IDE, скорее всего это будет projectRoot.

  • В этом случае $ projectRoot/src: java topLevelPackage.FileHelper будет src.

  • В этом случае $ projectRoot: java -cp src topLevelPackage.FileHelper будет projectRoot.

  • В этом случае $/User/home/Desktop: java -cp./projectRoot/src topLevelPackage.FileHelper будет Desktop.

(Assuming $ is your command prompt with standard Unix-like FileSystem. Similar correspondence/parallels with Windows system)

Таким образом, ваш относительный корень пути (.) Разрешает ваш рабочий каталог. Таким образом, чтобы лучше знать, где писать файлы, он сказал рассмотреть подход ниже.

package topLevelPackage

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

public class FileHelper {

    // Not full implementation, just barebone stub for path
    public void createLocalFile() {

        // Explicitly get hold of working directory
        String workingDir = System.getProperty("user.dir");

        Path filePath = Paths.get(workingDir+File.separator+"sampleFile.txt");

        // In case we need specific path, traverse that path, rather using . or .. 
        Path pathToProjectRoot = Paths.get(System.getProperty("user.home"), "Desktop", "projectRoot");

        System.out.println(filePath);
        System.out.println(pathToProjectRoot);

    }
}

Надеюсь это поможет.

Ответ 5

В окнах и Netbeans вы можете установить относительный путь как:

    new FileReader("src\\PACKAGE_NAME\\FILENAME");

В Linux и Netbeans вы можете установить относительный путь как:

    new FileReader("src/PACKAGE_NAME/FILENAME");

Если у вас есть код внутри Source Packages Я не знаю, одинаково ли это для затмения или другой среды IDE

Ответ 6

Только слегка связанный с вопросом, но попробуйте обернуть голову вокруг этого. Настолько неинтуитивный:

import java.nio.file.*;
class Main {
  public static void main(String[] args) {
    Path p1 = Paths.get("/personal/./photos/./readme.txt");
    Path p2 = Paths.get("/personal/index.html");
    Path p3 = p1.relativize(p2);
    System.out.println(p3); //prints  ../../../../index.html  !!
  }
}