能否在一个程序中使用2个JavaNIO文件系统?

能否在一个程序中使用2个JavaNIO文件系统?,java,scala,filesystems,java.nio.file,Java,Scala,Filesystems,Java.nio.file,我正在编写一个项目,该项目将从模板文件夹结构(我将其打包在jar中作为资源)生成一个文件夹结构。我希望将所有资源都保存在程序的jar文件中,因此我的用户只需要知道这个jar文件,而不必担心单独的资源文件夹 我这里有这段代码(使用java库的Scala代码): 它可以很好地从我的jar文件中读取资源,但是当它在copyToLocal中执行Files.write(file,content)时,它会失败,出现以下异常: Exception in thread "main" java

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

我这里有这段代码(使用java库的Scala代码):

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

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文件之外进行写操作,但是当您执行
filesystems.newFileSystem
时,它似乎会创建一个全局文件系统


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

您的方法
copyToLocal(…)
是错误的。它从一个文件中读取,然后将所有读取的行再次写回同一个文件。没有“神奇的机制”可以“知道”哪个文件系统用于读取,哪个文件系统用于写入

因此,主要问题是:
Files.write(路径、内容)
这样的操作如何知道要使用哪个
文件系统

回答:它使用用于创建路径的
文件系统

更长的回答:路径
对象始终与文件系统相关联。它始终表示特定文件系统的文件或文件夹,因此它同时包含文件系统和路径本身

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

如果使用(1)工厂方法
path.get(first,…more)
,则路径始终与默认文件系统关联。如果使用(2)
path.get(uri)
,则会搜索所有已安装的文件系统提供程序以查找该文件系统。如果(3)使用了具体的
文件系统的
getPath(…)
方法,则该路径与该文件系统相关联

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

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

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

    Files.copy(source, target);
}
(代码片段是用Java编写的,因为我不知道Scala)

这意味着您的代码:

...
val jarPath = Paths.get(uri)

Files.walk(jarPath).forEach(jarFile => {
  println(jarFile)
  if (Files.isRegularFile(jarFile))
    Files.copy(jarFile, createLocalPathFor(jarFile))
})
...

def createLocalPathFor(path: Path): Path = {
  // TODO: create a local path for the given file
  // TODO: which local folder? which local file name?
  return Paths.get(...)
}

您的方法
copyToLocal(…)
是错误的。它从一个文件中读取,然后将所有读取的行再次写回同一个文件。没有“神奇的机制”可以“知道”哪个文件系统用于读取,哪个文件系统用于写入

因此,主要问题是:
Files.write(路径、内容)
这样的操作如何知道要使用哪个
文件系统

回答:它使用用于创建路径的
文件系统

更长的回答:路径
对象始终与文件系统
相关联。它始终表示特定文件系统的文件或文件夹,因此它同时包含文件系统和路径本身

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

如果使用(1)工厂方法
path.get(first,…more)
,则路径始终与默认文件系统关联。如果使用(2)
path.get(uri)
,则会搜索所有已安装的文件系统提供程序以查找该文件系统。如果(3)使用了具体的
文件系统的
getPath(…)
方法,则该路径与该文件系统相关联

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

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

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

    Files.copy(source, target);
}
(代码片段是用Java编写的,因为我不知道Scala)

这意味着您的代码:

...
val jarPath = Paths.get(uri)

Files.walk(jarPath).forEach(jarFile => {
  println(jarFile)
  if (Files.isRegularFile(jarFile))
    Files.copy(jarFile, createLocalPathFor(jarFile))
})
...

def createLocalPathFor(path: Path): Path = {
  // TODO: create a local path for the given file
  // TODO: which local folder? which local file name?
  return Paths.get(...)
}

谢谢,我应该写什么来代替“…”?我需要访问jar和本地fs中的文件。“…”取决于本地目标文件的本地文件夹和文件名。您必须根据jar文件中的文件名“计算”它。请参阅我的扩展答案,了解一些方法。嗯,您的代码似乎至少还有其他问题:您使用了错误的URI来创建jar文件系统。URI应该具有模式
jar:
。在您的情况下,它似乎只是
。看吧,它仍然可以工作,显然,当您这样做时,它会自动插入“jar:”部分。getClass.getClassLoader.getResource(“resource1”)。“resource1”是jar中执行代码的文件夹。这是我运行的代码,您可以运行“mvn clean package”,这将构建一个胖jar,并将“resource”文件夹放入这个jar中。然后您可以运行jar文件,您将看到它是有效的。谢谢,我应该写什么来代替“…”?我需要访问jar和本地fs中的文件。“…”取决于本地目标文件的本地文件夹和文件名。您必须根据jar文件中的文件名“计算”它。请参阅我的扩展答案,了解一些方法。嗯,您的代码似乎至少还有其他问题:您使用了错误的URI来创建jar文件系统。URI应该具有模式
jar:
。在您的情况下,它似乎只是
。看吧,它仍然有效,很明显