Dosya olarak Java kaynağı


122

Java'da, sınıf yükleyici aracılığıyla bir kavanozdan alınan bir kaynak üzerinde bir Dosya örneği oluşturmanın bir yolu var mı?

Uygulamam, jar (varsayılan) veya çalışma zamanında (kullanıcı girişi) belirtilen dosya sistemi dizinindeki bazı dosyaları kullanıyor.
A) bu dosyaları bir akış olarak yüklemenin tutarlı bir yolunu arıyorum
b) dosyaları sırasıyla kullanıcı tanımlı dizinde veya jar dizininde listelemek

Düzenleme: Görünüşe göre ideal yaklaşım java.io.File dosyasından tamamen uzak durmak olacaktır. Sınıf yolundan bir dizin yüklemenin ve içeriğini (içindeki dosyalar / varlıklar) listelemenin bir yolu var mı?

Yanıtlar:


58

ClassLoader.getResourceAsStreamve Class.getResourceAsStreamkesinlikle kaynak verilerini yüklemenin yoludur. Ancak, sınıf yolunun bir öğesinin içeriğini "listelemenin" bir yolu olduğuna inanmıyorum.

Bazı durumlarda bu basitçe imkansız olabilir - örneğin, bir ClassLoader olabilir o istedi ne kaynak adı dayalı anında veriler üretir. ClassLoaderAPI'ye bakarsanız (temelde sınıf yolu mekanizmasının çalıştığı şeydir), istediğinizi yapacak hiçbir şey olmadığını göreceksiniz.

Aslında bir jar dosyanız olduğunu biliyorsanız, ZipInputStreamneyin mevcut olduğunu bulmak için onu yükleyebilirsiniz . Bu, dizinler ve jar dosyaları için farklı kodlara sahip olacağınız anlamına gelir.

Bir alternatif, eğer dosyalar önce ayrı olarak oluşturulursa, mevcut kaynakların listesini içeren bir tür bildirim dosyası eklemektir. Bunu jar dosyasında paketleyin veya dosya sistemine bir dosya olarak dahil edin ve kullanıcıya çeşitli kaynaklar sunmadan önce yükleyin.


3
Can sıkıcı olduğuna katılıyorum - ancak ClassLoader'ı başka şekillerde daha geniş çapta uygulanabilir kılıyor. Örneğin, bir "web sınıf yükleyicisi" yazmak kolaydır çünkü web dosyaları getirmek için iyidir, ancak genellikle dosyaları listelemez .
Jon Skeet

Yüklemeye çalıştığınız kaynak 1MiB'den çok daha büyükse, bu boyuttan sonra kaynağın baytlarını almak için duraklardan InputStreamalırsınız getResourceAsStreamve bunun yerine bir jar gibi sıkıştırılmış bir dosya sisteminde varsa 0 döndürür. Bu getResourcedurumda dosyayı bundan bağımsız olarak kullanmaya ve yüklemeye zorlanmış görünüyorsunuz .
mgttlinger

1
@mgttlinger: Bu bana pek olası görünmüyor ... eğer mümkünse repro ile yeni bir soru göndermeye değer.
Jon Skeet

Sorun, readne kadar veri okunacağına karar verme yönteminden kaynaklanıyordu (bunun farkında değildim). Ve okunmakta olan dosya normal bir klasörde bulunuyorsa, tüm dosya okundu gibi görünüyor. Dosya paketlendiği için bir kavanozun içindeyse, yalnızca bazı kısımlarını okur.
mgttlinger

1
@mgttlinger: Hayır, sadece bazı kısımlarını okumaz, ancak her okuma çağrısında sağlanan arabelleğin tamamını doldurmayabilir. Her zaman olduğu gibi InputStream, kaynağın tamamını okumak istiyorsanız read-1 döndürene kadar döngü yapmalısınız .
Jon Skeet

98

Aynı sorunu yaşadım ve aşağıdakileri kullanabildim:

// Load the directory as a resource
URL dir_url = ClassLoader.getSystemResource(dir_path);
// Turn the resource into a File object
File dir = new File(dir_url.toURI());
// List the directory
String files = dir.list()

45
Bu yaklaşım, sınıf yolunda
JAR'larla çalışmaz

1
@ yegor256 Dosyanız kavanozda ise bir FileSystemnesne oluşturabilir ve ondan alabilirsiniz Path. O zaman her zamanki gibi okuyabilirsiniz. (bkz. stackoverflow.com/a/22605905/1876344 )
mgttlinger

53

İşte uygulamalarımdan birinden bir parça kod ... İhtiyaçlarınıza uyup uymadığını bana bildirin. Kullanmak istediğiniz dosyayı biliyorsanız bunu kullanabilirsiniz.

URL defaultImage = ClassA.class.getResource("/packageA/subPackage/image-name.png");
File imageFile = new File(defaultImage.toURI());

Umarım yardımcı olur.


Evet öyle, ama toURI()başarısız olacak.
Olivier Faucheux

10

Bir kavanozdan alınan bir kaynakta bir File örneği oluşturmanın güvenilir bir yolu, kaynağı bir akış olarak geçici bir Dosyaya kopyalamaktır (geçici dosya, JVM çıktığında silinecektir):

public static File getResourceAsFile(String resourcePath) {
    try {
        InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
        if (in == null) {
            return null;
        }

        File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        tempFile.deleteOnExit();

        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            //copy stream
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        }
        return tempFile;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

4

Bunu dene:

ClassLoader.getResourceAsStream ("some/pkg/resource.properties");

Daha fazla yöntem vardır, örneğin buraya bakın: http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html


Cevabınız için teşekkürler. GetResourceAsStream hakkında bilgim var, ancak bunun aracılığıyla sınıf yolundan bir dizin yükleyebileceğimi sanmıyorum.
Mantrum

Java dizininde bir dosya var (sanırım UNIX kökleri), bu yüzden en azından denemelisiniz.
topchef

Bir dizindeki dosyaları listelemek için java.io.File kullanmanız gerekeceğini düşünüyorum. Dosyaya aktarılabilen bir URL döndüren ClassLoader.findResource ile dosyaları arayabilirsiniz.
Nathan Voxland

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.