Pertanyaan Bagaimana cara Java menyelesaikan path relatif di File baru ()?


Saya mencoba untuk memahami cara Java menyelesaikan path relatif di saat membuat File obyek.

OS yang digunakan: Windows

Untuk potongan di bawah ini, saya mendapatkan sebuah IOException karena tidak dapat menemukan jalur:

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

Pemahaman saya di sini adalah, Java memperlakukan jalur yang disediakan sebagai absolut dan mengembalikan kesalahan ketika jalur tidak ada. Jadi itu masuk akal.

Saat saya memperbarui kode di atas untuk menggunakan jalur relatif:

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

Ini menciptakan file baru dan menyediakan output di bawah ini:

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

Dalam hal ini, asumsi saya adalah, meskipun path yang disediakan tidak ada, karena path berisi "/../", java memperlakukan ini sebagai path relatif dan membuat file dalam user.dir. Jadi ini juga masuk akal.

Tetapi jika saya memperbarui jalur relatif seperti di bawah ini:

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

Lalu saya mendapatkan IOException: Akses ditolak.

Pertanyaan saya adalah:

  1. Mengapa "test/../test.txt" diperlakukan sebagai path relatif dan membuat file "user.dir" tapi"test/../../test.txt" mengembalikan kesalahan? Di mana ia mencoba untuk membuat file untuk jalan "test/../../test.txt"?
  2. Ketika path relatif tertentu tidak ditemukan, file tersebut tampaknya dibuat di user.dir. Jadi, tampaknya bagi saya bahwa dua skenario di bawah ini melakukan hal yang sama:

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

Jadi adakah kasus dunia nyata di mana orang akan menggunakan skenario 1 daripada skenario 2?

Saya kira saya kehilangan sesuatu yang jelas di sini atau memiliki jalur relatif yang secara fundamental disalahpahami. Saya pergi melalui Java docs for File dan saya tidak dapat menemukan penjelasan untuk ini. Ada beberapa pertanyaan yang diposting di Stack Overflow mengenai jalur relatif, tetapi yang saya cari adalah untuk skenario tertentu dan bukan tentang bagaimana jalan relatif diselesaikan.

Akan sangat bagus jika seseorang dapat menjelaskan kepada saya bagaimana ini bekerja atau menunjuk ke beberapa tautan terkait?


32
2018-01-11 10:08


asal


Jawaban:


Ada konsep a working directory.
Direktori ini diwakili oleh . (dot).
Di jalur relatif, semua hal lain relatif terhadapnya.

Sederhananya . (direktori kerja) adalah tempat Anda menjalankan program Anda.
Dalam beberapa kasus direktori kerja dapat diubah tetapi secara umum ini
  apa yang diwakili oleh titik. Saya pikir ini C:\JavaForTesters\ dalam kasusmu.

Begitu test\..\test.txt berarti: sub-direktori test 
di direktori kerja saya, lalu naik satu tingkat, lalu
mengajukan test.txt. Ini pada dasarnya sama saja test.txt.

Untuk lebih jelasnya, periksa di sini.

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

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


17
2018-01-11 10:13



Ketika jalan Anda dimulai dengan dir root, saya. C:\ di jendela atau / di Unix atau di jalur sumber daya java, itu dianggap sebagai jalur absolut. Yang lainnya relatif, jadi

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")

Perbedaan utama antara getAbsolutePath dan getCanonicalPath adalah bahwa yang pertama menggabungkan jalur orang tua dan anak, sehingga mungkin berisi titik-titik: .. atau .. getCanonicalPath akan selalu mengembalikan jalur yang sama untuk file tertentu.

catatan: File.equals menggunakan bentuk abstrak dari sebuah jalur (getAbsolutePath) untuk membandingkan file, jadi ini berarti dua File objek yang sama mungkin tidak sama dan Files tidak aman untuk digunakan dalam koleksi seperti Map atau Set.


8
2018-01-11 10:20



Direktori kerja adalah konsep umum di hampir semua sistem operasi dan bahasa program, dll. Ini adalah direktori tempat program Anda berjalan. Ini biasanya (tetapi tidak selalu, ada cara untuk mengubahnya) direktori tempat aplikasi berada.

Jalur relatif adalah jalur yang dimulai tanpa spekulan drive. Jadi di linux mereka tidak memulai dengan /, di windows mereka tidak dimulai dengan C:\, dll. Ini selalu dimulai dari direktori kerja Anda.

Jalur absolut adalah jalur yang dimulai dengan penunjuk drive (atau mesin untuk jaringan). Mereka selalu pergi dari awal drive itu.


5
2018-01-11 10:18



Pada windows dan Netbeans Anda dapat mengatur jalur relatif sebagai:

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

Di Linux dan Netbeans Anda dapat mengatur jalur relatif sebagai:

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

Jika Anda memiliki kode Anda di dalam Source Packages Saya tidak tahu apakah itu sama untuk gerhana atau IDE lainnya


0
2018-05-12 10:33



Hanya sedikit berhubungan dengan pertanyaan, tetapi cobalah untuk membungkus kepalamu yang satu ini. Sangat tidak intuitif:

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  !!
  }
}

0
2017-09-10 18:48



Jalur relatif dapat dipahami dengan baik jika Anda tahu bagaimana Java menjalankan program.

Ada konsep direktori kerja ketika menjalankan program di Java. Dengan asumsi Anda memiliki kelas, katakanlah, FileHelper yang melakukan IO di bawah /User/home/Desktop/projectRoot/src/topLevelPackage/.

Tergantung pada kasus di mana Anda memohon java untuk menjalankan program, Anda akan memiliki direktori kerja yang berbeda. Jika Anda menjalankan program Anda dari dalam dan IDE, kemungkinan besar akan terjadi projectRoot.

  • Pada kasus ini $ projectRoot/src : java topLevelPackage.FileHelper boleh jadi src.

  • Pada kasus ini $ projectRoot : java -cp src topLevelPackage.FileHelper boleh jadi projectRoot.

  • Pada kasus ini $ /User/home/Desktop : java -cp ./projectRoot/src topLevelPackage.FileHelper boleh jadi Desktop.

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

Jadi, akar path relatif Anda (.) pecahkan ke direktori kerja Anda. Jadi untuk lebih yakin di mana untuk menulis file, dikatakan untuk mempertimbangkan pendekatan di bawah ini.

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

    }
}

Semoga ini membantu.


0
2018-05-22 16:55