前言
io流在Java的常识体系中,属于很杂的那种了,次要是波及的类太多,输出流、输入流、文件输出流、文件输入流、字节输出流和输入流、字符输出流和输入流等等,常常把人弄晕。然而它的用处却十分宽泛,文件的操作、网络的操作等都离不开它,本文通过平时罕用操作来梳理一下io流中波及的重要类及办法。
什么是流
在Java中,文件个别不是独自解决的,而是视为输入输出设施的一种,Java应用一个对立的概念来解决所有的输入输出,包含键盘输入和网络输入输出等。这个对立的概念就是流,流又分为输出流和输入流,InputStream和OutputStream别离示意输出流和输入流,但这两个类是抽象类,大部分办法都是子类来实现的,如:
- BufferedInputStream和BufferedOutputStream对流起缓冲作用
- DataInputStream和DataOutputStream能够按8种根本类型和字符串类型对流进行读写
- ZipInputStream和ZipOutputStream能够对流进行压缩和解压缩
- printStream能够对根本类型和对象输入为其字符串示意
以InputStream和OutputStream为基类的流根本都是以二进制模式解决数据的,不可能不便地解决文本文件,没有编码的概念,可能不便地解决文本数据的基类是Reader和Writer,它也有很多子类,如:
- FileReader和FilerWriter用来读写文件
- BufferedReader和BufferedWriter起缓存装璜
- CharArrayReader和CharArrayWriter能够将字符数组包装为Reader和Writer
- StringReader和StringWriter能够将字符串包装为Reader和Writer
- InputStreamReader和OutputStreamWriter能够将InputStream和OutputStream转换为Reader和Writer
- printWriter能够将根本类型和对象输入为其字符串示意
二进制文件和字节流
二进制文件:所有文件外面的数据都是通过二进制来保留的,但为了不便解决数据,引入了文件类型的概念,次要分为文本文件和二进制文件。文本文件是指那些文本编辑器能够间接查看和编辑的文件,如.txt、.html、.java等文件;二进制文件是指一些非凡格局和性能的文件,如.zip、.jpg、.doc、.pdf等文件
Java次要通过InputStream和OutputStream来实现二进制字节模式解决文件。
OutputStream
OutputStream次要有上面几个办法:
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException
public void write(byte b[], int off, int len) throws IOException
public void close() throws IOException
public void flush() throws IOException
write(int b)
办法向流中写入一个字节,须要子类来实现。
write(byte b[])
办法外面调用write(byte b[], int off, int len)
办法来实现,将b[]数组从第off地位开始,len长度的数据写入到流中。
close()
敞开流,下面几个办法就算流中的数据都操作完了,也会阻塞,期待流中持续增加数据,因而咱们操作完数据当前,须要在finally办法中通过close()办法来敞开流。
flush()
将缓冲而未理论写入的数据进行理论写入,个别作用于带缓冲的流中,如BufferedOutputStream。
举例
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream("hello.txt");
String data = "hello world";
outputStream.write(data.getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
outputStream.close();
}
InputStream
InputStream次要有上面几个办法:
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException
public int read(byte b[], int off, int len) throws IOException
public void close() throws IOException
read()
办法从流中读取下一个字节,须要子类来实现,返回这个字节的值,当读到流结尾时返回-1。
read(byte b[])
外面也是调用read(byte b[], int off, int len)
来实现,从流的第off地位开始,读取len长度放入b[]数组中。
close()
敞开流,同OutputStream。
举例:
InputStream inputStream = null;
try {
inputStream = new FileInputStream("hello.txt");
byte[] arr = new byte[1024];
inputStream.read(arr);
System.out.println(new String(arr));
} catch (Exception e) {
e.printStackTrace();
} finally {
inputStream.close();
}
首先构建一个须要读取的文件的输出流,而后通过read(byte b[])
办法将流中的数据读取到字节数组中,这样就简略实现了一个读取文件的性能。但这里有一个前提,文件中的字节长度不超过1024,那如果超过这个长度,咱们怎么样能力将流中数据读取到一个字节数组中呢?
能够借助ByteArrayOutputStream。通过名字能够看出是将流中数据输入到字节数组中。
InputStream inputStream = null;
try {
inputStream = new FileInputStream("hello.txt");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] arr = new byte[4];
int len;
while ((len = inputStream.read(arr)) > -1) {
byteArrayOutputStream.write(arr, 0, len);
}
String data = byteArrayOutputStream.toString();
System.out.println(data);
} catch (Exception e) {
e.printStackTrace();
} finally {
inputStream.close();
}
ByteArrayOutputStream的输入指标是byte数组,这个数组的长度是依据数据内容动静扩大的,当调用write办法的过程中,如果数组大小不够,会进行扩大,每次扩大长度翻倍。
BufferedInputStream和BufferedOutputStream
FileInputStream和FileOutputStream是没有缓冲的,按单个字节读写时性能比拟低,尽管能够按字节数组读取来进步性能,但有时必须按字节读写,这时就须要将文件流包装到缓冲流中来进步性能。
应用办法只有在对应的流外层包上对应的缓冲类就行了,如下:
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("hello.txt"));
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("hello.txt"));
文本文件和字符流
下面介绍了如何以字节流的形式解决文件,对于文本文件,字节流没有编码的概念,不能按行解决,应用不太不便,更适宜用字符流来解决。
字符流和字节流相似,也是有两个基类,Reader和Writer。Reader和InputStream相似,Writer和OutputStream相似,具体的操作都是通过子类来实现。
InputStreamReader和OutputStreamWriter
InputStreamReader能够将InputStream转换为Reader,构造方法如下:
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String charsetName)
一个重要的参数是编码类型,对于字符流来说,编码是很重要的,雷同二进制内容,不同编码状况下,可能会呈现不同后果。通过传入输出流和编码类型来结构出字符输出流,如果不传编码类型,则为零碎默认编码,默认编码能够通过Charset.defaultCharset()失去。
应用举例
Reader reader = null;
try {
reader = new InputStreamReader(new FileInputStream("hello.txt"));
char[] chars = new char[1024];
reader.read(chars);
System.out.println(new String(chars));
}finally {
reader.close();
}
将文件中数据读取到内存中,这段代码一次reader就读取了所有的内容,前提是文件内容不超过数组长度,如果文件内容很长,能够应用CharArrayWriter或StringWriter,前面会介绍。
OutputStreamWriter能够将OutputStream转换为Writer,构造方法如下:
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, String charsetName)
构造方法和InputStreamReader相似
应用举例
Writer writer = null;
try {
writer = new OutputStreamWriter(new FileOutputStream("hello.txt"),"UTF-8");
writer.write("hello pipi蛋");
}finally {
writer.close();
}
InputStreamReader和OutputStreamWriter外部都有一个类型为StreamDecoder的解码器,能将字节依据编码转换为char。
CharArrayReader和CharArrayWriter
CharArrayWriter与ByteArrayOutputStream相似,它的输入指标是char数组,这个数组长度能够依据内容动静扩大。
下面通过字符流读取文件内容的代码,咱们能够优化一下,如下:
Reader reader = null;
try {
reader = new InputStreamReader(new FileInputStream("hello.txt"));
CharArrayWriter arrayWriter = new CharArrayWriter();
char[] chars = new char[1024];
int len = 0;
while ((len = reader.read(chars))> -1) {
arrayWriter.write(chars, 0, len);
}
System.out.println(arrayWriter.toString());
}finally {
reader.close();
}
StringReader和StringWriter与CharArrayReader和CharArrayWriter相似,只是输入指标是StringBuffer,而且String和StringBuffer外部都是由char数组组成的,所以他们实质上是一样的。
BufferedReader和BufferedWriter
BufferedReader/BufferedWriter与BufferedInputStream/BufferedOutputStream相似,提供缓冲性能,只须要在外层包装一层缓冲类就行了,而且能够按行读写。
按行写入举例:
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter("hello.txt"));
writer.write("第一行");
writer.newLine();
writer.write("第二行");
writer.newLine();
}finally {
writer.close();
}
按行读取举例:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("hello.txt"));
String s = null;
while ((s = reader.readLine()) != null) {
System.out.println(s);
}
}finally {
reader.close();
}
PrintWriter
PrintWriter有很多构造方法,能够承受文件路径名、文件对象、OutputStream、Writer等。PrintWriter是一个十分不便的类,能够间接指定文件名作为参数,能够指定编码类型,能够主动缓冲,能够字段将多种类型转换为字符串,在输入到文件时,能够优先选择该类
下面按行写入的代码,能够应用PrintWriter写为:
PrintWriter printWriter = null;
try {
printWriter = new PrintWriter("hello.txt");
printWriter.println("第一行");
printWriter.println("第二行");
printWriter.println("第三行");
}finally {
printWriter.close();
}
能够看出printWriter相对而言,不便很多。
封装办法
字节流
复制InputSteam到OutputStream
public void copy(InputStream in, OutputStream out) throws Exception{
byte[] arr = new byte[1024];
int len = 0;
while ((len = in.read(arr)) > -1) {
out.write(arr, 0, len);
}
}
将文件内容读取到字节数组中
public byte[] file2Array(String fileName) throws Exception{
InputStream in = null;
try {
in = new FileInputStream(fileName);
ByteArrayOutputStream out = new ByteArrayOutputStream();
copy(in,out);
return out.toByteArray();
}finally {
in.close();
}
}
再将字节数组写入到文件中
public void array2File(String fileName,byte[] bytes) throws Exception{
OutputStream out = null;
try {
out = new FileOutputStream(fileName);
out.write(bytes);
}finally {
out.close();
}
}
字符流
复制Reader到Writer中
public void copy(Reader reader, Writer writer) throws Exception{
char[] chars = new char[1024];
int len = 0;
while ((len = reader.read(chars)) > -1) {
writer.write(chars, 0, len);
}
}
将文件内容读入到一个字符串中
public String file2String(String fileName,String encoding) throws Exception {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), encoding));
StringWriter writer = new StringWriter();
copy(reader,writer);
return writer.toString();
}finally {
reader.close();
}
}
将字符串内容写入到文件中
public void string2File(String fileName,String encoding,String data) throws Exception{
Writer writer = null;
try {
writer = new OutputStreamWriter(new FileOutputStream(fileName),encoding);
writer.write(data);
}finally {
writer.close();
}
}
按行写入到文件中
public void writeLines(String fileName, String encoding, Collection lines) throws Exception{
PrintWriter writer = null;
try {
writer = new PrintWriter(fileName,encoding);
for (Object line : lines) {
writer.println(line);
}
}finally {
writer.close();
}
}
按行读取文件中内容,返回内容汇合
public List<String> readLines(String fileName,String encoding)throws Exception {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),encoding));
List<String> list = new ArrayList<>();
String line = null;
while ((line = reader.readLine()) != null) {
list.add(line);
}
return list;
}finally {
reader.close();
}
}
总结
咱们平时开发的时候对文件或者网络内容应用流操作时,可能都是应用第三方类库,比方Apache有一个类库Commons IO,外面提供了很多简略易用的办法,当然应用这些类库一点故障都没有,然而,如果有些时候不能应用第三方类库的时候,比方开发一些通用的jar包时,必定越少依赖越好,这时候就要相熟jdk中的一些罕用io操作了。
发表回复