微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

您可以在一个程序中使用2个Java Nio文件系统吗?

如何解决您可以在一个程序中使用2个Java Nio文件系统吗?

我正在编写一个项目,该项目将从模板文件夹结构(我将其打包在jar中作为资源)生成文件夹结构。我想将所有资源保留在程序的jar文件中,因此我的用户只需要了解这个jar文件,而不必担心单独的资源文件夹。

在这里有以下代码(使用Java库的Scala代码):

package ru.company.project

import java.nio.file.{FileSystems,Files,Path,Paths}
import java.util

object Main {
  def main(args: Array[String]): Unit = {
    val uri = this.getClass.getClassLoader.getResource("resource1").toURI

    // create file system
    val env = new util.HashMap[String,String]()
    env.put("create","true")
    val jarFS = FileSystems.newFileSystem(uri,env)

    val file = Paths.get(uri)

    Files.walk(file).forEach(f => {
      println(f)
      if (Files.isRegularFile(f))
        copyToLocal(f)
    })

    jarFS.close()
  }

  def copyToLocal(file: Path): Unit = {
    val content = Files.readAllLines(file)
    Files.write(file,content)
  }
}

它能够很好地从我的jar文件中读取资源,但是当它在Files.write(file,content)中执行copyToLocal时,它将失败,并出现以下异常:

Exception in thread "main" java.nio.file.FileAlreadyExistsException: resource1/another_text_file.txt
        at com.sun.nio.zipfs.ZipFileSystem.newOutputStream(ZipFileSystem.java:516)
        at com.sun.nio.zipfs.ZipPath.newOutputStream(ZipPath.java:790)
        at com.sun.nio.zipfs.ZipFileSystemProvider.newOutputStream(ZipFileSystemProvider.java:285)
        at java.nio.file.Files.newOutputStream(UnkNown Source)
        at java.nio.file.Files.write(UnkNown Source)
        at java.nio.file.Files.write(UnkNown Source)
        at ru.company.project.Main$.copyToLocal(Main.scala:28)
        at ru.company.project.Main$.$anonfun$main$1(Main.scala:20)
        at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(UnkNown Source)
        at java.util.stream.ReferencePipeline$3$1.accept(UnkNown Source)
        at java.util.Iterator.forEachRemaining(UnkNown Source)
        at java.util.Spliterators$IteratorSpliterator.forEachRemaining(UnkNown Source)
        at java.util.stream.AbstractPipeline.copyInto(UnkNown Source)
        at java.util.stream.AbstractPipeline.wrapAndcopyInto(UnkNown Source)
        at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(UnkNown Source)
        at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(UnkNown Source)
        at java.util.stream.AbstractPipeline.evaluate(UnkNown Source)
        at java.util.stream.ReferencePipeline.forEach(UnkNown Source)
        at ru.company.project.Main$.main(Main.scala:17)
        at ru.company.project.Main.main(Main.scala)

这是因为我不知何故需要使用另一个文件系统在jar文件之外进行写操作,但是似乎在执行FilesSystems.newFileSystem时会创建一个全局文件

那么,如何创建另一个文件系统并同时使用2个文件系统?

解决方法

您的方法copyToLocal(...)是错误的。它从文件读取,然后将所有读取的行再次写回到同一文件。没有“魔术机制”“知道”用于读取和写入的文件系统。

所以主要问题是: 例如Files.write(path,content)的操作如何知道使用哪个FileSystem

答案: 它使用用于创建路径的FileSystem

更长的答案Path对象始终与FileSystem相关联。它始终表示特定文件系统的文件或文件夹,因此它既包含文件系统又包含路径本身。

Files的所有静态方法,例如Files.delete(path)Files.list(path),都使用与给定路径关联的文件系统。如果两个路径都来自同一个文件系统(这是常见的情况),则优化了在多个路径上运行的方法(例如Files.copy(source,target,options)),但也应该跨不同的文件系统工作(如您的情况)。

如果您使用(1)工厂方法Paths.get(first,...more),则该路径始终与默认 FileSystem相关联。如果您使用(2)Paths.get(uri),则会在所有已安装的文件系统提供程序中搜索文件系统。如果使用(3)具体的getPath(...)的{​​{1}}方法,则路径与此文件系统相关联。

因此,您应该使用以下三种方式中的任何一种来控制应与您的路径相关联的文件系统,例如:

FileSystem

(代码段是Java,因为我不知道Scala)

这意味着您的代码:

try(FileSystem jarFs = ...;
    FileSystem defaultFs = ...) {

    Path source = jarFs.getPath(...);
    Path target = defaultFs.getPath(...);

    Files.copy(source,target);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。