[英]How to list all files from resources folder with scala
Assume the following structure in your recources folder:假设您的资源文件夹中的结构如下:
resources
├─spec_A
| ├─AA
| | ├─file-aev
| | ├─file-oxa
| | ├─…
| | └─file-stl
| ├─BB
| | ├─file-hio
| | ├─file-nht
| | ├─…
| | └─file-22an
| └─…
├─spec_B
| ├─AA
| | ├─file-aev
| | ├─file-oxa
| | ├─…
| | └─file-stl
| ├─BB
| | ├─file-hio
| | ├─file-nht
| | ├─…
| | └─file-22an
| └─…
└─…
The task is to read all files for a given specification spec_X
one subfolder by one.任务是逐个读取给定规范spec_X
的所有文件。 For obvious reasons we do not want to have the exact names as string literals to open with Source.fromResource("spec_A/AA/…")
for hundreds of files in the code.出于显而易见的原因,我们不希望使用Source.fromResource("spec_A/AA/…")
打开代码中数百个文件的确切名称作为字符串文字。
Additionally, this solution should of course run inside the development environment, ie without being packaged into a jar.此外,该解决方案当然应该在开发环境中运行,即无需打包到 jar 中。
The only option to list files inside a resource folder I found is with nio's Filesystem concept, as this can load a jar-file as a file system.我发现在资源文件夹中列出文件的唯一选项是使用 nio 的文件系统概念,因为这可以将 jar 文件作为文件系统加载。 But this comes with two major downsides:但这有两个主要缺点:
Collectors.toList()
cannot be made to compile as it cannot determine the right type. java.nio uses java Stream API, which I cannot collect from inside scala code: Collectors.toList()
cannot be made to compile as it cannot determine the right type.First lazy load the jar-filesystem if needed如果需要,首先延迟加载 jar 文件系统
private static FileSystem jarFileSystem;
static synchronized private FileSystem getJarFileAsFilesystem(String drg_file_root) throws URISyntaxException, IOException {
if (jarFileSystem == null) {
jarFileSystem = FileSystems.newFileSystem(ConfigFiles.class.getResource(drg_file_root).toURI(), Collections.emptyMap());
}
return jarFileSystem;
}
next do the limbo to figure out whether we are inside the jar or not by checking the protocol of the URL and return a Path.接下来通过检查 URL 的协议并返回路径来确定我们是否在 jar 内。 (Protocol inside the jar file will be jar:
(jar 文件中的协议将为jar:
static Path getPathForResource(String resourceFolder, String filename) throws IOException, URISyntaxException {
URL url = ConfigFiles.class.getResource(resourceFolder + "/" + filename);
return "file".equals(url.getProtocol())
? Paths.get(url.toURI())
: getJarFileAsFilesystem(resourceFolder).getPath(resourceFolder, filename);
}
And finally list and collect into a java list最后列出并收集到 java 列表中
static List<Path> listPathsFromResource(String resourceFolder, String subFolder) throws IOException, URISyntaxException {
return Files.list(getPathForResource(resourceFolder, subFolder))
.filter(Files::isRegularFile)
.sorted()
.collect(toList());
}
Only then we can go back do Scala and fetch is只有这样我们才能 go 回做 Scala 并获取
class SpecReader {
def readSpecMessage(spec: String): String = {
List("CN", "DO", "KF")
.flatMap(ConfigFiles.listPathsFromResource(s"/spec_$spec", _).asScala.toSeq)
.flatMap(path ⇒ Source.fromInputStream(Files.newInputStream(path), "UTF-8").getLines())
.reduce(_ + " " + _)
}
}
object Main {
def main(args: Array[String]): Unit = {
System.out.println(new SpecReader().readSpecMessage(args.head))
}
}
I put a running mini project to proof it here: https://github.com/kurellajunior/list-files-from-resource-directory我在这里放了一个正在运行的迷你项目来证明它: https://github.com/kurellajunior/list-files-from-resource-directory
But of course this is far from optimal.但这当然远非最佳。 I wanto to elmiminate the two downsides mentioned above so, that我想消除上面提到的两个缺点,所以,
Ok, after some trying and analyzing the Collector's API I was able to create a scala.List via ListBuffer collector.好的,经过一些尝试和分析收集器的 API 我能够通过 ListBuffer 收集器创建 scala.List。
class SpecReader (val spec:String) {
private val basePath = s"/spec_$spec"
lazy val jarFileSystem: FileSystem = FileSystems.newFileSystem(getClass.getResource(basePath).toURI, Map[String, String]().asJava);
def readSpecMessageScala(): String = {
List("CN", "DO", "KF")
.flatMap(listPathsFromResource)
.flatMap(path ⇒ Source.fromInputStream(Files.newInputStream(path), "UTF-8").getLines())
.reduce(_ + " " + _)
}
val collector: Collector[_ >: Path, ListBuffer[Path], List[Path]] = Collector.of(
new Supplier[ListBuffer[Path]]() {
override def get(): ListBuffer[Path] = ListBuffer[Path]()
},
new BiConsumer[ListBuffer[Path], Path]() {
override def accept(t: ListBuffer[Path], u: Path): Unit = t.addOne(u)
},
new BinaryOperator[ListBuffer[Path]]() {
override def apply(t: ListBuffer[Path], u: ListBuffer[Path]): ListBuffer[Path] = t.addAll(u)
},
new Function[ListBuffer[Path], List[Path]](){
override def apply(v1: ListBuffer[Path]): List[Path] = v1.toList
},
Array[Collector.Characteristics](): _*
)
def listPathsFromResource(folder: String): List[Path] = {
Files.list(getPathForResource(folder))
.filter(p ⇒ Files.isRegularFile(p, Array[LinkOption](): _*))
.sorted.collect(collector)
}
private def getPathForResource(filename: String) = {
val url = classOf[ConfigFiles].getResource(basePath + "/" + filename)
if ("file" == url.getProtocol) Paths.get(url.toURI)
else jarFileSystem.getPath(basePath, filename)
}
}
object Main {
def main(args: Array[String]): Unit = {
System.out.println(new SpecReader(args.head).readSpecMessage())
}
}
special attention was necessary for the empty varargs and empty setting maps.需要特别注意空可变参数和空设置映射。
Still the case for testing and jar operation.仍然是测试和 jar 操作的情况。 Git updated, PUll requests welcome: https://github.com/kurellajunior/list-files-from-resource-directory Git 已更新,欢迎请求请求: https://github.com/kurellajunior/list-files-from-resource-directory
Here's a function for reading all files from a resource folder.这是用于从资源文件夹中读取所有文件的 function。 My use case is with small files.我的用例是小文件。 Inspired by Jan's answers, but without needing a user-defined collector or messing with Java.受 Jan 的回答启发,但不需要用户定义的收集器或弄乱 Java。
// Given a folder (e.g. "A"), reads all files under the resource folder (e.g. "src/main/resources/A/**") as a Seq[String].
def readFilesFromResource(folder: String): Seq[String] = {
// Helper for reading an individual file.
def read(path: Path): String =
Source.fromInputStream(Files.newInputStream(path), "UTF-8").getLines.mkString("\n")
val uri = Main.getClass.getResource("/" + folder).toURI
Files.list(Paths.get(uri)).collect(Collectors.toList()).asScala.map(read) // Magic!
}
(not catered to example in question) (不适合有问题的示例)
Relevant imports:相关进口:
import java.nio.file._
import scala.collection.JavaConverters._ // Needed for .asScala
import java.util.stream._
import scala.io.Source
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.