【问题标题】:Tomcat server absolute file access in war webappWar webapp中的Tomcat服务器绝对文件访问
【发布时间】:2013-12-05 15:22:50
【问题描述】:

我有一个 Spring webapp,其 .war 文件已上传到 Tomcat 服务器。大多数基本功能都按预期工作 - 页面视图和表单提交。

我现在的问题是我的 webapp 需要读取和写入文件,而我不知道如何实现这一点(文件 I/O 返回java.lang.NullPointerException)。

我使用Titi Wangsa Bin Damhore 建议的以下code to get the absolute path of a given file 来了解相对于服务器的路径:

HttpSession session = request.getSession();
ServletContext sc = session.getServletContext();
String file = sc.getRealPath("src/test.arff");
logger.info("File path: " + file);

这里是输出路径:

/home/username/tomcat/webapps/appname/src/test.arff

但是当我通过WinSCP查看文件目录时,文件的实际路径是:

/home/username/tomcat/webapps/appname/WEB-INF/classes/test.arff

这是我的问题:

  1. 如何将这些路径转换为C:/Users/Workspace/appname/src/test.arff 之类的路径(我的本地计算机中的原始路径可以完美运行)?它的服务器是Apache Tomcat 6.0.35 和Apache Tomcat 6.0.35。
  2. 为什么代码返回的路径与实际路径不同?
  3. 如果文件 I/O 不适用,我可以使用哪些替代方案?

PS我只需要访问两个文件(每个文件minus 在this thread 中所建议的那样。

文件 I/O

以下是我用于访问所需文件的代码。

BufferedWriter writer;
    try {
        URI uri = new URI("/test.arff");
        writer = new BufferedWriter(new FileWriter(
            calcModelService.getAbsolutePath() + uri));

        writer.write(data.toString());
        writer.flush();
        writer.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }

【问题讨论】:

    标签: java spring tomcat file-io absolute-path


    【解决方案1】:

    读取文件:

    ServletContext application = ...;
    InputStream in = null;
    
    try {
      in = application.getResourceAtStream("/WEB-INF/web.xml"); // example
    
      // read your file
    } finally {
      if(null != in) try { in.close(); }
       catch (IOException ioe) { /* log this */ }
    }
    

    写入文件:

    ServletContext application = ...;
    File tmpdir = (File)application.getAttribute("javax.servlet.context.tempdir");
    
    if(null == tmpdir)
      throw new IllegalStateException("Container does not provide a temp dir"); // Or handle otherwise
    
    File targetFile = new File(tmpDir, "my-temp-filename.txt");
    BufferedWriter out = null;
    
    try {
      out = new BufferedWriter(new FileWriter(targetFile));
    
      // write to output stream
    } finally {
      if(null != out) try { out.close(); }
      catch (IOException ioe) { /* log this */ }
    }
    

    如果您不想使用 servlet 容器提供的 tmpdir,那么您应该使用完全在 servlet 上下文范围之外的地方,例如 /path/to/temporary/files 或类似的东西。除了可以在重新部署等时删除的真正临时文件之外,您绝对不想将容器的临时目录用于其他任何内容。

    【讨论】:

    • 我在 Google 上搜索了如何初始化 ServletContext,但他们似乎都为它创建了一个新类。如果只是为了这个类,我该如何初始化它?
    • ServletContext 是您的 servlet 应该已经可以使用的对象。我将把它留作练习,让你弄清楚在哪里获取它。提示:阅读 Servlet API javadocs。
    【解决方案2】:

    这是一场战争。您不会在其中读/写文件。

    读取很简单:将文件放在类路径中,然后作为资源读取。

    无论如何,您都不应该在 Web 应用程序中编写代码,因为即使它不是 WAR,上下文中的内容也可能在重新部署期间消失,或者它可能只在一台服务器上如果你是集群的,等等。相反,文件写入应该存在于可配置的地方。

    【讨论】:

    • 谢谢。好的,这些文件已经在类路径中 (/root/src/) 但我如何将它们作为资源读取?我需要在xml 文件中声明它们吗?
    • @thekalaban stackoverflow.com/q/1464291/438992 例如,尽管这在 SO 和一般网络上都可以轻松搜索。
    • 如果你发现自己打电话给getRealPath,那么你做错了。
    【解决方案3】:

    除非出于某种原因您确实需要java.io.File,否则请从类路径加载文件,不要担心它的来源。

    getClass().getClassLoader().getResourceAsStream("test.arff")
    

    【讨论】:

    • 好的,我明白了,所以对于test.arff,我将使用此代码创建并阅读它,对吗?我的另一个只读文件位于/home/username/tomcat/webapps/appname/WEB-INF/classes/mlp.model 呢?我如何访问它?
    • 我认为以classes/ 结尾的任何内容都应该在类路径中,因此您可以使用此方法。你不能这样写文件,你也不应该真的想要写到WEB-INF。
    • @thekalaban 你使用getServletContext().getResource("/WEB-INF/classes/mlp.model")。阅读 API 一段时间。它将为您的工作效率创造奇迹。
    • @ChristopherSchultz 为什么你更喜欢类加载器?
    • ClassLoader 只会在WEB-INF/classes 和WEB-INF/lib/*.jar 中查找,而使用ServletContainer 的getResource 方法将允许您加载对@ 不可用的资源987654333@。例如,您可以加载 /WEB-INF/config/foo.properties,而 ClassLoader 则无法做到这一点。
    【解决方案4】:

    我像这样使用yawn 建议的Spring Resource component to get my file path (注意 test.arff 在war 部署之前位于root/src):

    Resource resource = new ClassPathResource("/test.arff");
    String arffPathRaw = resource.getURI().toString(); // returns file:/path/to/file
    String arffPath = arffPathRaw.replace("file:/", ""); // pure file path
    

    接下来,我只是将arff 连接到我想要的文件中:

    URI uri = new URI("test.arff");
    BufferedWriter writer = new BufferedWriter(new FileWriter(
            arffPath + uri));
    

    我直接在其中使用了arffPath 只是为了一个简单的示例,但我创建了一个函数,这样会更方便。

    1. 文件路径实际上是/home/username/tomcat/webapps/bosom/WEB-INF/classes/test.arff,所以不要害怕使用它(就像我一样),因为它看起来不像C:/path/to/filelmao

    2. 这两个文件路径是相同的,如果用于获取文件不要混淆。

    【讨论】:

    • 除非您的 web 应用程序部署为分解的 WAR 文件,否则此解决方案将不起作用。因此它很脆弱。使用ClassLoader 或ServletContext 获取资源是一种更强大的解决方案。此解决方案似乎使用ClassLoader,但随后破坏了 URL 并使用标准文件 I/O 加载资源。 :(
    • @ChristopherSchultz,您能否提供一个我可以模仿的工作代码?
    • 您应该使用可以在“javax.servlet.context.tempdir”键下的ServletContext 中找到的File 属性。或者,您应该将文件完全存储在 Web 应用程序之外的已知位置(例如,/some/place/for/temp/files)。
    猜你喜欢
    • 1970-01-01
    • 2018-10-24
    • 2012-10-29
    • 2014-01-13
    • 1970-01-01
    • 2018-07-25
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多