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


目录


文件

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


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访问磁盘文件过程


java访问磁盘文件的更多相关文章

  1. java访问修饰符

    了解面向对象思想的同学们,都知道"封装"这一基本特征,如何正确运用访问修饰符,恰恰能体现出封装的好坏. java访问修饰符有四个: 1)public:访问权限最高,其修饰的类.类变 ...

  2. [THINKING IN JAVA]访问权限控制

    6 访问权限控制 6.1 包:库单元 package.import.import *.import static: 修改classpath环境变量可以将自己写的类库添加至环境变量并在任何java程序中 ...

  3. java 访问 usb

    java 要访问 usb 设备,通常要自己写c/c++代码,然后再用 java 访问这些组件,以达到控制usb设备的目的.但现在有一个开源组件 libusb 帮我们做好了访问usb设备的封装(包括wi ...

  4. Java访问USB设备

    最近在用Java访问RDing设备,使用的是Java HID API.使用过程中发现一个问题,由于是嵌入式小白,不知道如何向USB设备发送report.于是想到可以看看自带的软件如何访问USB的.找到 ...

  5. java访问权限的问题

    java访问权限的问题 java 访问权限 修饰符 背景: 关于java中的四种访问修饰符,public ,default ,protected ,private的作用范围本以为很熟悉了,但碰到了这样 ...

  6. Hadoop(五)搭建Hadoop与Java访问HDFS集群

    前言 上一篇详细介绍了HDFS集群,还有操作HDFS集群的一些命令,常用的命令: hdfs dfs -ls xxx hdfs dfs -mkdir -p /xxx/xxx hdfs dfs -cat ...

  7. java访问权限修饰符

    作用域 当前类 同一package 子孙类 其他package public √ √ √ √ protected √ √ √ × friendly √ √ × × private √ × × × ja ...

  8. MinerQueue.java 访问队列

    MinerQueue.java 访问队列 package com.iteye.injavawetrust.miner; import java.util.HashSet; import java.ut ...

  9. 论Java访问权限控制的重要性

    人在什么面前最容易失去抵抗力? 美色,算是一个,比如说西施的贡献薄就是忍辱负重.以身报国.助越灭吴:金钱,算是另外一个,我们古人常说“钱乃身外之物,生不带来死不带去”,但我们又都知道“有钱能使鬼推磨” ...

随机推荐

  1. ROS手动编写消息发布器和订阅器topic demo(C++)

    1.首先创建 package cd ~/catkin_ws/src catkin_create_pkg topic_demo roscpp rospy std_msgs 2. 编写 msg 文件 cd ...

  2. hdu6731 Angle Beats(ccpc秦皇岛A,计算几何)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6731 题意: 给出$n$个点,有$q$次询问 每次询问给出一个点$b$,求这$n+1$个点,组成直角 ...

  3. Log4j2 - 日志框架中isDebugEnabled()的作用

    为什么要使用isDebugEnabled() 之前在系统的代码中发现有时候会在打印日志的时候先进行一次判断,如下: if (LOGGER.isDebugEnabled()) { LOGGER.debu ...

  4. Java学习日记基础篇(九) —— 集合框架,泛型,异常

    集合框架 有事我们会需要一个能够动态的调整大小的数组,比如说要添加新员工但是数组已经满了,并且数组的大小是在定义的时候定死的,所以我们就需要一个能够动态调整大小的数组或者用链表解决,而java中提供了 ...

  5. 位于0/nut文件里的'Calculated'边界条件是什么意思?【翻译】

    翻译自:CFD-online 帖子地址:http://www.cfd-online.com/Forums/openfoam-pre-processing/140984-what-does-calcul ...

  6. spring boot 集成RabbitMQ的异常

    com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.clos ...

  7. mysql中的sql-mode导致的datetime类型字段不能为0000

    问题描述: 在执行建表语句的时候,出现invalid default datetime value '0000-00-00 00:00:00',从字面意思看,就是不合法的默认值'0000-00-00 ...

  8. Tag Tree

    Test & Measurement RF RFID DAQ Mixed Signal Instrumentation DSP C# C\C++ JAVA Work Better Git Ma ...

  9. 通过Redis的list来实现 Server - Client 的同步通信

    Redis实现类似同步方法调用的功能(一) 首先声明,这么干纯粹是为了好玩. 通常我们用Redis主要是为了存储一些数据,由于数据在内存里,所以查询更新很快.同时我们也可以利用 Pub/Sub 功能来 ...

  10. javascript的promise