java读取src路径下的txt文件_Java程序使用Maven后无法运行?

93d7d97e739b74005a46d576f940ddc8.png

问:老师,同样的代码,为何我将Java工程改造成Maven后,始终无法运行?

实现的功能:加载abc.txt文件,代码是写在了Demo类中。

开发工具是Idea。

1.以下是普通Java工程的目录结构。

c7854901fdb02dbffe7b63a24d789f91.png

Demo代码如下

public class Demo {
    public static void main(String[] args)throws Exception{
        InputStream input = new FileInputStream("src/a/abc.txt") ;
        System.out.println();
    }
}

此时,程序能够正常运行。

2.现在将Java工程,改造成基于Maven的形式。目录结构如下。

eb06b9c252de3514bd57468e002c3d70.png

Demo代码如下。

public 

Java工程的classpath是src;Maven工程的classpath有一个是resources。我也做了相应修改。但为何,此时用Maven写的同样功能代码,始终报错如下。

FileNotFoundException: 

答:

(赶时间的,可以略过分析,直接看本文最后的结论和源码)

“路径问题”首先得思考一个问题:程序中使用的相对路径,是基于最终执行的字节码路径,还是源码的路径?(比如原文件是A.java,编译后的文件是A.class。那么A在加载abc.txt时,“相对路径”是以“A.java”为参照点,还是以“A.class”为参照点?。

上面这个问题,暂时放一放。先直接看一下造成你疑惑的根本原因:普通的Java工程和Maven等构件工具,对.class文件和静态资源的打包路径不同。

1.打开普通Java工程中 字节码目录,如下。

d977fe1693dd91eda15506d078edbce2.png

发现了什么?在普通Java工程中在编译及运行阶段,并不会处理静态资源(也就是会忽略abc.txt文件)。因此,要加载abc.txt,就得去它原来的位置,即在src源码目录下,如图所示。

74e5248a8b41fe6e8487f80f7a37f2b2.png

所以,在使用普通Java工程时,就需要在src下面找abc.txt(因为字节码目录中的静态资源,会被忽略)。因此,加载路径是源码src中的路径,而不是字节码classes中的路径,如下。

new 

2.但Maven工程对静态资源的处理方式则不同。

我们知道,Maven会将字节码和静态资源 都打包在 target下,如图所示。

fbabe14bd062574dc34480b4d0dc6142.png

也就是说,maven会将Demo.class和abc.txt一同打包在 字节码(target/classes)目录下。但要注意:maven默认在读取路径时, 是基于字节码classes目录,而不是源码src目录,这与普通Java工程完全相反。【因为maven的一个原则:就是想让 最终的执行程序,与源码相互隔离,互不干扰】。所以,如果使用了maven,静态资源的相对路径获取方式,就和普通Java工程不一样了(不能再从src中读取静态资源,而要从classes中读取)。

讲到这里,有同学可能会问“看上图,可知abc.txt就在Demo.class的上一级。因此在Demo.class中使用../abc.txt不就行了?”。看起来好像可以,但实际也不行。

使用../abc.txt的意思是,从当前路径开始,寻找上一级目录。这里说的当前路径好像就是字节码路径中的Demo.class文件本身。但实际情况真的是吗?使用以下代码,查看一下当前路径到底是什么。

public 

运行结果:

D:githubJavaCoresrcJavaBook.

发现 ,程序在执行时当前路径是在src下,根本不是classes字节码。这又与Maven的原则相违背(Maven默认读取的路径是字节码classes目录,而不是源码src目录)。【这种特性是jvm底层决定的,我们无法改变】。

以上,有些绕,总结就是:

java程序在使用相对路径,加载静态资源时:

1.普通Java工程加载的是源文件src目录中的静态资源;

2.Maven工程加载的是字节码目录target/classes中的静态资源;

3.在编写源码时,程序中相对路径基于的“当前路径”是在源文件src目录下 ,不是在classes目录下。(也就是当前路径是基于A.java,而不是基于A.class)。

以上三条中,“1”和“3”是一致的,所以普通Java工程方式加载静态资源,没有什么,直接写相对路径就行;但“2”和“3”在读取路径时是矛盾的,因此Maven工程在加载静态资源时,就不能使用相对路径,而需要使用绝对路径。

但还要注意,绝对路径要以动态的方式获取,防止不同环境之间的差异。

最后,给出Maven方式,获取静态资源的代码。

public 

很“简单”一个问题,是不是还挺绕人的~

- 完 -

推荐阅读

答疑 | 高并发都要学哪些技术?

答疑 | 我是JAVA初级,有必要学架构设计吗?

Java小白到大神的心路历程(Java SE)

答疑 | 面试全对,却没offer?

答疑 | 背下这300字,面试就能加薪!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值