字节流
经过昨天的IO流概念的了解,我们知道他可以字符流和字节流,所以今天开始我们先来学习字节流。
而字节流呢?又可以分为字节输出流和字节输入流。今天我们准备对字节输出流进行一个详细的了解吧!
文件世界里,一切皆为字节
我们要知道,一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
字节输出流的父类(OutputStream)
OutputStream
,是所有字节输出流基类,是表示字节输出流的所有类的超类。主要作用是将指定的字节信息写出到目的地。它对整个体系的字节输出流制定了一些规范和方法。
1. 先来看看他的体系结构
FileOutputStream
:字节文件输出流是用于将数据写入到File,从程序中写入到其他位置。FilterOutputStream
:装饰者模式中处于装饰者,具体的装饰者都要继承它,所以在该类的子类下都是用来装饰别的流的,也就是处理类。ObjectOutputStream
:也是装饰类,用于序列化。主要是将Java对象的原始数据类型写出到文件,实现对象的持久存储。BufferedInputStream
:缓冲流,是FilterOutputStream
装饰流的加强,提高读写的效率。PrintStream
:是FilterOutputStream
装饰流的加强。能够方便地打印各种数据类型的值,是一种便捷的输出方式。DataOutputStream
:数据输出流,它是用来装饰其它输出流。
2. OutputStream中的方法
后续继承的子类都有这些方法,基本字节输出流都需要write()
方法进行写入文件中,使用close()
方法关闭资源。
3. FileOutputStream
1. 构造方法
public FileOutputStream(File file)
:创建文件输出流以写入由指定的 File对象表示的文件。public FileOutputStream(File file, boolean append)
:跟上面类似,多了个属性,下面再讲public FileOutputStream(String name)
: 创建文件输出流以指定的名称写入文件。public FileOutputStream(String name, boolean append)
:跟上面类似,多了个属性,下面再讲
这是还未创建构造方法前的文件夹信息
public class IOTest {
public static void main(String[] args) throws FileNotFoundException {
//public FileOutputStream(File file)
//使用File对象创建流对象
File file = new File("e:\\demo\\a.txt");
FileOutputStream fos = new FileOutputStream(file);
//public FileOutputStream(String name)
// 使用文件名称创建流对象
FileOutputStream fos2 = new FileOutputStream("E:\\demo\\b.txt");
}
}
我们中的a.txt
本来是没有的,而且b.txt
里面是有内容的,让我们执行下代码后,会发生什么吧:
可以看到,控制台没有报错,也没有什么信息。那我们在来看看文件夹信息吧:
注意:当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。
那为什么呢,有文件还会被清空数据呢,那我不想每次创建输出流对象,都要被清空目标文件中的数据,怎么做呢?
-
我们先看下我们调用的构造方法具体过程吧:
public FileOutputStream(File file) throws FileNotFoundException { this(file, false); } public FileOutputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null, false); } public FileOutputStream(File file, boolean append) throws FileNotFoundException {} public FileOutputStream(File file, boolean append) throws FileNotFoundException {}
可以发现,最后都会调用了包含了
append
属性的构造方法,并且append
为false。而这个
append
属性表示如果为true
表示追加追加数据,false表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了。我先在b.txt
加了hello
。然后我们在试下文件是否又被清空掉public class AppendDemo { public static void main(String[] args) throws FileNotFoundException { FileOutputStream fos2 = new FileOutputStream("E:\\demo\\b.txt", true); } } 执行后,可以看到,文件没有被清空数据了。
想一下我们在创建字节输出流对象了做了几件事情,是不是就认为不是直接创建的吗?还是底层有步骤的啦:
- 调用系统功能去创建文件。
- 创建
fos
对象。 - 把
fos
对象指向这个文件。
2. 写入数据
既然我们要创建出字节输出流,不就是为了写入数据吗,不然创建出来有什么用呢?那我们看下怎么用吧:
-
public void write(int b)
:每次写一个字节。public class WriteTest { public static void main(String[] args) throws IOException { // 使用文件名称创建输出流对象 FileOutputStream fos = new FileOutputStream("E:\\demo\\a.txt"); //public void write(int b) fos.write(97); fos.close(); //如果在流关闭后再写入数据会怎样。 //fos.write(98);//Exception in thread "main" java.io.IOException: Stream Closed } } 执行结果后,查看文件a.txt得到的是: a
有几点所需要注意:
-
一定要关闭资源:
为了让流对象变成垃圾,这样就可以被垃圾回收器回收了。
通知系统去释放跟该文件相关的资源。
-
为什么写的97,然后写到文件后变成字符
a
了:因为97代表了底层二进制数据,通过这个然后在字符表中找到对应的字符
a
。最后显示的也是a
,而不是97,但是底层数据是97。我们看下完整的ASCII码表: -
如果关闭了流资源后,则无法继续对这个流进行操作,否则会报
IOException
异常。 -
现在我们进行IO流操作,除了可能报错会打印在控制台上,其他都是直接在文件中进行操作,结果是直接显示在文件里,如果要看结果,打开文件就看到。
-
-
public void write(byte[] b, int off, int len)
:每次写出从off
索引开始,len
个字节。相当于写入一个字节数组的一部分。public class WriteTest2 { public static void main(String[] args) throws IOException { // 使用文件名称创建输出流对象 FileOutputStream fos = new FileOutputStream("E:\\demo\\a.txt"); //public void write(byte[] b) byte[] b = {97, 98, 99, 100, 101}; fos.write(b); fos.close(); } } 执行结果后,查看文件a.txt得到的是: abcde
-
public void write(byte[] b)
:每次写一个字节数组。public class WriteTest3 { public static void main(String[] args) throws IOException { // 使用文件名称创建输出流对象 FileOutputStream fos = new FileOutputStream("E:\\demo\\a.txt"); //public void write(byte[] b, int off, int len) byte[] b = {97, 98, 99, 100, 101}; fos.write(b,0,3); fos.close(); } } 执行结果后,查看文件a.txt得到的是: abc
3. 实现换行
我们以上操作好像都是写在一行上,那我们可不可以实现换行呢?
那我先看看怎样换行符是什么吧?
- 回车符
\r
和换行符\n
:
- 回车符:回到一行的开头(return)。
- 换行符:下一行(newline)。
- 系统中的换行:
- Windows系统里,每行结尾是
回车+换行
,即\r\n
;- Unix系统里,每行结尾只有
换行
,即\n
;- Mac系统里,每行结尾是
回车
,即\r
。从 Mac OS X开始与Linux统一。
而我们现在默认使用的应该都是Windows
系统,那我们需要加入的是\r\n
。那我们代码演示下看看吧:
执行结果后,查看文件a.txt得到的是:
epublic class WriteTest4 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建输出流对象
FileOutputStream fos = new FileOutputStream("E:\\demo\\a.txt");
//实现写入每一个字符后都换行
byte[] b = {97, 98, 99, 100, 101};
for (byte bs : b) {
fos.write(bs);
// 写出一个换行, 换行符号转成数组写出
fos.write("\r\n".getBytes());
}
fos.close();
}
}
执行结果后,查看文件a.txt得到的是:
a
b
c
d
e
是不是觉得每次都要查看文件,然后确认是否添加成功,很麻烦呢。接下来我们就学习字节流中的输入流,学习如何读取文件。
总结
相信各位看官都对IO流中字节输出流有了一定了解,期待等待下一章的字节输入流教学吧!
当然还有很多流等着下次一起看吧!欢迎期待下一章的到来!
学到这里,今天的世界打烊了,晚安!虽然这篇文章完结了,但是我还在,永不完结。我会努力保持写文章。来日方长,何惧车遥马慢!
感谢各位看到这里!愿你韶华不负,青春无悔!
注: 如果文章有任何错误和建议,请各位大佬尽情留言!如果这篇文章对你也有所帮助,希望可爱亲切的您给个三连关注下,非常感谢啦!
作者:***爷哪吒
链接:https://juejin.cn/post/6993310593729953829
来源:掘金