文章目录
FileInputStream 有两个常用的构造函数
构造函数1
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
参数 name 表示文件的路径。通过这个传入的路径打开实际的文件。
可以看到其中调用了this方法,这个方法是什么呢?其实就是另外一个构造函数。
构造函数2
public FileInputStream(File file) throws FileNotFoundException {
// 处理 file 参数为空的情况
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
// 处理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;
// 调用 native 方法打开文件
open(name);
}
构造器很简单,传入参数为File对象,然后对file对象进行一些处理,在将文件路径(file.getPath())传入 native 方法打开实际的文件。
FileInputStream 的读入方法
FileInputStream有多个read的方法可供调用
read方法1:只读取一个字节
public int read() throws IOException {
Object traceContext = IoTrace.fileReadBegin(path);
int b = 0;
try {
b = read0();
} finally {
IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1);
}
return b;
}
正如代码所示,这个方法每一次只返回一个字节。返回值是这个字符的ASCII码。
使用示例
public static void main(String[] args) {
String filePath = "F:\\FilesExample\\A.txt";
try ( FileInputStream fis = new FileInputStream(filePath)){
System.out.println( fis.read() );
} catch (IOException e) {
e.printStackTrace();
}
}
如果读到的字符是大写字母A的话,返回的ASCII码就是65,如果读到的字符是数字1的话,返回的ASCII码就是49.
read方法2:读取指定数组长度到该数组中
public int read(byte b[]) throws IOException {
Object traceContext = IoTrace.fileReadBegin(path);
int bytesRead = 0;
try {
bytesRead = readBytes(b, 0, b.length);
} finally {
IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
}
return bytesRead;
}
方法传入一个字节数组,方法调用了readBytes(b, 0, b.length)方法,它是一个native方法。
方法的第一个参数是的数组,待会儿会把读取出来的数据放在这个数组中,第二个是偏移量(关于偏移量:详解Java IO中的偏移量),第三个是数组长度,也就是需要读取多长的数据。
返回值是最后一个字符的坐标位置,如果已经到了最后一个字符还要继续读取的话,就会返回-1.
换句话说,只要接收到-1,就表示流已经读完了。
使用示例
public static void main(String[] args) {
String filePath = "F:\\FilesExample\\A.txt";
try ( FileInputStream fis = new FileInputStream(filePath)){
byte[] bytes = new byte[10];
System.out.println("最后一个字符的坐标:"+ fis.read(bytes));
for (int i = 0; i < bytes.length; i++) {
System.out.println("数组中第"+i+"项内容:"+bytes[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
假设现在A.txt文件中的内容如下:
ABCDEFG
那么这个示例的打印结果就是:
最后一个字符的坐标:7
数组中第0项内容:65
数组中第1项内容:66
数组中第2项内容:67
数组中第3项内容:68
数组中第4项内容:69
数组中第5项内容:70
数组中第6项内容:71
数组中第7项内容:0
数组中第8项内容:0
数组中第9项内容:0
可以发现数组中没有填满的地方都是使用的默认值0。
现在假设要传入的byte数组只有2个长度,结果会是什么样呢?
改造main方法
public static void main(String[] args) {
String filePath = "F:\\FilesExample\\A.txt";
try ( FileInputStream fis = new FileInputStream(filePath)){
byte[] bytes = new byte[2];
System.out.println("最后一个字符的坐标:"+ fis.read(bytes));
for (int i = 0; i < bytes.length; i++) {
System.out.println("数组中第"+i+"项内容:"+bytes[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
结果如下:
最后一个字符的坐标:2
数组中第0项内容:65
数组中第1项内容:66
看结果可以得出结论,我们传入的数组长度为2,read方法也只会读取2个字符。
read方法3:从指定位置读取指定长度的数据存放到指定数组
public int read(byte b[], int off, int len) throws IOException {
Object traceContext = IoTrace.fileReadBegin(path);
int bytesRead = 0;
try {
bytesRead = readBytes(b, off, len);
} finally {
IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
}
return bytesRead;
}
几个参数的含义已经在方法2中解释过了,这个方法最后也会调用和方法2相同的native的方法。
应用:读取指定文件内容
在上一篇文章中,我们使用FileOutputStream 字节输出流将内容输出到了指定文件中,现在我们利用 FileInputStream 字节输入流再将内容从文件中读取出来并打印在控制台上。
public static void main(String[] args) {
String filePath = “F:\FilesExample\A.txt”;
// 创建字节输入流
try ( FileInputStream fis = new FileInputStream(filePath)){
// 创建装数据的数组
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1){
// 将读出的数据转换成字符串
System.out.println(new String(bytes));
}
} catch (IOException e) {
e.printStackTrace();
}
}
打印结果:
This is FileOutputStreamTest Content
在进行读数据的时候,采取了三种read方法中的一种。有时间可以试试其他两种。
技 术 无 他, 唯 有 熟 尔。
知 其 然, 也 知 其 所 以 然。
踏 实 一 些, 不 要 着 急, 你 想 要 的 岁 月 都 会 给 你。