Чтение файлов в приложении springboot 2.0.1.release

У меня есть mvc-приложение SpringBoot 2.0.1.RELEASE. В папке ресурсов у меня есть папка с именем / elcordelaciutat.

В контроллере у меня есть этот метод для чтения всех файлов внутри папки

ClassLoader classLoader = this.getClass().getClassLoader();
        Path configFilePath = Paths.get(classLoader.getResource("elcordelaciutat").toURI());    

        List<String> cintaFileNames = Files.walk(configFilePath)
         .filter(s -> s.toString().endsWith(".txt"))
         .map(p -> p.subpath(8, 9).toString().toUpperCase() + " / " + p.getFileName().toString())
         .sorted()
         .collect(toList());

        return cintaFileNames;

запускает приложение. из Eclipse работает нормально, но когда я запускаю приложение на Windows Server, я получил эту ошибку:

java.nio.file.FileSystemNotFoundException: null
    at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:171)
    at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:157)
    at java.nio.file.Paths.get(Unknown Source)
    at 

Я разархивировал сгенерированный файл jar, и папка там!

и структура папок

elcordelaciutat/folder1/*.txt
elcordelaciutat/folder2/*.txt
elcordelaciutat/folder3/*.txt

И фиш, и Индра-башак здесь правы. phisch - это причина, по которой вы получаете ошибку, но это потому, что вы не полностью используете функциональность Spring; на это указывает Индра-башак.

Stephan 16.04.2018 20:52

Это нерешенная проблема со стороны весенней команды: github.com/spring-projects/spring-boot/issues/7161

Akli REGUIG 17.04.2018 20:30
4
2
2 687
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Когда вы запускаете свой проект из Eclipse, сгенерированные файлы классов и ресурсы на самом деле являются просто файлами и папками на вашем жестком диске. Вот почему можно перебирать эти файлы с помощью класса File.

Когда вы создаете jar, все содержимое фактически заархивировано и хранится в одном архиве. Вы больше не можете получить доступ к инструментам уровня файловой системы, поэтому ваше исключение FileNotFound.

Попробуйте что-нибудь подобное с JarURL:

JarURLConnection connection = (JarURLConnection) url.openConnection();
JarFile file = connection.getJarFile();
Enumeration<JarEntry> entries = file.entries();
while (entries.hasMoreElements()) {
    JarEntry e = entries.nextElement();
    if (e.getName(). endsWith("txt")) {
        // ...
   }
}

Это правильный ответ. Вы пытаетесь получить доступ к пути к файловой системе из своего jar-файла. Вы не сможете этого сделать.

thesb 16.04.2018 06:02
Ответ принят как подходящий

Я обнаружил, что комбинация ResourceLoader и ResourcePatternUtils является наиболее оптимальным способом перечисления / чтения файлов из папки ресурсов пути к классам в приложении Spring Boot:

@RestController
public class ExampleController {

    private ResourceLoader resourceLoader;

    @Autowired
    public ExampleController(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    private List<String> getFiles() throws IOException {
        Resource[] resources = ResourcePatternUtils
                .getResourcePatternResolver(loader)
                .getResources("classpath*:elcordelaciutat/*.txt");

        return Arrays.stream(resources)
                   .map(p -> p.getFilename().toUpperCase())
                   .sorted()
                   .collect(toList());

    }
}

Обновления

Если вы хотите получить все файлы, включая файлы в подпапках elcordelaciutat, вам необходимо включить следующий шаблон classpath*:elcordelaciutat/**. Это позволит получить файлы во вложенных папках, включая вложенные папки. Как только вы получите все ресурсы, отфильтруйте их по расширению файла .txt. Вот что вам нужно сделать:

private List<String> getFiles() throws IOException {
    Resource[] resources = ResourcePatternUtils
            .getResourcePatternResolver(loader)
            // notice **
            .getResources("classpath*:elcordelaciutat/**");

    return Arrays.stream(resources)
               .filter(p -> p.getFilename().endsWith(".txt"))
               .map(p -> {
                   try {
                       String path = p.getURI().toString();
                       String partialPath = path.substring(
                           path.indexOf("elcordelaciutat"));
                       return partialPath;
                   } catch (IOException e) {
                            e.printStackTrace();
                   }

                   return "";
                })
               .sorted()
               .collect(toList());
}

Допустим, у вас есть следующая структура папок ресурсов:

+ resources
  + elcordelaciutat
    - FileA.txt
    - FileB.txt
    + a-dir
      - c.txt
      + c-dir
        - d.txt
    + b-dir
      - b.txt

После фильтрации список будет содержать следующие строки:

  • elcordelaciutat/FileA.txt
  • elcordelaciutat/FileB.txt
  • elcordelaciutat/a-dir/c-dir/d.txt
  • elcordelaciutat/a-dir/c.txt
  • elcordelaciutat/b-dir/b.txt

Примечание

Когда вы хотите прочитать ресурс, вы всегда должны использовать метод getInputStream().

Обратите внимание, что внутри elcordelaciutat есть также подпапки и текстовые файлы внутри подпапок.

en Peris 18.04.2018 12:23

@ enPeris..ElgothdelaCiutat Обновил мое сообщение с ответом на ваш вопрос.

Indra Basak 19.04.2018 18:58
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;
...
private static final String CURRENT_FILE = "file.txt";

public Resource getCurrentResource() {
    return new ClassPathResource(CURRENT_FILE);
}

Позже в клиентском коде или в коде какого-либо другого модуля вы можете даже получить его байты:

...
Resource resource = getCurrentResource();
byte[] data = StreamUtils.copyToByteArray(resource.getInputStream());

Другие вопросы по теме