Bagaimana cara menggabungkan jalur di Jawa?

350

Apakah ada padanan Java untuk System.IO.Path.Combine()dalam C # /. NET? Atau kode apa saja untuk mencapai ini?

Metode statis ini menggabungkan satu atau lebih string ke jalur.

Rodrigue
sumber
1
Pertanyaan SO ini mungkin membantu.
Jim Blizard

Jawaban:

407

Daripada menjaga semua berbasis string, Anda harus menggunakan kelas yang dirancang untuk mewakili jalur sistem file.

Jika Anda menggunakan Java 7 atau Java 8, Anda harus mempertimbangkan untuk menggunakan java.nio.file.Path; Path.resolvedapat digunakan untuk menggabungkan satu jalur dengan yang lain, atau dengan string. Kelas Pathspembantu juga berguna. Sebagai contoh:

Path path = Paths.get("foo", "bar", "baz.txt");

Jika Anda perlu memenuhi lingkungan pra-Java-7, Anda dapat menggunakan java.io.File, seperti ini:

File baseDirectory = new File("foo");
File subDirectory = new File(baseDirectory, "bar");
File fileInDirectory = new File(subDirectory, "baz.txt");

Jika Anda ingin mengembalikannya sebagai string nanti, Anda dapat menelepon getPath(). Memang, jika Anda benar-benar ingin meniru Path.Combine, Anda bisa menulis sesuatu seperti:

public static String combine(String path1, String path2)
{
    File file1 = new File(path1);
    File file2 = new File(file1, path2);
    return file2.getPath();
}
Jon Skeet
sumber
10
Waspadalah terhadap jalur absolut. Versi .NET akan kembali path2(mengabaikan path1) jika path2merupakan jalur absolut. Versi Java akan menjatuhkan yang pertama /atau \ dan memperlakukannya sebagai jalur relatif.
finnw
23
@ Matthew - karena direktori adalah file. File ini yang isinya menentukan anak-anak dari dir itu, lokasinya pada disk, izin, dll.
Dónal
7
@ Hugo: Jadi itu membuang seluruh dua benda ? Mengejutkan! Tampak cukup bersih bagi saya, jujur ​​... itu membuat logika untuk nama file relatif di tempatnya, di kelas File.
Jon Skeet
1
@modosansreves: Lihat File.getCanonicalPath.
Jon Skeet
1
@SargeBorsch: Ya, C # hanyalah sebuah bahasa. Anda dapat dengan mudah membuat yang setara dengan Filedi C # jika Anda mau. (Saya berasumsi maksud Anda keberadaan Fileadalah manfaat, yang akan saya setujui.)
Jon Skeet
118

Di Java 7, Anda harus menggunakan resolve:

Path newPath = path.resolve(childPath);

Sementara kelas Path NIO2 mungkin tampak sedikit berlebihan untuk File dengan API berbeda yang tidak perlu, itu sebenarnya secara halus lebih elegan dan kuat.

Perhatikan bahwa Paths.get()(seperti yang disarankan oleh orang lain) tidak memiliki kelebihan mengambil Path, dan melakukan Paths.get(path.toString(), childPath)TIDAK sama dengan resolve(). Dari Paths.get()dokumen :

Perhatikan bahwa walaupun metode ini sangat nyaman, menggunakannya akan menyiratkan referensi yang diasumsikan ke Sistem File default dan membatasi utilitas kode panggilan. Oleh karena itu tidak boleh digunakan dalam kode perpustakaan yang dimaksudkan untuk digunakan kembali secara fleksibel. Alternatif yang lebih fleksibel adalah dengan menggunakan instance Path yang ada sebagai jangkar, seperti:

Path dir = ...
Path path = dir.resolve("file");

Fungsi saudari resolveadalah yang terbaik relativize:

Path childPath = path.relativize(newPath);
Aleksandr Dubinsky
sumber
17

Saya tahu ini sudah lama sejak jawaban asli Jon, tetapi saya memiliki persyaratan yang serupa dengan OP.

Dengan cara memperluas solusi Jon saya datang dengan yang berikut, yang akan mengambil satu atau lebih segmen jalan mengambil banyak segmen jalan yang bisa Anda lemparkan ke sana.

Pemakaian

Path.combine("/Users/beardtwizzle/");
Path.combine("/", "Users", "beardtwizzle");
Path.combine(new String[] { "/", "Users", "beardtwizzle", "arrayUsage" });

Kode di sini untuk orang lain dengan masalah yang sama

public class Path {
    public static String combine(String... paths)
    {
        File file = new File(paths[0]);

        for (int i = 1; i < paths.length ; i++) {
            file = new File(file, paths[i]);
        }

        return file.getPath();
    }
}
isNaN1247
sumber
12

pendekatan independen platform (menggunakan File.separator, yaitu akan berfungsi tergantung pada sistem operasi tempat kode berjalan:

java.nio.file.Paths.get(".", "path", "to", "file.txt")
// relative unix path: ./path/to/file.txt
// relative windows path: .\path\to\filee.txt

java.nio.file.Paths.get("/", "path", "to", "file.txt")
// absolute unix path: /path/to/filee.txt
// windows network drive path: \\path\to\file.txt

java.nio.file.Paths.get("C:", "path", "to", "file.txt")
// absolute windows path: C:\path\to\file.txt
Maksim Kostromin
sumber
11

Untuk meningkatkan jawaban JodaStephen, Apache Commons IO memiliki FilenameUtils yang melakukan ini. Contoh (di Linux):

assert org.apache.commons.io.FilenameUtils.concat("/home/bob", "work\\stuff.log") == "/home/bob/work/stuff.log"

Ini platform independen dan akan menghasilkan pemisah apa pun yang dibutuhkan sistem Anda.

alpian
sumber
2

Inilah solusi yang menangani beberapa bagian jalur dan kondisi tepi:

public static String combinePaths(String ... paths)
{
  if ( paths.length == 0)
  {
    return "";
  }

  File combined = new File(paths[0]);

  int i = 1;
  while ( i < paths.length)
  {
    combined = new File(combined, paths[i]);
    ++i;
  }

  return combined.getPath();
}
Tagihan
sumber
2

Jika Anda tidak membutuhkan lebih dari string, Anda dapat menggunakan com.google.common.io.Files

Files.simplifyPath("some/prefix/with//extra///slashes" + "file//name")

mendapatkan

"some/prefix/with/extra/slashes/file/name"
Gismo Ranas
sumber
1

Mungkin terlambat ke pesta, tapi aku ingin berbagi pendapat tentang ini. Saya menggunakan pola Builder dan memungkinkan appendpanggilan yang dirantai . Itu dapat dengan mudah diperluas untuk mendukung bekerja dengan Pathobjek juga.

public class Files  {
    public static class PathBuilder {
        private File file;

        private PathBuilder ( File root ) {
            file = root;
        }

        private PathBuilder ( String root ) {
            file = new File(root);
        }

        public PathBuilder append ( File more ) {
            file = new File(file, more.getPath()) );
            return this;
        }

        public PathBuilder append ( String more ) {
            file = new File(file, more);
            return this;
        }

        public File buildFile () {
            return file;
        }
    }

    public static PathBuilder buildPath ( File root ) {
        return new PathBuilder(root);
    }

    public static PathBuilder buildPath ( String root ) {
        return new PathBuilder(root);
    }
}

Contoh penggunaan:

File root = File.listRoots()[0];
String hello = "hello";
String world = "world";
String filename = "warez.lha"; 

File file = Files.buildPath(root).append(hello).append(world)
              .append(filename).buildFile();
String absolute = file.getAbsolutePath();

Hasilnya absoluteakan berisi sesuatu seperti:

/hello/world/warez.lha

atau bahkan mungkin:

A:\hello\world\warez.lha
Stephan Henningsen
sumber
1

Ini juga berfungsi di Java 8:

Path file = Paths.get("Some path");
file = Paths.get(file + "Some other path");
rootExplorr
sumber
0

Solusi ini menawarkan antarmuka untuk menggabungkan fragmen jalur dari array String []. Ini menggunakan java.io.File.File (induk String, String child) :

    public static joinPaths(String[] fragments) {
        String emptyPath = "";
        return buildPath(emptyPath, fragments);
    }

    private static buildPath(String path, String[] fragments) {
        if (path == null || path.isEmpty()) {
            path = "";
        }

        if (fragments == null || fragments.length == 0) {
            return "";
        }

        int pathCurrentSize = path.split("/").length;
        int fragmentsLen = fragments.length;

        if (pathCurrentSize <= fragmentsLen) {
            String newPath = new File(path, fragments[pathCurrentSize - 1]).toString();
            path = buildPath(newPath, fragments);
        }

        return path;
    }

Maka Anda bisa melakukan:

String[] fragments = {"dir", "anotherDir/", "/filename.txt"};
String path = joinPaths(fragments);

Pengembalian:

"/dir/anotherDir/filename.txt"
JackCid
sumber