java访问磁盘文件_java访问磁盘文件

本文详细解析了Java中访问磁盘文件的过程,从File对象的创建到FileDescriptor的使用,再到FileInputStream、FileReader、InputStreamReader以及StreamDecoder的角色和功能,揭示了Java读取文件的内部机制。
摘要由CSDN通过智能技术生成

转载,务必写上原文链接 !(尊重与你分享知识的人)

目录

文件

数据在磁盘中的唯一最小描述就是 文件 ,也就是说应用程序只能通过操控 文件 来操作磁盘上的数据;

File 对象 VS FileDescriptor 对象

初学 java IO 流的时候,基本都被告诉 java 里面用 File 来表示一个文件对象;

其实 File 并不代表一个真实存在的文件对象,当我们给定路径字符串的时候,返回的 File 对象仅仅是代表这个路径下的 虚拟对象,至于这个路径是一个文件还是一个文件夹,或者文件存在不存在,File 根本不关心 ;

只要当真正要读取这个文件的时候,才会检查给定路径的文件存在不存在(这个判断发生在读取流的构造器里面) ;

那么 java 里面,用什么来描述磁盘的文件 —— FileDescriptor 对象,它代表一个磁盘上的真实文件对象;

文件讲解java访问磁盘文件过程

// 创建一个字符读取流

FileReader fileReader = new FileReader("xxxxxx");

0、这一行代码后面都发生了什么事情;

我们要看下,这个 FileReader 到底是怎么工作的,跟进去看下源代码 ;

下面开始源码跟进分析

public FileReader(String fileName) throws FileNotFoundException {

// 调用父类构造器,传进去的参数是 FileInputStream

super(new FileInputStream(fileName));

}

----------------------------------------

// FileReader 的父类是 字节转换流

public class FileReader extends InputStreamReader

1、发现 FileReader 构造器中,是调用其父类 InputStreamReader 的构造器;

分析父类构造器参数发现,给父类构造器传递的参数是一个 FileInputStream 对象;我们同样需要看下这个类的构造器源代码;

public FileInputStream(String name) throws FileNotFoundException {

// 跟进传进来的字符串,创建对应的 虚拟对象 File

this(name != null ? new File(name) : null);

}

2、可以看见 FileInputStream 根据传进来的字符串,创建了 File 对象,然后将这个 File 对象,传给了同类的其他构造器 ;

public FileInputStream(File file) throws FileNotFoundException {

// 获取文件的路径

String name = (file != null ? file.getPath() : null);

SecurityManager security = System.getSecurityManager();

if (security != null) {

security.checkRead(name);

}

// 如果name为null,说明传进来的file就是null。抛出空指针异常

if (name == null) {

throw new NullPointerException();

}

// 判断文件是否有效,也就是判断给File对象的路径下面的文件是否真的存在的;

if (file.isInvalid()) {

throw new FileNotFoundException("Invalid file path");

}

// 创建一个代表真实文件的对象

fd = new FileDescriptor();

fd.incrementAndGetUseCount();

this.path = name;

// 打开路径下面的文件,是一个本地方法

open(name);

}

3、经过上面的代码分析,我们可以发现 FileInputStream 创建对象的时候,会对 File 构造器的路径参数进行检查,判断路径对应的文件到底存在与否;并且还会创建一个代表真实文件的 FileDescriptor 对象 ;

创建完 FileInputStream 对象以后,继续回到 FileReader 构造器上面 ;我们在上面的代码,知道 FileReader 是调用了父类 InputStreamReader 的构造器,现在我们关注一下它的父类构造器;

public FileReader(String fileName) throws FileNotFoundException {

// 调用父类构造器,传进去的参数是 FileInputStream

super(new FileInputStream(fileName));

}

----------------------------------------

public InputStreamReader(InputStream in) {

// 调用了父类构造器,里面没啥好看的,就加了锁

// 加锁的原因是因为,同一时刻一个文件只允许一个人来读取

super(in);

try {

// 创建一个 StreamDecoder 解码对象,将字节解码为字符

sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object

} catch (UnsupportedEncodingException e) {

// The default encoding should always be available

throw new Error(e);

}

}

4、查看源码,知道创建 InputStreamReader 对象,会同时创建 StreamDecoder 对象,因为我们是用字节流,最后需要的字符,所有需要它来解码

其中关于 StreamDecoder 笔者之前分析过—— StreamDecoder 对象分析(可点击)

fileReader.read()

分析完 上面,我们再看下 read()方法;看看到底是谁实现了read()接口 ;

FileReader fileReader = new FileReader("xxxxxx");

// 跟进去看看 read()方法到底是谁实现的;

fileReader.read();

---------------------------------

// 跟进去发现是调用了 一个 sd变量的read方法;

public int read() throws IOException {

return sd.read();

}

-------------------------------------

// sd的read()方法实现

private int read0() throws IOException {

Object var1 = this.lock;

synchronized(this.lock) {

if (this.haveLeftoverChar) {

this.haveLeftoverChar = false;

return this.leftoverChar;

} else {

char[] var2 = new char[2];

int var3 = this.read(var2, 0, 2);

switch(var3) {

case -1:

return -1;

case 0:

default:

assert false : var3;

return -1;

case 2:

this.leftoverChar = var2[1];

this.haveLeftoverChar = true;

case 1:

return var2[0];

}

}

}

}

---------------------------------

// 跟进发现 这个sd 是StreamDecoder 对象

private final StreamDecoder sd;

至此,我们发现底层工作都是 StreamDecoder 完成的,这个在背后默默工作的低调者,我们应该记住它;

图解java访问磁盘文件过程

82b4d225f7dc2847b9cc8b7748aafd81.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值