Search code examples
javaspringtomcatfile-ioabsolute-path

Tomcat server absolute file access in war webapp


I have a Spring webapp whose .war file has been uploaded to a Tomcat server. Most of the basic functions are working as intended - page views and form submission.

My problem now is that my webapp needs to read and write files and I am clueless as to how I can achieve this (the file I/O returns java.lang.NullPointerException).

I used the following code to get the absolute path of a given file suggested by Titi Wangsa Bin Damhore to know the path relative to the server:

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

Here is the output path:

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

But when I checked the file directory via WinSCP, the file's actual path is:

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

Here are my questions:

  1. How do I transform these paths into something like C:/Users/Workspace/appname/src/test.arff (the original path in my local machine that works perfectly)? It's servers are Apache Tomcat 6.0.35 and Apache Tomcat 6.0.35.
  2. Why is the code returning a different path as opposed to the actual path?
  3. If file I/O is not applicable, what alternatives can I use?

PS I just need to access two files (< 1MB each) so I don't think I may need to use a database to contain them as suggested by minus in this thread.

File I/O

Below is the code I use for accessing the file I need.

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();
    }

Solution

  • To read files:

    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 */ }
    }
    

    To write files:

    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 */ }
    }
    

    If you don't want to use the tmpdir provided by the servlet container, then you should use someplace that is entirely outside of the servlet context's purvue, like /path/to/temporary/files or something like that. You definitely don't want to use the container's temporary directory for anything other than truly temporary files which are okay to delete on re-deployment, etc.