Java'da Kaynak, URI, URL, Yol ve Dosya arasındaki fark nedir?


96

Şu anda Java kodunun bir parçasına bakıyorum ve String olarak bir yol alıyor ve kullanarak URL'sini alıyor URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);, sonra çağırıyor String path = resource.getPath()ve sonunda çalıştırıyor new File(path);.

Oh, ve de vardır çağrıları URL url = resource.toURI();ve String file = resource.getFile().

Şu anda tamamen kafam karıştı - çoğunlukla terminoloji yüzünden sanırım. Birisi lütfen farklılıklar konusunda bana rehberlik edebilir veya Kukla geçirmez materyal için birkaç bağlantı sağlayabilir mi? Özellikle URI'den URL'ye ve Kaynaktan Dosyaya ? Bana göre, sırasıyla aynı şey olmaları gerektiği gibi geliyor ...

Arasındaki fark getFile()ve getPath()burada açıklanmıştır: url.getFile () ve getpath () arasındaki fark nedir? (İlginçtir ki ikisi de Dizeleri döndürüyor gibi görünüyor, ki bu muhtemelen zihin durumuma çok şey katıyor ...)

Şimdi, bir jar dosyasındaki bir sınıfa veya paketi referans alan bir konumlandırıcım varsa, bu ikisi (yani bir dosya dizesinin yolu) farklı olur mu?

resource.toString()jar:file:/C:/path/to/my.jar!/com/example/sonuçta size verecektir (ünlem işaretine dikkat edin).

Arasındaki fark mı URI ve URL'ye Java eski kodlamak boşluk değil mi? Cf. Java'da çakışan dosyalar, URI'ler ve URL'ler (Bu yanıt , iki terim arasındaki genel, kavramsal farkı oldukça iyi açıklar : URI'ler tanımlar ve URL'ler bulunur; )

Son olarak - ve en önemlisi - neden Filenesneye ihtiyacım var ; Kaynak ( URL) neden yeterli değil? (Ve bir Kaynak nesnesi var mı?)

Bu soru biraz düzensizse özür dilerim; sadece sahip olduğum kafa karışıklığını yansıtıyor ... :)


5
Ve Path
NIO'dan

2
@eckes Her seferinde bir baş ağrısı lütfen. ;)
Christian

1
Sorunuzun bağlamında Dosya / URL + URI ilişkili değildir. Biri dosyalar üzerinde adlandırma ve işlem yapma aracı, diğeri ise kaynakları adlandırmak ve kaynaklardan okumak için bir yöntemdir (dosyalar olabilir). GetFile ve getPath yöntemleri, dosya nesneleri gibi (kafa karıştırıcı bir şekilde) adlandırılan bir URL'nin bileşenleriyle ilgilenir. Sınıf yükleyici kaynakları, farklı kökenlere sahip olabileceğinden (veya JAR dosyalarında iç içe olabileceğinden) dosyalar olarak temsil edilmez.
Eckes

1
Bu kodun amaçlandığı gibi çalışmayacağını not ediyorum. A URLise opak - Ürünün var göstermek olarak jar:file:yani bir kaynak, .jararşivde. Bunu a'ya çevirmenin Fileyararlı bir şeyle sonuçlanması pek olası değildir.
Örümcek Boris

1
Sorununuzun özü, kaynak ve yol kelimelerinin bağlama bağlı olarak farklı anlamlara sahip olabilmesidir.
Raedwald

Yanıtlar:


43

GÜNCELLEME 2017-04-12 Daha kapsamlı ve kesin bir açıklama içerdiğinden JvR'nin yanıtını kontrol edin !


Lütfen kendimi cevaplamaya% 100 yetkin bulmadığımı unutmayın, ancak yine de bazı yorumlar:

  • File dosya sistemi aracılığıyla erişilebilen bir dosya veya dizini temsil eder
  • kaynak , uygulama tarafından yüklenebilen bir veri nesnesi için genel bir terimdir
    • genellikle kaynaklar , uygulama / kitaplık ile dağıtılan ve sınıf yükleme mekanizması aracılığıyla yüklenen dosyalardır (sınıf yolunda bulunduklarında)
  • URL#getPathalıcı URL'nin yol kısmında ( protocol://host/path?query)
  • URL#getFile JavaDoc getirilerine göre path+query

Java'da, URIgenel tanımlayıcının kendisini işlemek için sadece bir veri yapısıdır.

URLÖte yandan, gerçekten bir kaynak bulucu ve kaynağı kayıtlı URLStreamHandlere- postalar aracılığıyla gerçekten okumak için size özellikler sunar .

URL'ler dosya sistemi kaynaklarına yönlendirebilir ve file://protokolü (dolayısıyla File<-> URLilişkisini) kullanarak her dosya sistemi kaynağı için URL oluşturabilirsiniz .

Ayrıca bununla URL#getFileilgisi olmadığını da unutmayın java.io.File.


Neden File nesnesine ihtiyacım var; Neden bir Kaynak (URL) yeterli değil?

Yeterli. Yalnızca, kaynağı yalnızca dosyalarla çalışabilen bir bileşene geçirmek istiyorsanız, ondan almanız gerekir File. Ancak tüm kaynak URL'leri URL’lere dönüştürülemez File.

Ve bir Kaynak nesnesi var mı?

JRE açısından, bu sadece bir terim. Bazı çerçeveler size böyle bir sınıf sağlar (örn. Spring's Resource ).


5
Ayrıca java.nio.file.Path, Java'nın java.io.Fileilk günlerinde ikinci API görünüşte zayıf bir şekilde düşünüldüğü için , temelde bir (Java 7+) yerine geçen bir şey de var .
ntoskrnl

1
Genel olarak, kesinlikle gerekli olmadıkça URL kullanımını en aza indirmelisiniz. Bunun nedeni, URL'nin eşittir ve hashCode yöntemlerinin şaşırtıcı bir şekilde uygulanmasıdır: yöntem çağrılarını engelliyorlar.
kibibyte

3
@kibibyte: Çağrının engellenmesini, hashcode'un eşzamansız bir uygulamasına sahip olmasını ve şimdi eşit olmasını beklerdim, bu çok rahatsız edici olurdu. Sanırım kastettiğin, aramaların ana bilgisayarı eşdeğeri olup olmadığını bulmaya çalışacak ve çözecek ve böylece potansiyel olarak engelleyici ağ aramaları yapabilecek.
Newtopian

54

Şu anda tamamen kafam karıştı - çoğunlukla terminoloji yüzünden sanırım. Birisi lütfen farklılıklar konusunda bana rehberlik edebilir veya Kukla geçirmez materyal için birkaç bağlantı sağlayabilir mi? Özellikle URI'den URL'ye ve Kaynaktan Dosyaya? Bana göre, sırasıyla aynı şey olmaları gerektiği gibi geliyor ...

Terminoloji kafa karıştırıcı ve bazen kafa karıştırıcıdır ve çoğunlukla Java'nın hem API hem de platform olarak zaman içindeki evriminden doğmuştur. Bu terimlerin ne yaptıkları anlamına geldiğini anlamak için Java'nın tasarımını etkileyen iki şeyi tanımak önemlidir:

  • Geriye dönük uyumluluk. Eski uygulamalar, ideal olarak değişiklik yapılmadan yeni kurulumlarda çalışmalıdır. Bu, eski bir API'nin (adları ve terminolojisiyle birlikte) tüm yeni sürümlerde korunması gerektiği anlamına gelir.
  • Çapraz platform. API, ister işletim sistemi ister tarayıcı olsun, temel platformunun kullanılabilir bir özetini sağlamalıdır.

Kavramları ve nasıl oluştuklarını gözden geçireceğim. Daha sonra diğer özel sorularınızı cevaplayacağım çünkü ilk kısımdaki bir şeye atıfta bulunmam gerekebilir.

"Kaynak" nedir?

Bulunabilen ve okunabilen soyut, genel bir veri parçası. Basitçe söylersek, Java bunu bir dosya olmayabilecek ancak adlandırılmış bir veri parçasını temsil eden bir "dosyaya" başvurmak için kullanır. Java'da doğrudan bir sınıf veya arayüz temsiline sahip değildir , ancak özellikleri nedeniyle (konumlandırılabilir, okunabilir) genellikle bir URL ile temsil edilir.

Java'nın ilk tasarım hedeflerinden biri, bir tarayıcının içinde, çok sınırlı haklara / ayrıcalıklara / güvenlik açıklığına sahip korumalı bir uygulama (apletler!) Olarak çalıştırılmak olduğu için, Java bir dosya (yerel dosya sistemi) ve bir kaynak (okuması gereken bir şey). Uygulamayla ilgili bir şey okumanın (simgeler, sınıf dosyaları vb.), ClassLoader.getResourceFile sınıfı aracılığıyla değil de yapılmasının nedeni budur .

Ne yazık ki, "kaynak" aynı zamanda bu yorumun dışında yararlı bir genel terim olduğundan , bu anlamda bir kaynak olmayan çok özel şeyleri (örneğin , ResourceBundle , UIResource , Resource sınıfı) adlandırmak için de kullanılır .

Bir kaynağı (bir yolu) temsil eden ana sınıflar java.nio.file.Path , java.io.File , java.net.URI ve java.net.URL'dir .

Dosya (java.io, 1.0)

Dosya ve dizin yol adlarının soyut bir temsili.

File sınıfı , platformun yerel dosya sistemi aracılığıyla erişilebilen bir kaynağı temsil eder . Yalnızca dosyanın adını içerir, bu nedenle, ana bilgisayar platformunun kendi ayarlarına, kurallarına ve sözdizimine göre yorumladığı bir yoldur (daha sonra bakın).

Dosyanın yerel bir şeye işaret etmesi gerekmediğini unutmayın , sadece ana bilgisayar platformunun dosya erişimi bağlamında anladığı bir şeye, örneğin Windows'ta bir UNC yolu. Bir ZIP dosyasını işletim sisteminize bir dosya sistemi olarak bağlarsanız, Dosya içerdiği girdileri iyi okuyacaktır.

URL (java.net, 1.0)

Sınıf URL'si, World Wide Web üzerindeki bir "kaynağa" işaret eden bir Tekdüzen Kaynak Konum Belirleyiciyi temsil eder. Bir kaynak, bir dosya veya dizin kadar basit bir şey olabilir veya bir veritabanına veya bir arama motoruna yönelik bir sorgu gibi daha karmaşık bir nesneye bir başvuru olabilir.

Bir kaynak kavramıyla birlikte, URL bu kaynağı, File sınıfının ana bilgisayar platformundaki bir dosyayı temsil ettiği şekilde temsil eder: bir kaynağa işaret eden yapılandırılmış bir dize olarak . URL ek olarak kaynağa nasıl ulaşılacağına dair ipucu veren bir şema içerir ("dosya:" "ana bilgisayar platformuna sor" olarak) ve bu nedenle kaynaklara HTTP, FTP, JAR içinde ve başka bir şeyle işaret etmeye izin verir.

Ne yazık ki, URL'ler "dosya" ve "yol" kullanımı dahil olmak üzere kendi sözdizimi ve terminolojisiyle birlikte gelir. URL'nin bir dosya-URL'si olması durumunda, URL.getFile, başvurulan dosyanın yol dizesiyle aynı olan bir dize döndürür.

Class.getResource bir URL döndürür: Geri dönen Dosyadan daha esnektir ve 1990'ların başında hayal edildiği gibi sistemin ihtiyaçlarına hizmet etmiştir.

URI (java.net, 1.4)

Bir Tekdüzen Kaynak Tanımlayıcısı (URI) başvurusunu temsil eder.

URI, URL üzerinden (hafif) bir soyutlamadır. URI ile URL arasındaki fark kavramsaldır ve çoğunlukla akademiktir, ancak URI biçimsel anlamda daha iyi tanımlanır ve daha geniş bir kullanım alanı yelpazesini kapsar. URL ve URI aynı şey olmadığından / olmadığından, bunları temsil etmek için URI.toURL ve URL.toURI yöntemleriyle biri ve diğeri arasında hareket edecek yeni bir sınıf tanıtıldı.

Java'da, URL ile URI arasındaki temel fark, bir URL'nin çözümlenebilir olma beklentisini taşımasıdır , bu , uygulamanın bir InputStream'den isteyebileceği bir şeydir; Bir URI daha soyut bir thingamajig gibi muamele edilir olabilecek bir şey çözülebilir işaret (ve genellikle yapar), ama ne anlama geldiğini ve nasıl bağlam ve yorumlamaya daha açık ulaşmak için.

Yol (java.nio.file, 1.7)

Bir dosya sistemindeki bir dosyayı bulmak için kullanılabilecek bir nesne. Tipik olarak sisteme bağımlı bir dosya yolunu temsil eder.

Path arayüzünde simge haline getirilen yeni dosya API'si, File sınıfının sunabileceğinden çok daha fazla esneklik sağlar. Path arabirimi, File sınıfının bir soyutlamasıdır ve New IO File API'nin bir parçasıdır . Dosya, ana bilgisayar platformu tarafından anlaşıldığı gibi bir "dosyaya" işaret ettiğinde, Yol daha geneldir: keyfi bir dosya sistemindeki bir dosyayı (kaynağı) temsil eder .

Yol, ana bilgisayar platformunun dosya konseptine olan güvenini ortadan kaldırır. Bir ZIP dosyasındaki bir giriş, FTP veya SSH-FS aracılığıyla erişilebilen bir dosya, uygulama sınıf yolunun çok köklü bir temsili veya FileSystem arayüzü ve sürücüsü FileSystemProvider aracılığıyla anlamlı bir şekilde temsil edilebilecek herhangi bir şey olabilir. Dosya sistemlerini "bağlama" gücünü bir Java uygulamasının içeriğine getirir.

Ana bilgisayar platformu "varsayılan dosya sistemi" ile temsil edilir; aradığınızda File.toPath, varsayılan dosya sisteminde bir Yol alırsınız.


Şimdi, bir jar dosyasındaki bir sınıfa veya paketi referans alan bir konumlandırıcım varsa, bu ikisi (yani bir dosya dizesinin yolu) farklı olur mu?

Olası olmayan. Kavanoz dosya yerel dosya sistemi üzerinde ise, bir sorgu bileşeni olmamalıdır, bu nedenle URL.getPathve URL.getFileaynı sonucu dönmelidir. Ancak, ihtiyacınız olanı seçin: dosya-URL'leri genellikle sorgu bileşenlerine sahip olmayabilir, ancak yine de bir tane ekleyebilirim.

Son olarak - ve en önemlisi - neden File nesnesine ihtiyacım var; Neden bir Kaynak (URL) yeterli değil?

URL yeterli olmayabilir çünkü Dosya size izinler (okunabilir, yazılabilir, çalıştırılabilir), dosya türü (ben bir dizin miyim?) Ve yerel dosya sistemini arama ve değiştirme yeteneği gibi temel verilere erişim sağlar. Bunlar ihtiyacınız olan özelliklerse, Dosya veya Yol bunları sağlar.

Yol'a erişiminiz varsa Dosyaya ihtiyacınız yoktur. Yine de bazı eski API'ler Dosya gerektirebilir.

(Ve bir Kaynak nesnesi var mı?)

Hayır yok. Onun gibi isimlendirilmiş pek çok şey var ama anlamında bir kaynak değiller ClassLoader.getResource.


Vay canına, çok titiz. Sadece üzerinden geçiyorum, ama zaten ilk soruya sahip: Bir Dosya "yalnızca dosyanın adını içerir" dediğinizde, bunun "dosya ve dizin yol adlarının soyut bir temsili" olduğu şeklindeki ilk ifadenizle çelişmez misiniz? - daha mı?
Christian

1
@Christian "yalnızca adı" kastetmiştim: hiçbir şekilde dosyanın içeriğini modellemez; sadece bir ipin etrafındaki ince bir pakettir. "Soyut temsil" kısmı, API belgelerinden alıntılanmıştır. ;)
JvR

Bu cevap çok daha fazla olumlu oyu hak ediyor ... okuyucuları buna yönlendirmek için kabul ettiğim cevabı güncelleyecektir.
Pavel Horal

12

Pavel Horal'ın cevabı güzel.

Dediği gibi, "dosya" kelimesinin URL#getFilevs java.io.File- içinde tamamen farklı (pratik olarak ilgisiz) anlamları vardır , bu kafa karışıklığının bir parçası olabilir.

Sadece eklemek için:

  • Bir kaynak Java soyut bir kavram, okunabilir bir veri kaynağıdır. Bir kaynağın konumu (veya adresi) Java'da bir URLnesne ile temsil edilir .

  • Bir kaynak , yerel dosya sistemindeki normal bir dosyaya karşılık gelebilir (özellikle, ile URLbaşladığında file://). Ancak bir kaynak daha geneldir (aynı zamanda bir kavanozda saklanan bir dosya veya ağdan veya bellekten okunacak bazı veriler veya ...). Ayrıca daha sınırlıdır, çünkü a File(normal bir dosyadan başka şeyler olmasının yanı sıra: bir dizin, bir bağlantı) da oluşturulabilir ve yazılabilir.

  • Java'da bir Filenesnenin gerçekten "bir dosyayı" değil, bir dosyanın konumunu (tam adı, yolu) temsil ettiğini unutmayın. Dolayısıyla, bir Filenesne, URLbir kaynağa erişmenize (ve bir kaynağa erişmenize) izin verdiği için bir dosyayı bulmanıza (ve açmanıza) olanak tanır. ( ResourceJava'da bir kaynağı temsil edecek bir sınıf yoktur , ancak bir dosyayı temsil edecek bir sınıf yoktur ! Bir kez daha: Filebir dosya değil, bir dosyanın yoludur).


3

Onları anladığım kadarıyla aşağıdaki şekilde kategorize edebilirsiniz:

Web Tabanlı: URI'ler ve URL'ler.

  • URL'ler: Bir URL, internt üzerindeki kesin bir konumdur (sadece - stackoverflow.com gibi normal bir web adresi)
  • URI'ler: Ever URL bir URI'dir. Ancak URI'ler aynı zamanda "mailto:" gibi şeyler de içerebilirler, bu yüzden onlar da, bir "komut dosyası" diyeceğim.

Ve yerel: Kaynak, Yol ve Dosyalar

  • Kaynak: Kaynaklar, kavanozunuzun içindeki dosyalardır. Dosyaları kavanozlardan / kaplardan yüklemek için kullanılırlar.
  • Yol: Yol, temelde bir dizedir. Ancak, birden çok dizeyi birleştirmek veya bir dizeye dosya eklemek için bazı kullanışlı işlevlerle birlikte gelir. İnşa ettiğiniz yolun geçerli olduğundan emin olmanızı sağlar.
  • Dosya: Bu, bir dizin veya dosyaya referanstır. Dosyaları değiştirmek, açmak vb. İçin kullanılır.

Tek bir sınıfta birleştirilmeleri daha kolay olurdu - gerçekten kafa karıştırıcı: D

Umarım bu sana yardımcı olur :)

(Belgelere bir göz attım - docs.oracle.com adresine bakın)


0

Dosya, yerel dosya sistemindeki bir varlığın soyut bir temsilidir.

Yol, genellikle bir dosyanın bir dosya sistemi içindeki konumunu gösteren bir dizedir. Genellikle dosya adını içermez. Yani c: \ belgeler \ mystuff \ stuff.txt, "C: \ belgeler \ mystuff" değerine sahip bir yola sahip olacaktı Açıkçası, mutlak dosya adlarının ve yolların biçimi, dosya sisteminden dosya sistemine büyük ölçüde değişecekti.

URL, genellikle http üzerinden erişilebilen kaynakları temsil eden URL’ye sahip bir URI nesnesidir. Bir şeyin URL'ye karşı URI olması gerektiğine dair herhangi bir sert kural olduğunu sanmıyorum. URI'ler, bitcoin: // params, http://something.com?param=value gibi "protokol: // kaynak tanımlayıcı" biçimindeki dizelerdir . URL gibi sınıflar genellikle dizeyi sarar ve String'in sağlamak için hiçbir nedeninin olmayacağı yardımcı program yöntemleri sağlar.

Kaynak diye bir şey yok, en azından bahsettiğiniz anlamda değil. Bir yöntemin adı getResource olması, Resource türünde bir nesne döndürdüğü anlamına gelmez.

Nihayetinde, bir Sınıfın yöntemlerinin ne yaptığını anlamanın en iyi yolu, kodunuzda bunun bir örneğini oluşturmak, yöntemleri çağırmak ve ardından hata ayıklama modunda adım atmak veya sonuçları System.out'a göndermektir.


"Yol" tanımınız OP bağlamındaki "yol" kavramına karşılık gelmiyor
leonbloy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.