字节输入流
昨天我们学习了字节输出流的学习,而在字节流中,我们还剩下一个字节输入流。
所以今天我们准备对字节输入流进行一个详细的了解吧!
字节输入流的父类(InputStream)
InputStream
,是所有字节输入流基类,是表示字节输入流的所有类的超类。主要作用是读取字节信息到内存中。它对整个体系的字节输入流制定了一些规范和方法。
1.先来看看他的体系结构
FileInputSream
:文件输入流。它通常用于对文件进行读取操作。FilterInputStream
:装饰者模式中处于装饰者,具体的装饰者都要继承它,所以在该类的子类下都是用来装饰别的流的,也就是处理类。BufferedInputStream
:缓冲流,对处理流进行装饰,增强,内部会有一个缓存区,用来存放字节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送。效率更高。ObjectInputStream
:对象输入流,用来提供对基本数据或对象的持久存储。也就是能直接传输对象(反序列化中使用)。DataInputStream
:数据输入流,它是用来装饰其它输入流。
2. InputStream中的方法
后续继承的子类都有这些方法,基本字节输入流都需要read()
方法进行读取文件,使用close()
方法关闭资源。
3. FileInputStream
FileInputStream
的使用与FileOutputStream
基本类似。
1. 构造方法
public FileInputStream(File file)
:通过打开与实际文件的连接来创建一个FileInputStream
,该文件由文件系统中的 File对象 File命名。public FileInputStream(String name)
:通过打开与实际文件的连接来创建一个FileInputStream
,该文件由文件系统中的路径名name
命名。
这次我们来看下使用构造前的文件信息:
public class FileInputStreamTest {
public static void main(String[] args) throws FileNotFoundException {
//public FileInputStream(File file)
//使用File对象创建流对象
File file = new File("e:\\demo\\b.txt");
FileInputStream fis = new FileInputStream(file);
//public FileInputStream(String name)
// 使用文件名称创建流对象
FileInputStream fis2 = new FileInputStream("e:\\demo\\c.txt");
}
}
执行程序,结果:
Exception in thread "main" java.io.FileNotFoundException: e:\demo\c.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at com.it.test3.FileInputStreamTest.main(FileInputStreamTest.java:16)
这里的16行错误即: FileInputStream fis2 = new FileInputStream("e:\\demo\\c.txt");
注意:
- 与输出流不同的是,
FileInputStream
如果传入的路径是空的话,就会报错,而FileOutputStream
则会创建文件。 FileInputStream
创建出来输入流对象,是不会清空对象的。很好理解,输入流本来就是要读取文件信息创建出来的流,如果清空了,那我还读个啥对吧,读出一片寂寞吗。
2. 读取数据
既然我们要创建出字节输入流,不就是为了读取数据吗,不然创建出来有什么用呢?那我们看下怎么用吧:
-
public int read()
:每次可以读取一个字节的数据,读出的类型为int
类型,当读取到文件末尾即没有数据,返回-1
。public class ReadTest { public static void main(String[] args) throws IOException { // 使用文件名称创建流对象 FileInputStream fis = new FileInputStream("e:\\demo\\b.txt"); //int read():一次读取一个字节 int read = fis.read(); System.out.println(read); System.out.println((char) read); fis.close(); } }
输出结果:
104 h
我们
b.txt
中存储的是hello
。根据输入流读取的结果返回的是int
类型,那我们就需要强转成char
字符类型,返回得到原来的文件信息。可是如果每次都是这样一个字节慢慢读取的话,是不是很麻烦,那这种重复度很高的话,就可以考虑循环优化它,可是我们现在不知道循环结束的条件是什么?那我们来测试下,读完后是什么结果呢?
public class ReadTest2 { public static void main(String[] args) throws IOException { // 使用文件名称创建流对象 FileInputStream fis = new FileInputStream("e:\\demo\\b.txt"); //int read():一次读取一个字节 int read = fis.read(); System.out.print(read); System.out.println(" : "+(char) read); read = fis.read(); System.out.print(read); System.out.println(" : "+(char) read); read = fis.read(); System.out.print(read); System.out.println(" : "+(char) read); read = fis.read(); System.out.print(read); System.out.println(" : "+(char) read); read = fis.read(); System.out.print(read); System.out.println(" : "+(char) read); //b.txt中,我们知道hello是5次就可以读完,那我们读第六次会怎样呢? read = fis.read(); System.out.print(read); System.out.println(" : "+(char) read); fis.close(); } }
程序运行结果:
104 : h 101 : e 108 : l 108 : l 111 : o -1 :
可以发现如果读到没有数据,最后读到的结果是
-1
,那我们是不是知道了循环结束的条件呢,如果没读到数据了就返回-1
。那我们使用循环改进:
public class ReadTest3 { public static void main(String[] args) throws IOException { // 使用文件名称创建流对象 FileInputStream fis = new FileInputStream("e:\\demo\\b.txt"); // 定义变量,保存数据 int b; // 循环读取 while ((b = fis.read())!=-1) { System.out.println((char)b); } // 关闭资源 fis.close(); } }
程序运行结果:
h e l l o
使用输入流的有几点注意:
- 虽然读取了一个字节,但是会自动提升为
int
类型。需要强转回字符。 - 跟输出流一样,输入流操作完毕后,必须释放系统资源,调用
close()
方法
- 虽然读取了一个字节,但是会自动提升为
-
public int read(byte b[])
:每次读取b
的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1
。public class ReadTest4 { public static void main(String[] args) throws IOException { // 使用文件名称创建流对象 // b.txt中信息为: FileInputStream fis = new FileInputStream("e:\\demo\\b.txt"); //public int read(byte b[]) byte[] b = new byte[3]; int len = fis.read(b); System.out.println(len);// 可以看到读到是实际长度 System.out.println(new String(b)); len = fis.read(b); System.out.println(len);// 可以看到读到是实际长度 System.out.println(new String(b)); //到这么,已经读取完了,看看是不是和读取一个一样是读到-1。 len = fis.read(b); System.out.println(len);// 可以看到读到是实际长度 // 关闭资源 fis.close(); } }
执行结果为:
3 hel 2 lol -1
可以发现:
-
如果读取到的实际长度是
-1
,就说明没有数据了。这就可以利用这个改进行循环优化了。 -
而且我们知道
System.out.println
,每打印出字符串后,就会进行换行,则有可能对我们的获取产生错乱,因为可能我们读取的字符就在一行呢,所以我们也得进行更换为System.out.print
。 -
len
获取到是实际的数据长度,第一次得到是3
,获得了hel
,而第二次获取的也就是2
,可以看到确实不错,但按道理来说,我们得到不应该是lo
吗,怎么会是lol
呢,这是在提示我要打LOL
了吗,嘿嘿!你看我是想喜欢打游戏吗?而且是像我这种经常拿五杀的人,并且经常CARRY的人,排位打到王者的男人。这里我战绩就不放出来了,怕吓到你们。而且我现在不打了,如果打下去,就可能是下一个UZI,theShy了。好了好了,会到重点,我们看下为什么最后会打出
lol
呢,而不是lo
。
在知道了以上的步骤后,我们进行循环优化,并对之前的发生的问题进行修改。
public class ReadTest5 { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("e:\\demo\\b.txt"); byte[] b = new byte[3]; int len; while((len = fis.read(b)) != -1) { System.out.print(new String(b, 0, len));//如此便也可以返回实际的字符 } // 关闭资源 fis.close(); } } 执行程序结果为: hello
可以看到,完美的在控制台上打印出了
hello
,并且不会每次读取,都会换行,完美复刻。小结下:
在开发中,我们使用数组读取,每次读取多个字节,减少了系统间的IO操作次数,从而提高了读写的效率。
-
字节流练习:图片复制
既然我们已经学习了字节的输出流和输入流,那何不妨来具体实战一下:
先来解释一波,复制的原理,就像电脑的右键复制一样:
复制前,先看看文件信息,免得你说我偷偷右键复制过去。
跟着我走,使用Java复制图片,你将会觉得很简单。So Easy
。
public class CopyTest {
public static void main(String[] args) throws IOException {
// 1. 创建输入和输出流对象。
// 1.1 指定要读文件的路径。
FileInputStream fis = new FileInputStream("e:\\demo\\北极星.jpg");
// 1.2 指定目的地文件的路径。
FileOutputStream fos = new FileOutputStream("e:\\demoCopy\\北极星.jpg");
// 2.读写数据
// 2.1 定义字节数组
byte[] b = new byte[1024];
int len;
// 2.2 循环读取出数据
while ((len = fis.read(b))!=-1) {
// 2.3 将得到的字节数据写出
fos.write(b, 0 , len);
}
// 3.关闭所有资源
fos.close();
fis.close();
}
}
程序运行后,你将会看到很快就完成,再到文件查看下,发现复制好的北极星.jpg
已经完整的躺好在哪里了。
大家要看下北极星小姐姐吗,不知道大家还记得北极星小姐姐吗,真的太可了,真的awsl
,为此我多年前还专门刷完了天赋异禀整部剧,看到北极星和交食两人在一起产生极光,真的Interesting
。极光是因为太阳带电粒子流进入地球磁场而产生的。 嘿嘿,好东西还是自己偷偷看吧,哈哈,还是默默躺在我文件夹中吧。
总结
相信各位看官都对IO流中字节输入流有了一定了解,期待等待下一章的字符流教学吧!
当然还有很多流等着下次一起看吧!欢迎期待下一章的到来!
学到这里,今天的世界打烊了,晚安!虽然这篇文章完结了,但是我还在,永不完结。我会努力保持写文章。来日方长,何惧车遥马慢!
感谢各位看到这里!愿你韶华不负,青春无悔!
注: 如果文章有任何错误和建议,请各位大佬尽情留言!如果这篇文章对你也有所帮助,希望可爱亲切的您给个三连关注下,非常感谢啦!
作者:***爷哪吒
链接:https://juejin.cn/post/6993640831424921608
来源:掘金