简体   繁体   English

如何使用 scala 列出资源文件夹中的所有文件

[英]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:但这有两个主要缺点:

  1. 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. 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.
  2. The filesystem needs different base paths for OS-filesystems and jar-file-based filesystems.对于 OS 文件系统和基于 jar 文件的文件系统,文件系统需要不同的基本路径。 So I need to manually differentiate between the two situations testing and jar-based running.所以我需要手动区分测试和基于jar的运行两种情况。

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我想消除上面提到的两个缺点,所以,

  1. scala files only仅 scala 文件
  2. no extra testing code in my production library我的生产库中没有额外的测试代码

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.

相关问题 你如何列出资源文件夹中的所有文件(java/scala) - How do you list all files in the Resources folder (java/scala) 如何从 Scala 的资源文件夹中读取文件? - How to read files from resources folder in Scala? 在 scala 中使用 spark 流从文件夹流式传输时,如何读取包括子文件夹在内的所有文件? - How do I read in all files including subfolders when streaming from folder using spark streaming in scala? Scala 不从资源文件夹中读取文件 - Scala does not read file from resources folder 如何将资源文件夹中的文件作为Scala中的InputStream读取? - How to read a file in resources folder as an InputStream in Scala? 如何将所有依赖资源从Gradle MultiProject收集到dist文件夹中 - how to gather all dependencies resources from a gradle multiproject into a dist folder 如何在 Scala 中将文件/文件从一个文件夹移动到另一个文件夹 - How to move file/files from one folder to another in Scala 如何在 Scala 中将文件从一个文件夹移动到另一个文件夹 - How to move files from one folder to another in Scala 如何在SPARK数据框创建的文件夹中合并所有零件文件并在Scala中将其重命名为文件夹名称 - How to merge all part files in a folder created by SPARK data frame and rename as folder name in scala 如何在scala中列出子目录中的所有文件? - How do I list all files in a subdirectory in scala?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM