当前位置: 首页 > 知识库问答 >
问题:

从java中的资源文件夹访问文件(运行JavaScript文件)

山森
2023-03-14

我正在尝试从一个java项目运行一个javascript文件。目前,我正在使用Nashorn java脚本引擎运行脚本,并使用maven编译和创建jar文件。

我得到警告:

Warning: Nashorn engine is planned to be removed from a future JDK release

我使用的是openjdk 11版本。这会是一个很大的问题吗?如果是这样的话,我要做的事情的最佳替代方案是什么?

我得到了一个FileNotFoundException

Java.io.FileNotFoundException: /Script.js (No such file or directory)

我有一个javascript文件脚本。js和两个java文件,应用程序。java,其中包括我的主要方法和过程。正在尝试查找javascript文件的java。

src
 ┣ main
 ┃ ┣ java
 ┃ ┃ ┗ com
 ┃ ┃ ┃ ┗ group
 ┃ ┃ ┃ ┃ ┣ App.java
 ┃ ┃ ┃ ┃ ┗ Processor.java
 ┃ ┗ resources
 ┃ ┃ ┗ Script.js
 ┗ test
 ┃ ┗ java
 ┃ ┃ ┗ com
 ┃ ┃ ┃ ┗ group
 ┃ ┃ ┃ ┃ ┗ AppTest.java

应用程序。java文件将构造一个处理器对象并调用函数connect。

public class App 
{
    public static void main( String[] args )
    {
        Processor p = new Processor();
        p.connect();
    }
}

Process.java

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.io.FileReader;
import java.io.FileNotFoundException;

public class Processor {

...

  /*LINK TO JAVASCRIPT*/
    public void connect(){
        // get instance of the JavaScript engine
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("nashorn");
 
        // Load and execute the script
        try {
            engine.eval(new FileReader("/Script.js"));
        }
        catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
        catch (ScriptException ex) {
            ex.printStackTrace();
        }
    }
    
}

我发现这可能会有所帮助:

getClass().getClassLoader().getResourceAsStream("/Script.js");

然而,这将返回一个InputStream,有没有一种方法可以从InputStream运行javascript文件,或者将InputStream作为字符串获取?

共有1个答案

董子航
2023-03-14

我使用的是OpenJDK 11版本。这会是一个很大的问题吗?

我可以这么说。JDK15是第一个不包含nashorn的JDK。最新的“长期支持”版本是JDK17,而当前的OpenJDK版本是18,所以在这一点上,是的,这是一个大问题。

如果是这样,对我正在努力做的事情来说,什么是最好的选择?

与其依赖JDK附带的javascript引擎,你应该选择一个第三方javascript引擎,并将其与你的应用程序一起提供。Java应用程序应该有许多许多依赖项(也许是数百个)——JDK不附带Web模板引擎、Web路由、数据库交互库(JDBC附带JDK,但它不打算直接使用,它更像是构建在JDBI、JOOQ和HiberNate等底层库之上的),等等。有目的地——JDK永远不能破坏向后兼容性,这对许多类型的库来说太难了。解决方案是使用强大而广泛的开源库。每个流行的java构建工具(无论是Maven、Gradle,甚至是蚂蚁常春藤)都让它变得非常简单;只需将你想要的库的GAV(Group::Artiface::Version)ID放在你的构建文件中,这个工具就可以处理一切(从镜像服务器网络下载它,保持它最新的工具,运输它,等等)。

这是一个将GraalVM javascript引擎添加到项目中的教程。它不是唯一的javascript引擎,你还有其他选择。但是它展示了原理。

new FileReader(“/Script.js”)

在java中,File的意思是文件。jar文件中的条目不是文件。因此,FileReader?您已经丢失了,不能将这些东西用于资源。

您想要使用的是GRAS机制:让java的classloader基础设施从加载类文件的同一位置加载资源(可以这样想:类文件是资源——没有它们,java应用程序就无法工作,JVM本身需要在应用程序运行时加载它们。比如说,GUI的图标文件,或者你想通过javascript引擎抛出的javascript,为什么会有什么不同呢?)

唯一的办法就是GRAS。它有两种形式:

一些API有一个接受URL的方法。例如,ImageIcon和java提供的GUI库中的大多数其他东西(摇摆、JavaFX等)。对于这些:

class Example {
  void example() {
    URL resource = Example.class.getResource("foo.png");
    new ImageIcon(resource);
  }
}

如果API不提供采用URL的方法变量,那么肯定有一种方法可以采用InputStream(对于基于字节的内容,如图像文件)或阅读器(对于基于字符的内容,如javascript)。通过指定字符集编码,您可以轻松地将inputstream转换为读取器:

try (InputStream in = ...) {
  Reader r = new InputStreamReader(in, StandardCharsets.UTF_8);
  somethingThatNeedsAReader(r);
}

考虑到这些是资源,您必须安全地关闭它们,因此需要使用资源进行尝试(如果必须,请滚动您的try/finally)。否则,你的应用程序最终会因为文件句柄不足而崩溃。

所以,我们需要知道的就是如何获取InputStream对象——因为我们可以使用上述技巧将它们转化为读取器。它的工作原理如下:

try (InputStream in = Example.class.getResourceAsStream("foo.js")) {
  ....
}

传递给getResourcegetResourceAsStream的字符串不是一个完整的文件路径。它与示例的位置相同。class(包含示例类代码的类文件)位于,即使它位于jar文件中。即使它是动态生成的,动态下载的——java的类加载器系统是一个抽象概念,谁知道它是如何加载这些内容的。这就是重点:你只需要从任何地方加载。

这样的条目有一个“根”——你也可以从根开始,在它前面加一个斜杠。

例:

  1. 在包com中有一个名为Example的类。foo

然后,您可以使用以下任一选项将该资源作为输入流加载:

Example.class.getResource("js/myapp.js"); // relative to com/foo
Example.class.getResource("/com/foo/js/myapp.js"); // relative to root

它不是一个文件系统- 不起作用。如果它出现在/js/myapp中。js,那么领先的斜杠策略是唯一的选择。

这些在教程和答案中很常见,但千万不要使用它们:

  1. getClass()。getResource而不是示例。班getResource-如果有人将其子类化,则getClass技巧将失效。这不太可能,但为什么要编写更糟糕的代码呢?避免风格指南的争论,并使用在更多情况下都能正常工作的版本
  2. 示例。班getClassLoader()。getResource()-这是不必要的长,删除了使用相对路径的能力,在某些情况下会中断。例如,作为引导加载加载加载的类没有类加载程序,因此上面的代码会抛出NullPointerException。但例如String。班getResource(“String.class”)工作正常

资源加载器系统只有“加载资源”的“原语”。没有list()操作!-一些图书馆认为它存在,但这些都是在某些情况下会被破解的黑客。因此,如果您想要类似“我能得到js目录中所有js文件的列表吗?”答案很简单:不,那是不可能的。

一般的解决方案是制作一个文本文件,列出你感兴趣的资源,并将其保存到一个具有已知名称的文本文件中。现在,为了“伪造”一个“列出所有资源”操作,您可以使用getResource加载该文件,对其进行处理,并使用加载每个条目。依次获取资源。这正是SPI的工作原理(例如,java本身是如何发现可用的JDBC驱动程序、字符集提供程序、加密提供程序等的)。现在你知道如果你需要“列出某种类型的所有资源”,在网上搜索什么了:)

 类似资料:
  • 我有一个资源文件夹/包在我的项目的根,我"不"想要加载某个文件。如果我想加载某个文件,我会使用class.getResourceAsStream,我会没事的!!我实际上想做的是在资源文件夹中加载一个“文件夹”,循环该文件夹中的文件,并获得每个文件的流,并在内容中读取...假设在运行时之前没有确定文件名...那我该怎么办?有没有一种方法来获得一个文件夹中的文件列表在您的jar文件?请注意,带有资源的

  • 我正在从主类访问资源文件夹中的文件 我收到了这个错误: 我甚至打开了jar文件,remoteUnitsIdsInOldServer.txt文件就在那里,在类内部

  • 我有一个名为的项目,它有以下结构: 所以这两个文件的路径是: 我想读测试文件。TestDataProvider中的json。JAVA 我曾经用过 我看到从URL res=getClass(). getClassLoader(). getResources("testfile.json")返回; 有人能帮我吗?

  • 如何从资源文件夹的子文件夹中读取文件。 我在资源文件夹中有一些json文件,例如: 现在我想在我的课堂上读到这个 这是我正在尝试的,但是失败了。 不起作用,那么我正在尝试: 这两样东西都不工作。

  • 问题内容: 我的项目具有以下结构: 我有一个文件,我想从单元测试中加载文件 我有此代码不起作用。它抱怨“没有这样的文件或目录”。 我也试过了 这也不起作用。它返回。我正在使用Maven构建我的项目。 问题答案: 尝试下一个: 如果上述方法不起作用,则已在以下类中添加了各种项目:1(代码在此处)。 以下是有关如何使用该类的一些示例:

  • 资源(Asset)代表 source 文件夹中除了文章以外的所有文件,例如图片、CSS、JS 文件等。比方说,如果你的Hexo项目中只有少量图片,那最简单的方法就是将它们放在 source/images 文件夹中。然后通过类似于 ![](/images/image.jpg) 的方法访问它们。 对于那些想要更有规律地提供图片和其他资源以及想要将他们的资源分布在各个文章上的人来说,Hexo也提供了更组