Java基础—IO编程(字节流与字符流)
文章目录
字节流与字符流
字节流与字符流简介
流是什么呢?听到流我们第一个想到的是什么,水流?数据流?都不是。这里我们对流的定义主要是数据的处理方式,以及目标内容的处理机制,流分为输入流和输出流两种,在java.io包中针对输入输出流分为两种类型:
· 字节操作流:OutputStream(字节输出流)、InputStream(字节输入流);
· 字符操作流:Writer(字符输出流)、Reader(字符输入流)。
另外,输入流和输出流的定义如下:
· 输入流: 程序可以从中读取数据的流。
· 输出流: 程序能向其中写入数据的流。
字节输出流OutputStream
OutputStream流是实现字节输出的操作类,定义如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
OutputStream是在JDK1.0的时候提供的,而后在JDK1.5的时候设计了两个新的接口:Closeable和Flushable,而且在JDK1.7的时候Closeable又成了AutoCloseable接口的子类。
Closeable和Flushable接口的定义如下:
//Closeable 接口定义
public interface Closeable extends AutoCloseable{
public void close() throws IOException;
}
//Flushable 接口定义
public interface Flushable{
public void flush() throws IOException;
}
OutputStream类提供的是一个流的输出操作,所以在OutputStream类中提供有三个输出方法。
序号 | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public abstract void write(int b)throws IOException | 方法 | 输出单个字节数据 |
2 | public void write(byte[] b)throws IOException | 方法 | 输出全部字节数组的数据 |
3 | public void write(byte[] b,int off,int len) | 方法 | 输出部分字节数组的数据 |
OutputStream类中的write()方法是针对字节数据进行处理的,但是OutputStream类是一个抽象类,需要通过子类的实例化对象才可以访问类中的方法,此时我们要进行文件处理选用java.io.FileOutputStream子类实现。
对于抽象类的子类来说,我们需要关注的点有两个:
· 1.子类中完成对父类抽象方法的覆写;
· 2.子类构造实例化对象向上转型;
此时由于是系统给出的子类,只需要关注构造方法即可。
序号 | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public FileOutputStream(File file)throws FileNotFoundException | 构造方法 | 设置文件的输出流,每次对原始数据进行覆盖 |
2 | public FileOutputStream(File file,boolean append)throws FileNotFoundException | 构造方法 | 如果将append的内容设置为true,表示进行内容增加 |
使用构造方法实现磁盘数据的输出:
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
//使用OutputStream实现磁盘数据的输出
public class Test01{
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator+"zhang"+File.separator+"da"+File.separator+"pao.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(file);
output.write("zhangdapao".getBytes());
output.close();
}
}
此时使用构造方法就完成了对文件内容的覆盖操作。如果想对内容进行追加内容,可以使用另一个构造方法完成。如下所示:
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
//使用OutputStream实现磁盘数据的输出
public class Test01{
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator+"zhang"+File.separator+"da"+File.separator+"pao.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(file);
output.write("zhangdapao".getBytes());
output.close();
}
}
字节输入流InputStream
InputStream流是实现字节输出的操作类,定义如下:
public abstract class InputStream extends Object implements Closeable
通过观察定义可以发现,进行InputStream和OutputStream类有所区别,InputStream没有实现Flushable接口,因为在读的过程是不需要使用到系统的缓冲区的,缓冲区是为了防止过多的写入,在InputStream类中提供有如下的读取操作方法:
序号 | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public abstract int read()throws IOException | 方法 | 读取单个字节数据,没有数据返回“-1” |
2 | public int read(byte[] b)throws IOException | 方法 | 将内容读取到字节数组中,返回读取个数,没有数据返回“-1” |
3 | public int read(byte[] b,int off,int len | 方法 | 读取部分内容到字节数组中,返回读取个数,没有数据返回“-1” |
4 | public byte[] readAllBytes() | 方法 | 返回全部的字节数据 |
5 | public int available() | 方法 | 获取可用的长度 |
InputStream类是一个抽象类,可以利用FileInputStream子类为其进行实例化,实现文件流的操作,构造方法定义为:
public FileInputStream(File file)throws FileNotFoundException;
使用InputStream实现文件数据的读取,示例如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
//使用InputStream实现文件数据的读取
public class Test01{
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator+"zhang"+File.separator+"da"+File.separator+"pao.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//定义一个字节数组,用来保存数据
byte data [] = new byte[1024];
InputStream input = new FileInputStream(file);
//获取读取的字节个数
int len = input.read(data);
//打印字节数组中的数据
System.out.println(new String(data));
input.close();
}
}
执行结果:D:\java\jdk-11\bin\java.exe "-javaagent:D:\IDEA\IntelliJ IDEA 2018.3.2\lib\idea_rt.jar=56626:D:\IDEA\IntelliJ IDEA 2018.3.2\bin" -Dfile.encoding=UTF-8 -classpath D:\JavaTest\out\production\Test01 zhang.da.pao.Test01
zhangdapao111
Process finished with exit code 0
从JDK1.9之后InputStream追加了一个新的方法“readAllBytes()”,这种方法特点在于可以直接返回所有字节,不需要考虑数组大小。但仅适用于小文件,不然程序会崩溃。
字符输出流:Writer
上文所述的OutputStream类是可以实现输出操作,但是输出的时候使用的是字节类型,但多数情况下使用的最多的还是字符串类型,为了简化输出操作,JDK1.1开始提供了字符输出流,Writer类的定义为:
Public abstract class Writer extends Object implements Appendable,Closeable,Flushable
从定义我们可以看出相比较OutputStream类,Writer类多实现了一个Appendable接口,里面只有一个append()方法;让我们来观察一下Appendable接口里面的内容;
public interface Appendable{
public Appendable append(CharSequence csq)throws IOException;
public Appendable append(CharSequence csq,int start, int end)throws IOException;
public Appendable append(Char c)throws IOException;
}
使用Writer类进行输出的时候,最大的特点在于可以直接进行字符串的数据处理,Writer类是一个抽象类,可以利用FileWriter子类为其进行实例化,实现文件流的操作,构造方法定义为:
序号 | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public void write(String str)throws IOException | 方法 | 在文件上写入字符串数据 |
使用FileWriter进行文件操作:
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
//使用FileWriter进行程序的数据输出,文件的写入操作
public class Test01{
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator+"zhang"+File.separator+"da"+File.separator+"pao.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
Writer writer = new FileWriter(file);
//写入字符串数据
writer.write("zhangdapao006");
//追加写入
writer.append("zhangdapao007");
writer.close();
}
}
使用Writer最大的有时就在于可以直接进行字符串的输出处理。
字符输入流:Reader
Reader是实现字符数据的输入流类,定义如下:
public abstract class Reader extends Object implements Readable,Closeable
与InputStream类有所区别的是,Readable类中没有提供读取全部数据的方法,避免造成内存溢出,但实现方法与前面讲的三个类一样,都是使用子类对象实例化来实现,如下例所示:
//使用Reader读取数据
public class Test01{
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator+"zhang"+File.separator+"da"+File.separator+"pao.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//定义一个字节数组,用来保存数据
char data [] = new char[1024];
Reader reader = new FileReader(file);
//获取读取的字节个数
int len = reader.read(data);
//打印字节数组中的数据
System.out.println(new String(data));
reader.close();
}
}
执行结果:D:\java\jdk-11\bin\java.exe "-javaagent:D:\IDEA\IntelliJ IDEA 2018.3.2\lib\idea_rt.jar=55635:D:\IDEA\IntelliJ IDEA 2018.3.2\bin" -Dfile.encoding=UTF-8 -classpath D:\JavaTest\out\production\Test01 zhang.da.pao.Test01
zhangdapao006zhangdapao007
Process finished with exit code 0
字节流与字符流区别
在实际开发中该选用哪一种输入输出流呢?先来看看两者的区别:
字节操作属于基础的二进制操作形式,在网络、文件等操作几乎都是以字节数据为主,但是字节数据不方便进行中文的处理,所以对于中文处理应使用字符流。
还有比较特殊的一点是:在进行网络传输或者磁盘数据存储的时候,所存放的内容都属于字节数据。
close()方法可以自动清空缓冲区的内容,另外清空缓存区还可以使用flush方法实现。