关于idea中访问上下文txt文件返回空指针的BUG

本文讲述了在IntelliJ IDEA中通过上下文对象访问资源文件时遇到空指针异常的原因,涉及路径问题、IDE差异和ClassLoader使用技巧。通过调整资源文件位置和使用getClass().getClassLoader().getResourceAsStream()方法解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


问题描述

在idea中通过上下文对象访问目标文件路径会返回空指针,很明显是因为我们使用的对象方法没有找到该文件在哪。

访问的代码字段为:

InputStream is = LifeServlet.class.getResourceAsStream("count.txt");
System.out.println("目前为止是没有发生异常的1");
System.out.println("is="+is);

输出结果

在这里插入图片描述


原因分析:

这种情况比较常见,但是这个问题本身却很少遇见,一般情况下,我们会考虑是不是下面几种原因:
1.考虑相对路径出错
2.考虑text文件放置位置出错
3.考虑要使用绝对路径
但是在对上述的所有原因进行调试后,发现还是不能解决这个错误。
这时通过多方面的信息查询和询问同学,我总结出了一下的一些原因。
因为导入的war包是用eclipse新建的项目,而idea和eclipse的文件目录有些区别,idea中maven的项目中的资源文件和代码根目录文件位resourses。
同时还存在两个函数的区别(这个是真的头大):
classLoader.getResource(name):
该方法的作用与class.getResource(name)的作用一样,接收一个表示路径的参数,返回一个URL对象,该URL对象表示name对应的资源(文件)。但是,与class.getResource(name)不同的是,该方法只能接收一个相对路径,不能接收绝对路径如/xxx/xxx。并且,接收的相对路径是相对于项目的包的根
Class.getResource(name):
该方法接收一个表示文件路径的数,返回一个URL对象,该URL对象表示的name指向的那个资源(文件)。这个方法是在类中根据name获取资源。其中,name可以是文件的相对路径(相对于该class类来说),也可以是绝对路径(绝对路径的话,根目录符号/是代表项目路径而不是磁盘的根目录)


解决方案:

将上下文txt文件放在resourses中,并且将获取资源文件的代码修改成如下的代码。

//大佬说他一般是这样获取资源文件的,咱就这样改~
InputStream is = this.getClass().getClassLoader().getResourceAsStream("count.txt");
System.out.println("目前为止是没有发生异常的1");
System.out.println("is="+is);

然后就是全部的代码奉上,希望对你调试bug有帮助。

package servlet;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * @author fhzheng
 * <li>演示Servlet的生命周期
 * 同时采用了注解和xml配置
 */
@WebServlet("/LifeServlet")
public class LifeServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	// 声明计数器,上下文对象,路径
	int count;
	ServletContext sc;
	String path;
    
	/**
	 * <li> 做一些准备工作
	 * <li> 1 获取上下文环境
	 * <li> 2从上下文对象获取文件路径
	 * <li> 3读取文件中的信息
	 * <li> 
	 * <li> 注意,首次读取时,因为没有文件,可能会有异常Null
	 * <li> 然后用不同的浏览器来访问时,就可以看到共享的计数了
	 */
	public void init() throws ServletException{
		//count = 0;
		System.out.println("在init中完成计数器的初始化begin");
        //WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用
		//而下面两行代码是获取该web应用的ServletContext对象
		//servletContext封装有上下文对象
		sc = this.getServletContext();
		//因为idea和ecplice的习惯不一样,这里需要修改
		//这里只是获取路径,修改这里无意义
		//上面两句话纯属放屁,web项目运行的时候所在的路径和本地路径不相同
		// 而对于web-inf中的文件全部映射到了根目录下
		//所以最终修改成如下就能找到count文件了。
		path = sc.getRealPath("count.txt");
//		System.out.println(path);
		try {
			//功能:根据参数给定的名称,查找文件资源,并且进行加载为字节输入流
			//这里好像没有执行吧
			//上面那句纯属废话,首先txt文件要放在resources中,同时写法换成下面哪个。
//			InputStream is = LifeServlet.class.getResourceAsStream("count.txt");
			InputStream is = this.getClass().getClassLoader().getResourceAsStream("count.txt");
			System.out.println("目前为止是没有发生异常的1");
			System.out.println("is="+is);
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			System.out.println("目前为止是没有发生异常的2");
			String string = br.readLine();
			System.out.println("读到的字符串是:"+string);
			count = Integer.parseInt(string);
			br.close();
			is.close();
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("没有找到文件!!!");
		}
		String Path= this.getClass().getResource("").getPath();
		//输出两个路径看看情况
//		System.out.println(path);
		//调试发现Path路径是存放.class文件的路径
//		输出为:/D:/workspace/jee/jee-ex05/target/jee-ex05-1.0-SNAPSHOT/WEB-INF/classes/servlet/
		System.out.println(Path);
		System.out.println("在init中完成计数器的初始化end");
	}
	
	/**
	 * <li> 销毁
	 */
	public void destroy() {
		System.out.println("Servlet已经释放");
	}
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LifeServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * <li> 处理输出到响应中的信息
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		count++;
		out.println("这个Servlet历史上已经被访问了"+count+"次了!");
		OutputStream fw = new FileOutputStream(path);
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fw));
		String string = String.valueOf(count);
		bw.write(string);
		bw.close();
		fw.close();
		
		System.out.println("该Servlet的doGet方法被执行了一次");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//调用了get函数,哇咔咔,和前面只有get函数有什么区别吗
		doGet(request, response);
		System.out.println("该Servlet的doPost方法被执行了一次");
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值