Kavanozun içinden bir kaynak dosyasını okuma


242

Kavanozumdaki bir kaynağı şöyle okumak istiyorum:

File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferredReader reader = new BufferedReader(new FileReader(file));

//Read the file

ve Eclipse içinde çalıştırırken iyi çalışıyor, ancak bir kavanoz çalıştırmak için dışarı aktarırsanız bir IllegalArgumentException var:

Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical

ve nedenini bilmiyorum ama bazı testlerde

file = new File(getClass().getResource("/file.txt").toURI());

için

file = new File(getClass().getResource("/folder/file.txt").toURI());

o zaman tersi çalışır (kavanozda çalışır, ancak tutulmaz).

Eclipse kullanıyorum ve benim dosya ile klasör bir sınıf klasöründe.


Dosyalar için herhangi bir sayı ile kavanozdaki bir dizindeki dosyaları okumak istiyorsanız, Stackoverflow-Link
Michael Hegner

1
Asıl sorunun Spring ile ilgili olduğundan emin değilim. Önceki yorumdaki bağlantı, farklı bir sorunun Bahar'a özgü bir cevabını ifade eder. getResourceAsStreamSoruna hala daha basit ve daha taşınabilir bir çözüm olduğuna inanıyorum .
Drew MacInnis

Yanıtlar:


398

Kaynağı bir Dosya olarak ele almaya çalışmak yerine ClassLoader'dan getResourceAsStream aracılığıyla kaynak için bir InputStream döndürmesini isteyin :

InputStream in = getClass().getResourceAsStream("/file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

file.txtKaynak sınıfyolunda mevcut olduğu sürece, bu yaklaşım, file.txtkaynağın bir classes/dizinde veya a içinde olmasına bakılmaksızın aynı şekilde çalışır jar.

URI is not hierarchicalBir kavanoz dosya içinde bir kaynak için URI böyle bakmak şeye gidiyor çünkü oluşur: file:/example.jar!/file.txt. jar(Bir zipdosya) içindeki girişleri düz eski bir Dosya gibi okuyamazsınız .

Bu, aşağıdakilerin cevaplarıyla açıklanmaktadır:


3
Teşekkür ederim, bu çok yardımcı oldu ve kod mükemmel çalışıyor, ama bir sorunum InputStreamvar , oyunumun File.exists()varsayılan dosyayı kullanıp kullanmamayı söyleyebilmesi için (gibi ) olup olmadığını belirlemem gerekiyor . Teşekkürler.
PrinceCJC

1
Oh ve BTW neden getClass().getResource("**/folder**/file.txt")işe yaradı çünkü benim kavanoz ile aynı dizinde bu klasör vardı :).
PrinceCJC

5
getResourceAsStreamkaynak mevcut değilse, null değerini döndürür.
Drew MacInnis

1
BTW, bir yazım hatası var: BufferredReader değil, BufferedReader olmalı (daha sonra ekstra 'r' dikkat edin)
mailmindlin

2
Ve elbette ... girişi kapatmayı unutmayınStream ve BufferedReader
Noremac

26

Kavanozdaki bir dosyaya erişmek için iki seçeneğiniz vardır:

  • Dosyayı paket adınızla eşleşen dizin yapısına yerleştirin (.jar dosyasını çıkardıktan sonra .class dosyasıyla aynı dizinde olmalıdır), ardından getClass().getResourceAsStream("file.txt")

  • Dosyayı kök dizinine yerleştirin (.jar dosyasını çıkardıktan sonra kökte olması gerekir), ardından Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")

Kavanoz eklenti olarak kullanıldığında ilk seçenek çalışmayabilir.


Bu harika cevap için çok teşekkür ederim ... İkinci seçeneğin bir başka yararı da ana yöntemden işe yaramasıdır, çünkü getClass () statik yöntemlerden değil, yalnızca bir örnekten çalışır.
Dan Ortega

6

Daha önce bu sorunu yaşadım ve yükleme için yedek yol yaptım. Temelde ilk yol .jar dosyası içinde ve ikinci yol tutulma veya diğer IDE içinde çalışır.

public class MyClass {

    public static InputStream accessFile() {
        String resource = "my-file-located-in-resources.txt";

        // this is the path within the jar file
        InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
        if (input == null) {
            // this is how we load file within editor (eg eclipse)
            input = MyClass.class.getClassLoader().getResourceAsStream(resource);
        }

        return input;
    }
}

3

Şimdi (2017 Aralık) kadar, bu işleri ben buldum tek çözüm hem içeri hem dışarı IDE.

PathMatchingResourcePatternResolver Kullan

Not: bahar önyüklemesinde de çalışır

Bu örnekte src / main / resources / my_folder konumunda bulunan bazı dosyaları okuyorum :

try {
    // Get all the files under this inner resource folder: my_folder
    String scannedPackage = "my_folder/*";
    PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
    Resource[] resources = scanner.getResources(scannedPackage);

    if (resources == null || resources.length == 0)
        log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
    else {
        for (Resource resource : resources) {
            log.info(resource.getFilename());
            // Read the file content (I used BufferedReader, but there are other solutions for that):
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                // ...
                // ...                      
            }
            bufferedReader.close();
        }
    }
} catch (Exception e) {
    throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}

3

Sorun, bazı üçüncü taraf kitaplıklarının giriş akışları yerine dosya yol adları gerektirmesidir. Cevapların çoğu bu konuyu ele almıyor.

Bu durumda, bir geçici çözüm kaynak içeriğini geçici bir dosyaya kopyalamaktır. Aşağıdaki örnek jUnit'i kullanmaktadır TemporaryFolder.

    private List<String> decomposePath(String path){
        List<String> reversed = Lists.newArrayList();
        File currFile = new File(path);
        while(currFile != null){
            reversed.add(currFile.getName());
            currFile = currFile.getParentFile();
        }
        return Lists.reverse(reversed);
    }

    private String writeResourceToFile(String resourceName) throws IOException {
        ClassLoader loader = getClass().getClassLoader();
        InputStream configStream = loader.getResourceAsStream(resourceName);
        List<String> pathComponents = decomposePath(resourceName);
        folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
        File tmpFile = folder.newFile(resourceName);
        Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
        return tmpFile.getAbsolutePath();
    }

Bu çok fazla parlatılır. Belgelediğiniz için teşekkürler. JUnit olmadan başka hangi seçeneklerin olduğunu merak ediyorum.
Alex Moore-Niemi

0

Dosya olarak okumak isterseniz, yine de benzer bir çözüm olduğuna inanıyorum:

    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("file/test.xml").getFile());

4
URL.getFile () , URL'yi dosya adına dönüştürmez. URL'nin ana bilgisayardan sonraki kısmını ve tüm yüzde kodlamaları bozulmadan döndürür, bu nedenle yol ASCII olmayan karakterler veya URL'lerde (boşluklar dahil) izin verilmeyen ASCII karakterleri içeriyorsa, sonuç mevcut bir dosya adı olmaz , URL bir file:URL olsa bile .
VGR

48
program bir kavanoza inşa
Akshay Kasar

1
Dizeye dönüştürüp önce yerel olarak kaydetmediğiniz sürece kavanozdan çalışmaz.
smoosh911

0

Doğru ayırıcıyla çalıştığınızdan emin olun. Hepsini /göreceli bir yolla bir File.separator. Bu IDE iyi çalıştı, ancak yapı JAR işe yaramadı.


0

Bunun java'da da çalışması gerektiğini düşünüyorum. Aşağıdaki kodu kotlin kullanıyorum.

val resource = Thread.currentThread().contextClassLoader.getResource('resources.txt')

0

Bir düzeltme buldum

BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));

"Main" kodunu, kodladığınız java sınıfıyla değiştirin. "Path" dosyasını jar dosyasındaki yolla değiştirin.

örneğin, State1.txt dosyasını com.issac.state paketine koyarsanız, Linux veya Mac çalıştırıyorsanız yolu "/ com / issac / state / State1" olarak yazın. Windows'u çalıştırırsanız, yolu "\ com \ issac \ state \ State1" olarak yazın. Dosya bulunamadı özel durumu oluşmadıkça .txt uzantısını dosyaya eklemeyin.


-1

Sınıfyolundan KÖK yolu olarak okunacak sınıf yükleyiciyi kullanabilirsiniz (başlangıçta "/" olmadan)

InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

-1

Yay kullanıyorsanız, dosyayı src / main / resources dizininden okumak için aşağıdaki yöntemi kullanabilirsiniz:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;

  public String readFileToString(String path) throws IOException {

    StringBuilder resultBuilder = new StringBuilder("");
    ClassPathResource resource = new ClassPathResource(path);

    try (
        InputStream inputStream = resource.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {

      String line;

      while ((line = bufferedReader.readLine()) != null) {
        resultBuilder.append(line);
      }

    }

    return resultBuilder.toString();
  }

1
SO hoş geldiniz. Bu soruya bir cevap sağlamaz. Yeterli bir üne sahip olduğunuzda , herhangi bir gönderi hakkında yorum yapabilirsiniz . Ayrıca bunun yerine ne yapabilirim .
15'te

Bu, dosyadaki satır sonlarını kaldıracaktır!
elad.chen

-1

Nedense classLoader.getResource()ben web uygulaması WildFly 14 konuşlandırıldığında her zaman null döndü classLoader alma getClass().getClassLoader()veya Thread.currentThread().getContextClassLoader()null döndürür.

getClass().getClassLoader() API doc diyor ki,

"Sınıf için sınıf yükleyiciyi döndürür. Bazı uygulamalar, bootstrap sınıf yükleyicisini temsil etmek için null kullanabilir. Bu sınıf, bootstrap sınıf yükleyicisi tarafından yüklendiyse bu tür uygulamalarda null değerini döndürür."

WildFly kullanıyorsanız ve sizin web uygulaması bunu deneyin

request.getServletContext().getResource()kaynak URL'sini döndürdü. Burada istek bir ServletRequest nesnesidir.


-2

Aşağıdaki kod Spring boot (kotlin) ile çalışır:

val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
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.