Java 流(Stream)和IO
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。
流: 流的作用,流的特点,流的功能,流的使用
1.节点流:最基本完成读入写出功能
1)字节流 : 万能流 *******
FileInputStream | FileOutputStream -->文件操作
字节数组流(了解),字节节点流 不是操作文件,不是读入写出文件,而是读入字节数组中的内
容,写出到字节数组
ByteArrayInputStream ByteArrayOutputStream
2)字符流 :纯文本
FileReader FileWriter
2.功能流(节点流):
1)缓冲流 : 提高节点流的功能和读写效率
字节缓冲流--没有新增方法
字符缓冲流--有新增方法,读取一行,插入换行符
2)转换流:字节->字符
InputStreamReader OutputStreamWriter
3)data流(字节节点流[文件|字节数组]):读写保留基本数据类型+字符串
DataInputStream DataOutputStream 新增方法:readXxx() writeXxx()
4)对象流(字节节点流[文件|字节数组]):读写对象类型信息
ObjectInputStream ObjectOutputStream 新增方法:readXxx() writeXxx()
字节流
字节输入流FileInputStream:
/*
* 目的:操作文件内部的内容,读,写...
* 流:一连串流动的数据,管道,具有先入先出的规律..
* IO流:学习不同的流,达到写出写出,上传下载的过程
* 数据源头 -----> 目的地
* 流的分类:
* 方向划分: 以程序为中心
* 输入流
* 输出流
* 操作单元:
* 字节流:万能流***
* 字符流
* 功能:
* 节点流: 直接从数据源到目的地
* 功能流|包装流:从数据源出来的数据经过一些包装,增强某些功能到目的地
* 流的分类之间都是相辅相成的
*
* 字节流:万能流 *****
* 字节输入流 InputStream 抽象类 -> 子类FileInputStream文件字节输入流
读read()+close()关闭
*
*/
//字节流 万能流 读入
public class IODemo01 {
public static void main(String[] args) throws IOException {
//1.通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例,建立要读入文件与程序的联系
File src=new File("D:/haha/heihei.txt");
//2.打开一个到实际文件的连接来创建一个流 抽象类多态(接口与实现类的方法相同,实现类新增方法对接口 不可见)
InputStream is=new FileInputStream(src);
//3.调用流的方法read,读数据,利用数组存值,循环读入
byte[] car=new byte[1024];//声明数组,一般为1024的整数倍
//read(byte[])-->返回值:读入到字节数组中的数据的个数
//从此输入流中将 byte.length 个字节的数据读入一个 byte 数组中。在某些输入可用之前,此方法将阻 塞。
//读入缓冲区的字节总数,如果因为已经到达流末尾而没有更多的数据,则返回 -1。
//如果一个数组读不完,重复循环的读入
int len=-1; //定义读入到数组中的数据的个数
while((len=is.read(car))!=-1){
System.out.print(new String(car, 0, len));
}
//4.关闭流
is.close();
}
}
字节输出流FileOutputStream:
/*
* 文件字节输入流--读入
* 文件字节输出流--写出
* OutputStream 抽象类-->FileOutputStream 字节文件输出流
* 输出流: 写出-->刷出-->关闭
*
* 覆盖问题:写出默认覆盖原文件中的内容,如果想要追加,可以构造器中添加boolean append,true追加,false不追加,覆盖,默认false
*/
//写出
public class IODemo02 {
public static void main(String[] args) throws IOException {
//1.通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例,建立要读入文件与程序的联系
File f=new File("D:/haha/heihei.txt");
//2.选择写出流
//FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入 数据的文件输出流。
//boolean append,true追加,false不追加则覆盖,默认false
OutputStream out=new FileOutputStream(f,true);
//3.写出到文件
out.write(100);
//4.刷出
out.flush();
//5.关闭
out.close();
}
}
字节输出流FileOutputStream写出多个数据:
/*
* 一个字节一个字节写出,效率低,想要写出多个数据,可以写出一个字节数组的数据 write(byte[]) 将数组写出到 输出流中
*/
public class IODemo03 {
public static void main(String[] args) {
//流
OutputStream out=null;
//目的地:文件不存在,系统会自动创建,如果路径(文件夹)不存在,需要手动创建,否则会报错
try {
out=new FileOutputStream("D:/haha.txt");
//2.写出
//准备数据
String str="bxn";
byte[] b=str.getBytes();
out.write(b);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
增强程序的健壮性
try {
if(out!=null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
封装拷贝文件的工具类:
public class CopyUitls {
//拷贝文件 参数:2个 数据源 目的地
public static void copyFile(String src,String dest){
copyFile(new File(src),new File(dest));
}
public static void copyFile(File src,File dest){
//1.建立联系(数据源.目的地)
//2.创建流
InputStream is=null;
OutputStream os=null;
try {
is=new FileInputStream(src);//数据源
os=new FileOutputStream(dest);//目的地
//3.读入写出
//准备数组
byte[] car=new byte[1024];
int len=-1; //读入到数组中数据的个数
while((len=is.read(car))!=-1){
os.write(car, 0, len);
}
//4.刷出
os.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
//5.关闭(后打开的先关闭,先打开的后关闭)
if(null!=os){
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(null!=is){
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
字符流
字符流 :只能操作纯文本的内容…
字符输入流FileReader:
字符输入流 Reader 抽象类 FileReader 文件字符输入流
流向:输入流 功能:节点流 操作单元:字符流
public class IODemo01 {
public static void main(String[] args) {
//1.建立联系+选择流
Reader read=null;
try {
read=new FileReader("D:/lalala.txt");
//2.读入
//System.out.println((char)read.read());
char[] car=new char[1024];
//int len=read.read(car);
int len=0; //读入到字符数组中的字符个数
while((len=read.read(car))!=-1){
System.out.println(new String(car,0,len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//3.关闭
try {
if(read!=null){
read.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
字符输出流FileWriter:
字符输出流: Writer 抽象类 FileWriter 文件字符输出流
流向:输出流 操作单元:字符流 功能:节点流
没有新增方法可以发生多态
public class IODemo02 {
public static void main(String[] args) {
//1.选择流
Writer wr=null;
try {
wr=new FileWriter("D:/lalala.txt",true); //默认false不追加
//2.准备数据+写出
//数据
String str="哈哈哈,今天是周六啦!!!";
char[] car=str.toCharArray();
//wr.write(str);
//wr.write(str,2,4);
//wr.write("\n"); //系统文件中打开没效果,工具中打开有效果
wr.write("\r\n"); //windows操作系统识别换行,工具中打开有效果
wr.write(car,0,car.length);
//3.flush
wr.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
//4.关闭
try {
//选中多行,alt+shift+z
if(wr!=null){
wr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
缓冲流
缓冲流 ->功能流的一种: 增强性能,提高功能,提高读写速度…
功能流使用: 功能流(节点流)
字节输入/输出缓冲BufferedInputStream/BufferedOutputStream:
字节输入缓冲流(字节输入流) BufferedInputStream
字节输出缓冲流(字节输出流) BufferedOutputStream
没有新增方法,可以换使用多态
public class BufferedInputStream01 {
public static void main(String[] args) throws IOException {
InputStream is=new BufferedInputStream(new FileInputStream("D://hehe.txt"));
OutputStream os=new BufferedOutputStream(new FileOutputStream("D:/haha.txt"));
byte[] car=new byte[1024];
int len=0;
while(-1!=(len=is.read(car))){
os.write(car, 0, len);
}
os.flush();
os.close();
is.close();
}
}
*字符输入/输出缓冲流BufferedReader/BufferedWriter:
字符输入 缓冲流 BufferedReader 功能:功能流 流向:输入流 操作单元:字符流
新增方法:String readLine() 读取一个文本行。
字符输出缓冲流 BufferedWriter
新增方法: void newLine() 写入一个行分隔符。
存在新增方法,不能多态使用
public class BufferedReader02 {
public static void main(String[] args) {
//1.声明流
BufferedReader rd=null;
BufferedWriter rt=null;
try {
rd=new BufferedReader(new FileReader("D:/hehe.txt"));
rt=new BufferedWriter(new FileWriter("D:/xixi.txt"));
//2.读入写出
//char[] car=new char[1024];
String msg=null; //存储的是读取到的每行内容
while(null!=(msg=rd.readLine())){
rt.write(msg);
rt.newLine();
}
//3.刷出
rt.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
//4.关闭
try {
if(rt!=null){
rt.close();
}
if(rd!=null){
rd.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
转换流
需求: 想要把字节转为字符,或者已有字节流,想要使用字符流的功能,可以进行转换
转换流: 功能流(节点流): 把字节流转换为字符流
字节输入转换流:InputStreamReader(InputStream,“编码格式”) -->Reader
字节输出抓换流:OutputStreamWriter(OutputStream,“编码格式”)–>Writer
public class ConvertDemo02 {
public static void main(String[] args) throws IOException {
//1,流
BufferedReader read=new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream("D:/haha.txt"))));
BufferedWriter write=new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream("D:/heihei.txt",true))));
//2.读写
String msg=null;
while((msg=read.readLine())!=null){
write.write(msg);
write.newLine();
}
//3.刷出
write.flush();
//4.关闭
write.close();
read.close();
}
}
data数据流
基本数据类型流 Data流|数据流: 功能流(节点流)
功能:读写带有基本数据类型的数据+String
DataInputStream(InputStream) 新增方法: readXxx() 读入java基本类型的数据
DataOutputStream(OutputStream) 新增方法: writeXxx() 写出java基本类型的数据
注意:什么顺序写出,什么顺序读入
可能遇到异常EOFException:文件存在,内容无法读取
public class DataDemo03 {
public static void main(String[] args) throws IOException {
//write("D:/aaa.txt");
read("D:/aaa1.txt");
}
//读入
public static void read(String pathName) throws IOException{
//输入流
DataInputStream is=new DataInputStream(new BufferedInputStream(new FileInputStream(pathName)));
//读入
int i=is.readInt();
boolean b=is.readBoolean();
String s=is.readUTF();
System.out.println(i+"-->"+b+"-->"+s);
//关闭
is.close();
}
//写出带有基本数据类型的数据
public static void write(String pathName) throws IOException{
//输出流
DataOutputStream out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(pathName)));
//数据
int i=101;
boolean b=false;
String str="haha";
//写出
out.writeInt(i);
out.writeBoolean(b);
out.writeUTF(str);
//刷出
out.flush();
//关闭
out.close();
}
}
对象流
对象流: 保留数据+数据类型
对象流(节点流)
序列化:把对象的信息状态,变为可存储|可传输的过程
序列化输出流 ObjectOutputStream(OutputStream)
新增方法: void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
反序列化输入流 ObjectInputStream(InputStream)
注意:
1.不是所有类型的对象都能序列化 需实现java.io.Serializable
2.先序列化后反序列化 写出读入的过程一致
3.不是对象的所有属性都需要序列化 被transient修饰的属性不能被序列化
4.static不能被序列化
5.如果父类实现了Serializable接口,子类中所有内容都能序列化
6.如果父类没有实现,子类实现了Serializable接口,只能序列化子类中独有的内容
public class ObjectDemo04 {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
write("D:/bbb.txt");
read("D:/bbb.txt");
}
//读入对象信息
public static void read(String pathName) throws FileNotFoundException, IOException, ClassNotFoundException{
//流
ObjectInputStream is=new ObjectInputStream(new BufferedInputStream(new FileInputStream(pathName)));
//读
Person obj1=(Person)(is.readObject());//将序列化的对象信息读入程序,并用对应类型接收
String[] obj2=(String[])(is.readObject());
System.out.println(obj1+"-->"+Arrays.toString(obj2));
//关闭
is.close();
}
//写出对象信息
public static void write(String pathName) throws FileNotFoundException, IOException{
//构建流
ObjectOutputStream wr=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(pathName)));
Person p=new Person("李毅",25,"hehe");
String[] arr={"呵呵","哈哈"};
//写出
wr.writeObject(p);
wr.writeObject(arr);
p.setName("老裴");
p.haha="lllllllllll";
//刷出
wr.flush();
//关闭
wr.close();
}
}
//创建javabean类实现Serializable接口
class Person implements Serializable{
private String name;
private transient int age;
static String haha="123345";
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String name, int age,String haha) {
super();
this.name = name;
this.age = age;
this.haha=haha;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ","+age+","+haha+"]";
}
}
乱码问题
1.编码和解码格式统一
2.长度丢失问题
public class Demo01 {
public static void main(String[] args) throws UnsupportedEncodingException {
/* 中文: 所占字节数
* ISO8859-1 1个
* UTF-8 3个
* GBK 2个
* GB2312 2个
*/
System.out.println("好".getBytes("ISO8859-1").length);
System.out.println("好".getBytes("UTF-8").length);
System.out.println("好".getBytes("GBK").length);
System.out.println("好".getBytes("GB2312").length);
byte[] arr="你好".getBytes("GBK");//编码
System.out.println(Arrays.toString(arr));
System.out.println(new String(arr,"GBK"));//解码为字符串
}
}