Java基础——IO流(字节流、字符流、文件与文件夹的拷贝、缓冲流、转换流、基本数据类型流、序列化和反序列化)
一. IO 流
1.流的概念
流是一个抽象、动态的概念,是一连串连续动态的数据集合。
对于输入流而言,数据源就像水箱,流(stream)就像水管中流动着的水流,程序就是我们最终的用户。我们通过流(A Stream)将数据源(Source)中的数据(information)输送到程序(Program)中。
对于输出流而言,目标数据源就是目的地(dest),我们通过流(A Stream)将程序(Program)中的数据(information)输送到目的数据源(dest)中。
2.流的分类
按流的方向分类
- 输入流:数据流向是数据源到程序(以InputStream、Reader结尾的流)。
- 输出流:数据流向是程序到目的地(以OutPutStream、Writer结尾的流)。
按操作单元分类
- 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、FileOutputStream。
2. 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter。
按处理对象不同(功能)分类
1.节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等。
2.处理流(功能流):不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流。
节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性。
3.四大IO抽象类
· InputStream
此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。 数据的读取需要由它的子类来实现。根据节点的不同,它派生了不同的节点流子类 。
继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节(8 bit)。
常用方法:
int read():读取一个字节的数据,并将字节的值作为int类型返回(0-255之间的一个值)。如果未读出字节则返回-1(返回值为-1表示读取结束)。
void close():关闭输入流对象,释放相关系统资源。
· OutputStream
此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。
常用方法:
void write(int n):向目的地中写入一个字节。
void close():关闭输出流对象,释放相关系统资源。
· Reader
Reader用于读取的字符流抽象类,数据单位为字符。
int read(): 读取一个字符的数据,并将字符的值作为int类型返回(0-65535之间的一个值,即Unicode值)。如果未读出字符则返回-1(返回值为-1表示读取结束)。
void close() : 关闭流对象,释放相关系统资源。
· Writer
Writer用于写入的字符流抽象类,数据单位为字符。
void write(int n): 向输出流中写入一个字符。
void close() : 关闭输出流对象,释放相关系统资源。
4.字节流(万能流)***
字节输入流
InputStream 流向:输入流 操作单元:字节流 功能:节点流
此抽象类是表示字节输入流的所有类的超类。 不能实例化
FileInputStream 从文件系统中的某个文件中获得输入字节
read() 每次从输入流中读入一个字节的内容,想要读入多个,只能手动一个字节一个字节读入
int read(byte[] b) 一个字节数组一个字节数组读入
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /* * int read(byte[] b) 一个字节数组一个字节数组读入 */ public class ByteDemo02 { public static void main(String[] args) { //1.选择流 InputStream is=null; try { is=new FileInputStream("D:/test.txt"); //2.准备卡车 byte[] car=new byte[1024];//一般使用1024或1024的整数倍 //3.操作 读入 read(byte[]) 读到字节数组中多少个数的数据返回值为多少,没有读到返回-1 // int len=is.read(car); //读取 重读读入 通过字节数组 int len=-1; while((len=is.read(car))!=-1){ //4.处理数据 System.out.println(len); //11 System.out.println(new String(car, 0, len)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //5.关闭 try { if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
字节输出流
OutputStream 此抽象类是表示输出字节流的所有类的超类。
FileOutputStream 文件输出流是用于将数据写入 File的输出流。
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; //字节输出流 OutputStream public class ByteDemo03 { public static void main(String[] args) throws IOException { //1.选择流 如果目的地的文件不存在系统会自动创建指定文件,文件夹不会自动创建 ////boolean append true追加 false不追加(默认) OutputStream os=new FileOutputStream("D:/hehe.txt",true); //2.准备数据 int num=97; String str="周杰伦-晴天"; byte[] car=str.getBytes(); //3.写出 os.write(num); os.write(98); os.write(car); //4.强制刷出 os.flush(); //5.关闭 os.close(); } } 文件的拷贝 //文件拷贝: 数据源-->程序-->目的地 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; //文件拷贝: 数据源-->程序-->目的地 public class CopyFile04 { public static void main(String[] args) { //1.选择流 InputStream is=null; java.io.OutputStream os=null; try { is=new FileInputStream("D:/IMG_0024.JPG"); os=new FileOutputStream("D:/IMG_024.JPG"); //2.准备卡车 byte[] car=new byte[1024]; //3.读入写出 int len=-1; //读入到小卡车中数据的个数 while((len=is.read(car))!=-1){ os.write(car, 0, len); } //4.刷出--刷新此输出流并强制写出所有缓冲的输出字节。 os.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { if(os!=null){ os.close(); } if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
文件夹的拷贝
import java.io.File; import java.io.IOException; /* * 文件夹的拷贝 */ public class CopyDir { public static void main(String[] args) throws IOException { copyDir("D:/A", "C:"); } /* * 1.不能把文件拷贝到文件所在路径下 */ public static void copyDir(String src,String dest) throws IOException { // 判断/最后一次出现的位置索引 int index=src.lastIndexOf("/"); String str=src.substring(0, index); if(src.equals(dest) || (src+"/").equals(dest)){ throw new IOException("目标路径不能为源文件路径的子路径"); } copyDir(new File(src),new File(dest)); } /* * 2.目标路径不能为源文件路径的子路径下 */ private static void copyDir(File src,File dest) throws IOException { if(dest.getAbsolutePath().contains(src.getAbsolutePath())){ throw new IOException("目标路径不能为源文件路径的子路径下"); } //目标路径:完整路径 copyDirDetils(src, new File(dest,src.getName())); } private static void copyDirDetils(File src,File dest){ if(src.isFile()){ //如果目标文件所在路径文件存在不存在的情况,就创建多个不存在的文件夹 if(!dest.getParentFile().exists()){ dest.getParentFile().mkdirs(); } //调用拷贝文件类 CopyUtil.copyFile(src, dest); }else if(src.isDirectory()){ //创建目标路径所有不存在的文件夹 dest.mkdirs(); File[] file=src.listFiles(); for(File srcFile:file){ copyDirDetils(srcFile, new File(dest,srcFile.getName())); } } } }
5.字符流
字符流 :只能操作纯文本的内容 .txt .html 节点流 字符流
字符输入流
Reader 字符输入流 抽象类 FileReader 输入流
主要方法:read() | read(char[]) + close()
import java.io.FileReader; import java.io.IOException; import java.io.Reader; //字符输入流 public class CharDemo01 { public static void main(String[] args) throws IOException { //1.选择流 Reader reader=new FileReader("D:/test.txt"); //2.卡车 char[] car=new char[1024]; //3.读入 //逐个打印 //System.out.println((char)(reader.read())); int len=-1; while((len=reader.read(car))!=-1){ System.out.println(new String(car,0,len)); } reader.close(); } }
字符输出流
Writer 字符输出流 抽象类 FileWriter 输出流
FileWriter write() | write(char[]) | append() +flush() + close()
import java.io.FileWriter; import java.io.IOException; import java.io.Writer; //字符输出流 public class CharDemo02 { public static void main(String[] args) { //1.选择流 Writer writer=null; try { writer=new FileWriter("D:/haha.txt"); //2.准备数据 String str="伤心的人别听慢歌"; char[] arr={'-','五','月','天'}; //3.写出 writer.append(str); writer.write(arr); //4.刷出 writer.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if(writer!=null){ try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
字符流实现文件拷贝
1.文件–>程序 输入
2.程序–>文件 写出
import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; /*字符流实现文件拷贝: 1.文件-->程序 输入 2.程序-->文件 写出*/ public class CopyFile03 { public static void main(String[] args) { //1.选择流 Reader reader=null; Writer writer=null; try { reader=new FileReader(new File("D:/test.txt")); writer=new FileWriter(new File("D:/dest.txt")); //2.小卡车 char[] car=new char[1024]; //3.读写 int len=-1; while((len=reader.read(car))!=-1){ writer.write(car, 0, len); } //4.刷出 writer.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(writer!=null){ try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } if(reader!=null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
6.缓冲流
功能流的一种:
缓冲流:增强功能,提高性能
使用:功能流(节点流)
字节缓冲流
字节输入缓冲流 BufferedInputStream
字节输出缓冲流 BufferedOutputStream
无新增方法,可以发生多态
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; //字节缓冲流 public class BufferedInputStreamDemo { public static void main(String[] args) { //1.选择流 InputStream is=null; OutputStream os=null; try { is=new BufferedInputStream(new FileInputStream("D:/test.txt")); os=new BufferedOutputStream(new FileOutputStream("D:/hehe.txt")); //准备卡车 byte[] car=new byte[1024]; //3.读入写入 int len=-1; while((len=is.read(car))!=-1){ os.write(car, 0, len); } //刷出 os.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { if(os!=null){ os.close(); } if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
字符缓冲流
BufferedReader 新增方法 readLine() 读取一行
BufferedWriter 新增方法 newLine() 写出换行符
不能发生多态,因为父类引用对子类新增方法不可见
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; //字符缓冲流 public class BufferedReaderDemo { public static void main(String[] args) { //1.选择流 BufferedReader reader=null; BufferedWriter writer=null; try { reader=new BufferedReader(new FileReader("D:/haha.txt")); writer=new BufferedWriter(new FileWriter("D:/heihei.txt")); //2.读入写出 String msg=null; while((msg=reader.readLine())!=null){ writer.write(msg); writer.newLine(); } //3.刷出 writer.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ //关闭 if(writer!=null){ try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } if(reader!=null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
7.转换流(了解)
可以把字节流转为字符流使用
InputStreamReader(InputStream,String charset)
OutputSteamWriter(OutputSteam,String charset)
可能出现乱码的情况:
1.字符编码格式不统一
2.缺少字节个数
不同编码格式汉字所占字节大小:
ISO-8859-1 1个字节
GBK 2个字节
GB2312 2个字节
UTF-8 3个字节
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; //转换流----可以把字节流转为字符流使用 public class ConvertDemo { public static void main(String[] args) throws IOException { System.out.println("火".getBytes("ISO-8859-1").length);//1 System.out.println("火".getBytes("GBK").length);//2 System.out.println("火".getBytes("GB2312").length);//2 System.out.println("火".getBytes("UTF-8").length);//3 BufferedReader reader=new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream("D:/haha.txt")),"gbk")); BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream("D:/hengheng.txt")), "gbk")); String string=null; while((string=reader.readLine())!=null){ writer.write(string); writer.newLine(); } writer.flush(); writer.close(); reader.close(); } }
8.基本数据类型流
读写带有基本数据类型的数据+String
基本数据类型流(字节节点流)
DataInputStream(InputStream): 新增方法: readXXX()
DataOutputStream(OutputStream): 新增方法: writeXXX()
EOFException:文件存在,但是内部无法读取,不是源文件
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class DataDemo { public static void main(String[] args) throws IOException { readd("D:/haha.txt"); writee("D:/hhhh.txt"); } //读取带有基本数据类型+字符串的数据 public static void readd(String pathname) throws IOException { //1.输入流 DataInputStream inputStream=new DataInputStream(new BufferedInputStream(new FileInputStream(pathname))); //2.读入 读入和写出顺序要保持一致 int i=inputStream.read(); double d=inputStream.readDouble(); boolean b=inputStream.readBoolean(); String s=inputStream.readUTF(); System.out.println(i+"-->"+d+"-->"+b+"-->"+s); //3.关闭 inputStream.close(); } //写出带有基本数据类型的数据 public static void writee(String pathname) throws IOException{ //1.输出流 可以写出基本数据类型的数据 DataOutputStream outputStream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(pathname))); //2.准备数据 int i=23; double d=20.19; boolean b=true; String s="老詹"; //3.写出 outputStream.writeInt(i); outputStream.writeDouble(d); outputStream.writeBoolean(b); outputStream.writeUTF(s); //4.刷出 outputStream.flush(); //5.关闭 outputStream.close(); } }
9.序列化和反序列化
序列化:将对象信息转为可存储或者可传输的信息格式
对象流:
序列化输出流 ObjectOutputStream
反序列化输入流 ObjectInputStream
新增方法 readXxx() writeXxx()
先序列化后反序列化
不是所有的类都能序列化 实现一个空接口 java.io.Serializable
不是所有的属性都需要序列化 transient
静态的内容不能被序列化 默认值
如果父类实现了Serializable,子类中所有的内容都可以序列化
如果子类实现Serializable,父类中的内容没有序列化能力,只有子类的内容有
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; //序列化:将对象信息转为可存储或者可传输的信息格式 public class ObjectDemo { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { write("D:/lala.txt"); read("D:/lala.txt"); } //反序列化输入流 public static void read(String pathname) throws ClassNotFoundException, IOException { //1.对象输入流 ObjectInputStream inputStream=new ObjectInputStream(new BufferedInputStream(new FileInputStream(pathname))); //2.读 Person person=(Person) (inputStream.readObject()); int[] o=(int[]) inputStream.readObject(); System.out.println(person); System.out.println(Arrays.toString(o)); inputStream.close(); } //序列化输出流 public static void write(String pathname) throws FileNotFoundException, IOException{ //1.对象输出流 ObjectOutputStream outputStream=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(pathname))); //2.准备数据 Person person1=new Person("halo",18,1000); int[] arr={1,2,3,4}; //3,写出 outputStream.writeObject(person1); outputStream.writeObject(arr); //4.刷出 outputStream.flush(); outputStream.close(); } } class Person implements Serializable{ private String name; private int age; // 不是所有的属性都需要序列化 transient private transient double money; public Person() { // TODO Auto-generated constructor stub } public Person(String name, int age, double money) { super(); this.name = name; this.age = age; this.money = money; } 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; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", money=" + money + "]"; } }
- JAVA基础 day23 IO流的其他类 (对象的序列化 管道流 RandomAccessFile类(随机读取文件) DateStream(操作基本数据类型的流) 操作数组的流 )字符编码问题
- java中的io流(输入输出流,序列化与反序列化,字节流 , 字符流,包装流,缓冲流)
- 黑马程序员--Java基础学习之IO流之字节流、字符流、读取写入文件、Copy文件、键盘输入输出、流操作的基本规律
- Java笔记(7)-输入、输出流、File类、InputStream、Reader、文件字节流、文件字符流、缓冲流、随机流、数据流、对象流、序列化和对象克隆、Scanner解析文件、Console流
- java基础之IO转换流--OutputStreamWriter(字符流通往字节流,可以指定字符编码的IO流对象)
- Java基础——IO(拷贝文件+字节流-字符流缓冲区(装饰设计)-转换流-IO操作规律-异常日志-系统信息列表输出)
- 【Java基础知识】IO流--字节流读写数据以及复制文件的几种方式
- java基础的综合应用(类的应用,文本拷贝,IO流,数组,集合,文件文件夹的创建)
- 【java基础】采用字节流的文件IO演示,字节流与字符流转换,转换流的编码解码
- 黑马程序员——JAVA基础------IO流(四)----字节字符转换流和缓冲流
- JAVA基础再回首(二十二)——转换流概述及用法、简化写法FileWriter和 FileReader、字符缓冲流及特殊用法、字节流字符流复制文件方法总结
- 【java基础】在Java中实现基本数据类型与字符、字符串之间的转换
- JAVA基础 day21 字节流的输入和输出 字节流的缓冲区 (自己实现BufferedInputStream) 键盘输入 转换流的用法 改变标准输入输出设备 IO流操作的基本规律
- imooc java 文件传输基础——Java IO流 第6章 6-1序列化基本操作 对象的序列化 数据的反序列化 对象写成byte文件 读取byte文件显示对象内容
- 黑马程序员_字符流_字节流_IO异常处理_文件的续写_拷贝文本_缓冲流
- Java读写Properties文件及JavaIO中字节流和字符的转换
- 【Java基础知识】IO类--字符流读写数据以及复制文件的几种方式
- 黑马程序员——Java基础——IO流、字符流、字节流、缓冲区技术、装饰设计模式、LineNumberReader等
- 【Java基础知识】IO流——序列化/反序列化/serialVersionUID
- 小白成长记——Java基础之基本数据类型与字符串的相互转换