IO加强
IO加强
1字符流
字符流只能读入文本,操作的是char,一个char等于二个bytes。
字符流有二个父类
1)重点为前二个子类
Reader(字符输入流)分为以下子类
*** BufferedReader*:基于缓冲区的读者**
*** InputStreamReader:在字节流和字符流之间做转换的流。*
子类有一个FileReader,是一个基于磁盘文件的字符输入
CharArrayReader:字符数组读者
PipedReader:管道读者
StringReader .. FilterReader ..
Writer(字符输出流)分为一下子类:
*** BufferedWriter***
*** OutputStreamWriter***
子类:FileWriter
PrintWriter:打印写者并提供换行。
CharArrayWriter
PipedWriter
FilterWriter .. StringWriter..
字符流的作用:与字节流相比效率更高,因为一个字符=二个字节,但局限性,应用不广。
1.1FileWriter
是一个基于字符的文件输出流,用于在磁盘中对文本文件做写操作。
构造方法和FileInputStream无大差别。
FileWriter(String name)
FileWriter(File file)
FileWriter(String name,boolean append)
FileWriter(File file,boolean append)
下面这个成员方法:Writer(int c)指传入一个ASCII码,传入文件变为ASCII码对应的字符。
场景:将字符写入磁盘
package com.hujesse.IO;
import java.io.FileWriter;
public class FileWriterTest1 {
public static void main(String[] args) {
try(
FileWriter fw=new FileWriter("b.txt")
){
char [] data = {'h','e','l','l','0'};
// 将字符数组写入
fw.write(data);
//写入部分字符
fw.writer(data,0,5);
//写入单个字符
fw.writer(100);
//写入字符串
fw.writer("Hujesse4");
//写入部分字符串
fw.writer("Hujesse4",0,5);
}catch(Exception e){
e.printStackTrace(); }
}
}
1.2FileReader
基于字符的文件输入流,用来读取磁盘文件的数据。
// FileReader 的源码
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
// FileInputStream的源码
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
//说明了字符流是基于字节流的
场景:创建FileReader对象读取数据
package com.hujesse.IO;
import java.io.FileReader;
import java.util.Arrays;
public class FileWriterTest1 {
public static void main(String[] args) {
try(
FileReader fw=new FileReader("b.txt")
){
// d定义一个字符数组,一次从磁盘读取多个
char [] data = new char[32];
fw.read(data);
System.out.println(Arrays.toString(data));
}catch(Exception e){
e.printStackTrace(); } }}
1.3文本文件的拷贝
package com.hujesse.IO;
import java.io.FileReader;
import java.io.FileWriter;
public class FileWriterTest1 {
public static void main(String[] args) {
try(
FileReader fr=new FileReader("b.txt");
FileWriter fw=new FileWriter("b_copy.txt");
){
char []buffer = new char[32];
int len;
while ((len=fr.read(buffer))!=-1){
fw.write(buffer,0,len);
}
}catch(Exception e){
e.printStackTrace(); } }}
2缓冲流
2.1相关概念
流的分类
流的流向:输入流和输出流
按照数据类型:字节流和字符流
按照功能:基础流和装饰流(处理流)
什么是基础流:FileInputStream和FileOutputStream之间操作磁盘的。
什么是装饰流:对基础流做了一个包装,例如FileReader对FileInputStream做了一个装饰,在创建FileReader同时创建了FileInputStream
2.2带有缓冲区的装饰流(基于字节)
带有缓冲区的好处(由来..whatever):内存读取数据快,磁盘读取数据慢,需要一个缓冲区来匹配速度
基于字节的装饰流:
BufferedInputStream & BufferedOutputStream
2.2.1BufferedInputStream
1)**BufferedInputStream 在基础流之上多了一个基于字节数组的缓冲区,默认大小为8192bytes。
2)缓冲输入流相对于普通输入流的优势是,它提供了一个缓冲数组,每次调用read方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,最后再将缓冲区中的内容部分或全部返回给用户.由于从缓冲区里读取数据远比直接从物理数据源(譬如文件)读取速度快。
3) 里面有二个属性,pos(position)和count,当pos==count,说明读取完毕了
场景:使用缓冲输入流读取磁盘数据并打印
package com.hujesse.IO;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class BufferedInputTest {
public static void main(String[] args) {
try(
BufferedInputStream bu = new BufferedInputStream(new FileInputStream("a.txt"));
){
//每次读取1024个字节
byte[] data = new byte[1024];
int len = 0;
// 理解String StringBuffer StringBuilder的区别;capacity容积
StringBuilder sb = new StringBuilder(500);
while ((len=bu.read(data))!=-1){
//将字节数组转换为字符串
String str = new String(data,0,len);
//将字符串追加到StringBuilder
sb.append(str);
}
System.out.println(sb.toString());
}catch (Exception e){
e.printStackTrace(); } }}
2.2.2BufferedOutputStream
BufferedOutputStream是一个缓冲输出流,内部也有一个缓冲区,在写数据的时候,会将数据写入缓冲区直到写满,再讲缓冲区的数据一次性写入磁盘。
场景:使用字节缓冲流拷贝图片
package com.hujesse.IO;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class BufferedOutPutTest {
public static void main(String[] args) {
try (
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("BufferCopy.jpg"));
BufferedInputStream in = new BufferedInputStream(new FileInputStream("D:\\timg.jpg"));
) {
byte[] data = new byte[1024];
int len = 0;
while ((len = in.read(data)) != -1) {
os.write(data, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} }}
// 和FileInputStream操作真没什么区别
唯一需要注意的是BufferOutputStream(OutputStream out)需要传入对象,子类也可以。
2.3带有缓冲区的装饰流(基于字符)
他们内部也有一个缓冲区,这个缓冲区是一个char[],默认长度为8192
2.3.1BufferedReader
构造方法:BufferedReader(Reader):创建一个基于字符的缓冲流,参数是一个Reader的子类,例如:FileReader。
它除了支持read()的方法外还支持
readLine():读取缓冲区里的一行数据,读到\r\n就会结束。
2.3.2 BufferedWriter
构造方法:BufferWriter(Writer):创建一个基于字符的缓冲流,参数是一个Writer的子类,例如:FileWriter。
还支持newLine():写入\r\n换行
场景:使用字符缓冲流进行文件的copy&paste
package com.hujesse.IO;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
// bufferReader BUfferedWriter进行copy& paste
public class BufferRead {
public static void main(String[] args) {
try(
BufferedReader bf = new BufferedReader(new FileReader("D:\\bia.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("copyChar.txt"));
){
// 用一个String类型接受数据
String line = null;
while ((line=bf.readLine())!=null){
bw.write(line);
//换行
bw.newLine();
}
}catch (Exception e){
e.printStackTrace(); } }}
3内存流(重点)
特征:数据的读和写都在内存中完成,可以将数据写入内存中,也可以从内存中读取数据。
3.1 ByteArrayOutputStream
基于字节的内存输出流,它是一个基础流,主要用于将程序中的数据转换为字节数组,然后写入流中。
构造方法如下:
ByteArrayOutputStream()无参构造方法,用来创建字节数组输出流对象。
ByteArrayOutputStream(int size)同上,不过参数size是字节数组的长度。
场景:定义一个变量,将其转换为字节数组,然后将其写入到ByteArrayOutputStream流里面
package com.hujesse.IO;
import java.io.ByteArrayOutputStream;
public class ByteArrayOutStream {
public static void main(String[] args) {
try (
ByteArrayOutputStream bo = new ByteArrayOutputStream();
) {
String str = "helloIO";
bo.write(str.getBytes());
//bo.flush(); JVM自动帮我门做了这种事
} catch (Exception e) {
e.printStackTrace(); } }}
3.2 ByteArrayInputStream
是一个字节数组输入流,也是一个基础流,主要用于将内存的数据读取到程序中。
场景:定义一个变量,将其转换为字节数组,然后将其写入到ByteArrayInputStream流,最后调取类的方法读取数据
package com.hujesse.IO;
import java.io.ByteArrayInputStream;
public class ArrayInputStreamTest {
public static void main(String[] args) {
try(
ByteArrayInputStream bi = new ByteArrayInputStream("test".getBytes());
){
int data = bi.read();
System.out.println((char)data);
}catch(Exception e){
e.printStackTrace();
} }}
// FileInputStream(String name)读取磁盘里面的数据
//ByteArrayInputStream(byte[])读取内存中的数据
综合案例:将百度服务器的logo下载到本地磁盘
package com.hujesse.IO;
/**
* 场景:从百度服务器下载资源
* 创建URL对象,指定百度服务器的地址
* 打开URL链接
* 读取百度服务器数据,将读取的数据存储到内存流
* 创建FileInputStream,将内存流数据写到本地磁盘
*/
import java.io.*;
import java.net.URL;
public class ArrayInputStreamTest {
public static void main(String[] args) throws Exception{
URL url = new URL("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
try(
//url.openStream()相当于在浏览器输入服务器地址,然后回车
InputStream in = url.openStream();
ByteArrayOutputStream bo = new ByteArrayOutputStream();
){
// 使用输入流读取百度服务器图片,将读取的数据放进内存流
byte[] bufffer = new byte[1024];
int len = 0;
while ((len=in.read(bufffer))!=-1){
bo.write(bufffer,0,len); }
bo.flush();
// 获取内存流里面的字节数
try(
FileOutputStream fo = new FileOutputStream(new File("Logo.png"));
){
//bo.toByteArray()将内存流里面的数据转换为字节数组
byte [] data2 = bo.toByteArray();
fo.write(data2);
}catch(Exception e
){
e.printStackTrace();
}
}catch (Exception e){
e.printStackTrace(); } }}
//最主要的是内存流有个方法 byteArrayOutputStream.toByteArray()
//可以将内存流里面的的数据全部转换为字节数组
4对象输入和输出流
4.1 ObjectInputStream
是一个基于字节的对象输入流,同时也是一个装饰流,主要用于读取内存中的对象
构造方法:ObjectInputStream(InputStream)
1)工作中可以使用对象输入和输出流来完成对象的克隆
2)什么叫对象的克隆?在原始对象的基础上繁殖新对象,新对象数据和原对象一模一样
4.2 ObjectOutputStream
是一个基于字节的对象输出流,同时也是一个装饰流,主要用于读取内存中的对象
构造方法:ObjectOutputStream(outputStream)
场景:对象的克隆
package com.hujesse.IO;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectInPutStreamCLONE {
public static void main(String[] args) {
Student hujesse4 = new Student(20, "hujesse4");
try (
//创建原始输出流对象,将字节数组输出流注入到对象输出流里面
ByteArrayOutputStream bo= new ByteArrayOutputStream();
ObjectOutputStream op = new ObjectOutputStream(bo);
) {
//将对象写入内存
op.writeObject(hujesse4);
try(
// 注意把输出流的内容转换为对象数组传给输入流.bo.toByteArray()存储了原始数据
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream ob = new ObjectInputStream(bi);
){
Object stuClone = ob.readObject();
System.out.println(stuClone);
}catch (Exception e){
System.out.println("clone Object failed");
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("clone Object failed");
e.printStackTrace(); } }}
package com.hujesse.IO;
import java.io.Serializable;
//参与clone的对象必须继承implements Serializable接口,否则抛出异常
public class Student implements Serializable {
private int age;
private String name;
/* getters and setters */
小改进,写成一个静态方法
public static Object ObejctClone (Object obj)throws Exception{
try (
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
) {
oo.writeObject(obj);
try (
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
){
return oi.readObject();
} } }
5转换流
5.1 InputStreamReader
它是一个连接字节流和字符流之间的桥梁,也是一个输入流
// 为什么需要转换流 ---
为了解决设备之间编码方式不统一的问题
场景:将D盘目录下的一个文本文件拷贝,可它使用的是GBK编码,但IDEA使用的是UTF-8编码,拷贝会出现乱码。
什么时候用呢:即源头编码和目标编码不一致时,使用转换流(指定编码格式)即解决乱码
但是工作中一般定义有缓冲区的转换流
new BufferedReader(new InputStreamReader(new FileInputStream("D:\\bia.txt"),"GBK"))
new BufferedWriter(new InputStreamWriter(new FileOutputStream("copy.txt"),"GBK"))
场景:使用带有缓冲区的读者写者配合转换流进行文件的复制粘贴
package com.hujesse.IO;
import java.io.*;
public class InputStreamReaderTES {
public static void main(String[] args) {
try(
BufferedReader bf=new BufferedReader(new InputStreamReader(new FileInputStream("D:\\bia.txt"),"UTF-8"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copy.txt"),"UTF-8"));
){
String line = null;
while((line=bf.readLine())!=null){
bw.write(line);
bw.newLine();
}
}catch(Exception e){
e.printStackTrace(); } }}
5.2 OutputStreamWriter
它是一个连接字节流和字符流之间的桥梁,也是一个输出流
见上个场景
6读写基本数据类型
6.1 DataInputStream
构造函数DataInputStream(InputStream )
还提供了一些读写的方法
readint()读整数
readFloat()读单精度浮点小数
readDouble()读双精度浮点小数
readBoolean()读取Boolean
readChar()读字符
readUTF()读字符串
6.2 DataOutputStream
构造函数DataOutputStream(OutputStream)
还提供了一些写的方法
writeInt(int);写入整数
writeFloat(Float):写入单精度浮点数
场景:定义一个Student数组,使用DataOutputStream将数据写入磁盘,然后用DataInoutStream读写出来并打印;
package com.hujesse.IO;
import java.io.*;
public class DataInOutputStreamTest {
private static Student[] students = {
new Student(20,"hujesse"),
new Student(13,"cousin")};
public static void main(String[] args)
{
try(
DataOutputStream dot = new DataOutputStream(new FileOutputStream(new File("student")))
){
for(Student stu:students){
dot.writeInt(stu.getAge());
dot.writeUTF(stu.getName());
}
try(
DataInputStream dit = new DataInputStream(new FileInputStream("student"));
){
for(int i =0;i<students.length;i++){
int age = dit.readInt();
String name = dit.readUTF();
System.out.println(age);
System.out.println(name);
}
}catch (Exception e){e.printStackTrace();
}
}catch (Exception e){e.printStackTrace();
} }}
7打印流(了解)
PrintWriter:就是BufferedWriter + 换行
PrintWriter时一个字符流同时也是一个装饰流提供了换行的功能;
方法为:pw.println(args);
小知识
1)boolean不是布尔类型,而是logic(逻辑)类型