Java路径问题


0. 环境介绍

在Java应用程序特别是JavaWeb程序中,我们经常需要访问本程序下的文件或者外部的文件,但是如何组织文件的路径信息才可以更好的访问到文件呢?今天我们来分析一下。
首先是所需要的开发环境:
系统:Windows7
JDK:JDK1.8.0_101
IDE:Intellij IDEA 15.0.3

1. Java路径介绍

在Java处理的文件系统中,目录的表示方式有两种:

  • 绝对目录,它以”/”为起始字符,代表从根目录下开始寻找给出的目录,如/JavaPath/src/mysql.properties
  • 相对路径,它以不带”/”的目录名表示,表示以当前Java程序正在运行的目录作为起始目录来寻找给出的目录。如src/classes。在相对路径中,有一些特定的字符,可以代表特的的目录,比如,”/”代表当前目录,”//”代表当前目录的上一级目录。在网上很多给出的例子中,就是利用”.”作为目录名,构造File对象的实例,然后通过File对象的方法来获取当前程序运行的目录
    归根结底,Java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源的!

2. URL和URI

  • URI:统一资源标识符,如
    /F:/Projects/IDEA workplace/JavaPath/out/production/JavaPath/com/weegee/path/
  • URL:统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它,如https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png

URL是URI的特例,URL可以打开资源,而URI则不行。URL和URI对象可以互相转换,使用各自的toURI(),toURL()方法即可

3. J2SE的应用程序获取路径信息

项目结构(只罗列出有用的项目结构信息)

JavaPath                            # 项目名称,在F:\Projects\IDEA workplace\下
    | root.properties               # 用于测试路径的文件
    |-config                        # 用于测试路径的目录
    | | config.properties           # 用于测试路径的文件
    |-out                           # 存放编译后的类的目录
    | |-production
    | | |-JavaPath                  # classpath,在Eclipse中
                                    # out/production/JavaPath
                                    # 相当于bin目录
                                    # 存放.class文件和配置文件
    | | | | src.properties
    | | | |-com
    | | | | |-weegee
    | | | | | |-path
    | | | | | | | GetPath.class
    | | | | | | | current.properties
    |-src
    | | src.properties              # 用于测试路径的文件
    | |-com
    | | |-weegee
    | | | |-path
    | | | | | GetPath.java
    | | | | | current.properties    # 用于测试路径的文件
  • 在JVM中已经有一个属性用于输出当前程序的路径信息

    //最简单的获取Java程序根目录的方法
    System.out.println(System.getProperty("user.dir"));
    输出:F:\Projects\IDEA workplace\JavaPath

    不过这种方法不太推荐。

  • 另一种获取Java程序根目录的方法

    System.out.println(new File("").getAbsolutePath());
    输出:
    F:\Projects\IDEA workplace\JavaPath
  • 获取当前类编译后的.class文件所在的目录

    System.out.println(GetPath.class.getResource(""));
    System.out.println(GetPath.class.getResource("."));
    输出:
    file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/com/weegee/path/
  • 获取当前类编译后的.class文件所在的目录的上层目录

    System.out.println(GetPath.class.getResource(".."));
    输出:
    file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/com/weegee/
  • 获取classpath的绝对路径

    System.out.println(GetPath.class.getResource("/"));
    System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));
    System.out.println(GetPath.class.getClassLoader().getResource(""));
    System.out.println(ClassLoader.getSystemResource(""));
    输出:
    file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/

    不过由于第二种方式适用性更好,因此更加推荐使用。

  • 获取和当前类编译后的.class文件同一文件夹下的文件路径

    System.out.println(GetPath.class.getResource("current.properties"));
    输出:
    file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/com/weegee/path/current.properties

    上面我们可以看到路径的表示方法都是前缀file:并且空格被转化为了%,这用我们再使用获取的路径拼装路径信息的时候就会出错,使用getFile()或者getPath()可以去除前面的file:前缀

    System.out.println(GetPath.class.getResource(""));
    输出:file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/com/weegee/path/
    System.out.println(GetPath.class.getResource("").getPath());
    System.out.println(GetPath.class.getResource("").getFile());
    输出:
    /F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/com/weegee/path/

    不过%还是存在,可以使用URLDecoder.decode

    try {
            System.out.println(URLDecoder.decode(GetPath.class.getResource("").getPath(),"UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    输出:
    /F:/Projects/IDEA workplace/JavaPath/out/production/JavaPath/com/weegee/path/

    不过URLDecoder.decode并不能处理路径中的+,因此我们更常采用另一种方法toURI()

    try {
            System.out.println(GetPath.class.getResource("").toURI().getPath());
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
  • 得到当前类的包名

    System.out.println(GetPath.class.getPackage().getName());
    输出:
    com.weegee.path

在Java访问文件中,访问范围有三种
1. 路径信息不以”/”开头,如
src.propertiescom/weegee/path/current.properties,这种方式默认是从此类所在的包下取资源,若不存在则向上层目录中寻找,最多寻至classapth目录下,若能不存在则显示找不到,抛出空指针异常;
2. 路径信息以”/”开头,如
/src.properties或者/com/weegee/path/current.properties,默认从classpath下获取资源,访问范围仍是只在classpath目录下;
3. 绝对路径信息,可在任意存在的路径取资源,如
F:\Projects\all\other.properties./root.propertiesconfig/config.properties等。

具体实现:

  • 接受不以”/”开头的路径的获取文件的方法
    使用当前类名.class.getResource()

    System.out.println(GetPath.class.getResource("current.properties"));
    输出:
    file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/com/weegee/path/current.properties

    特殊情况(不能有文件扩展名)

    ResourceBundle resourceBundle = ResourceBundle.getBundle("com/weegee/path/current", Locale.getDefault());
  • 接受以”/”开头的路径的获取文件的方法

    System.out.println(Thread.currentThread().getClass().getResource("/src.properties"));
    输出:
    file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/src.properties
    
      System.out.println(Thread.currentThread().getClass().getResource("/com/weegee/path/current.properties"));
    输出:
    file:/F:/Projects/IDEA%20workplace/JavaPath/out/production/JavaPath/com/weegee/path/current.properties

    使用当前类名.class.getResourceAsStream()

    nputStream inputStream = GetPath.class.getResourceAsStream("/src.properties");
    InputStream inputStream = GetPath.class.getResourceAsStream("/com/weegee/path/current.properties");
  • 接受任何存在的路径的方法

    InputStream inputStream = new FileInputStream("F:\\Projects\\all\\other.properties");
    //拼接的路径信息
    InputStream inputStream = new FileInputStream(GetPath.class.getResource("").toURI().getPath() + "current.properties");
    //等价于new FileInputStream("./root.properties");
    InputStream inputStream = new FileInputStream("root.properties");
    //等价于new FileInputStream("./config/config.properties");
    InputStream inputStream = new FileInputStream("config/config.properties");

在具体使用的时候,我们最好能够自己获取基本路径信息然后再拼接成完整的路径信息。

4. J2EE的应用程序获取路径信息

首先也是看下项目结构(只罗列必要的目录和文件)

JavaWebPath                                 # 项目名称,在F:\Projects\IDEA workplace\JavaWebPath
    |-out                                   # 输出路径
    | |-artifacts                           # 相当于tomcat下的webapps目录
    | | |-JavaWebPath_war_exploded          
    | | |...
    |-src
    | | src.properties                      # 测试用的文件
    | |-com
    | | |-weegee
    | | | |-path
    | | | | |-web
    | | | | | GetPathServlet.java           # servlet
    |-web
    | |-WEB-INF
    | | | | index.jsp
    | | | |-WEB-INF
    | | | | |-web.xml
    | | | | |-classes                       # 编译后的目录
    | | | | | | src.properties
    | | | | | |-com
    | | | | | | |-weegee
    | | | | | | | |-path
    | | | | | | | | |-web
    | | | | | | | | | GetPathServlet.class
    | | | | |-lib

获取JavaWeb项目下的路径有了两种方法,在Servlet中获取和在JSP中获取。

  • Servlet获取路径信息,下面是一个servlet.java文件
import javax.servlet.ServletException;
import java.io.IOException;

public class GetPathServlet extends javax.servlet.http.HttpServlet {

    public void init() throws ServletException {
        System.out.println("当前web应用的绝对路径:" + this.getServletContext().getRealPath("/"));
        //在J2SE中打印项目绝对路径的方法在这里却是打印的tomcat的bin目录
        System.out.println("Tomcat的bin目录:" + System.getProperty("user.dir"));
    }
    protected void doPost(javax.servlet.http.HttpServletRequest request,
                          javax.servlet.http.HttpServletResponse response)
            throws javax.servlet.ServletException, IOException {

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request,
                         javax.servlet.http.HttpServletResponse response)
            throws javax.servlet.ServletException, IOException {

        System.out.println("当前servlet的相对路径:" + request.getServletPath());
        System.out.println("当前servlet的绝对路径:" + request.getSession().getServletContext().getRealPath(request.getRequestURI()));
        System.out.println("index.jsp的绝对路径:" +  request.getSession().getServletContext().getRealPath("/index.jsp"));
        System.out.println("当前web应用的绝对路径:" +  request.getSession().getServletContext().getRealPath("/"));
        System.out.println("当前web应用的绝对路径:" +  request.getSession().getServletContext().getRealPath(""));
        System.out.println("当前web应用的绝对路径:" +  request.getServletContext().getRealPath("/"));
        System.out.println("当前web应用的绝对路径:" +  request.getServletContext().getRealPath(""));
        System.out.println("当前web应用的绝对路径:" +  this.getServletConfig().getServletContext().getRealPath("/"));
        System.out.println("当前web应用的绝对路径:" +  this.getServletConfig().getServletContext().getRealPath(""));
    }
}

在浏览器访问servlethttp://localhost:8080/servlet/GetPathServlet,输出的信息为

当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\
Tomcat的bin目录:D:\Program Files\Apache Software Foundation\Tomcat 9.0\bin
当前servlet的相对路径:/servlet/GetPathServlet
当前servlet的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\servlet\GetPathServlet
index.jsp的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\index.jsp
当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\
当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\
当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\
当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\
当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\
当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\
  • 在JSP页面获取路径信息,我们的web项目发布以后,存在客户端浏览和服务端浏览。客户端是通过URL访问的,如http://localhost:8080/index.jsp,而服务器端则是通过文件路径访问的如使用绝对路径F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\index.jsp或者相对路径(推荐使用相对路径)/index.jsp
    index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.io.File" %>
<html>
  <head>
    <title>路径信息</title>
  </head>
  <body>
  <p>当前web应用的绝对路径:<%= pageContext.getServletContext().getRealPath("") %></p>
  <p>src.properties的绝对路径:<%= pageContext.getServletContext().getRealPath("/WEB-INF/classes/src.properties") %></p>
  <p>当前文件(jsp文件)的相对路径(客户端):<%= request.getRequestURI() %></p>
  <p>当前文件(jsp文件)的绝对路径(客户端):<%= request.getRequestURL() %></p>
  <p>当前文件(jsp文件)的绝对路径(服务器端):<%= application.getRealPath(request.getRequestURI()) %></p>
  <p>取得请求文件(当前jsp问件)的上层目录绝对路径:<%= new File(application.getRealPath(request.getRequestURI())).getParent()%></p>
  <p>当前web应用的绝对路径:<%= application.getRealPath("/") %></p>
  </body>
</html>

输出信息如下

当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\

src.properties的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\WEB-INF\classes\src.properties

当前文件(jsp文件)的相对路径(客户端):/index.jsp

当前文件(jsp文件)的绝对路径(客户端):http://localhost:8080/index.jsp

当前文件(jsp文件)的绝对路径(服务器端):F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\index.jsp

取得请求文件(当前jsp问件)的上层目录绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded

当前web应用的绝对路径:F:\Projects\IDEA workplace\JavaWebPath\out\artifacts\JavaWebPath_war_exploded\

5. 总结

在实际的项目使用中,若是在项目内的路径获取,一般推荐使用相对路径。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值