I have a SpringBoot 2.0.1.RELEASE mvc application. In the resources folder I have a folder named /elcordelaciutat.
In the controller I have this method to read all the files inside the folder
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;
running the app. from Eclipse is working fine, but when I run the app in a Windows Server I got this error:
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
I unzipped the generated jar file and the folder is there !
and the structure of the folders is
elcordelaciutat/folder1/*.txt
elcordelaciutat/folder2/*.txt
elcordelaciutat/folder3/*.txt
I found the combination of ResourceLoader
and ResourcePatternUtils
to be the most optimum way of listing/reading files from a classpath resource folder in a Spring Boot application:
@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());
}
}
Updates
If you want to fetch all the files including the files in subfolders of elcordelaciutat
, you need to include the following pattern classpath*:elcordelaciutat/**
. This would retrieve the files in the subfolders including the subfolders. Once you get all the resources, filter them based on .txt
file extension. Here are the changes you need to make:
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());
}
Let's say if you have the following resources folder structure:
+ resources
+ elcordelaciutat
- FileA.txt
- FileB.txt
+ a-dir
- c.txt
+ c-dir
- d.txt
+ b-dir
- b.txt
After filtering, the list will contain the following strings:
elcordelaciutat/FileA.txt
elcordelaciutat/FileB.txt
elcordelaciutat/a-dir/c-dir/d.txt
elcordelaciutat/a-dir/c.txt
elcordelaciutat/b-dir/b.txt
Note
When you want to read a resource, you should always use the method getInputStream()
.
When you start your project from Eclipse, the generated class files and resources are actually just files and folders on your hard drive. This is why it works to iterate over these files with the File
class.
When you build a jar
, all content is actually ziped and stored in a single archive. You can not access is with file system level tools any more, thus your FileNotFound
exception.
Try something like this with the 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")) {
// ...
}
}
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);
}
Later in client code or in code of some other module code you can even get its bytes:
...
Resource resource = getCurrentResource();
byte[] data = StreamUtils.copyToByteArray(resource.getInputStream());
来源:https://stackoverflow.com/questions/49774517/reading-files-in-a-springboot-2-0-1-release-app