Java基础|Java这些IO流你了解嘛


IO

  • 字节流
    • FileInputStream
    • FileOutputStream
    • 文件拷贝
  • 字符流
    • FileReader
    • FileWriter
    • 文件拷贝
  • 缓冲(处理)流
    • 缓冲字节流
    • 缓冲字符流
  • 打印流
  • 转换流
  • 数据流
  • 对象流

字节流 FileInputStream FileInputSteam:用于读取诸如图像数据的原始字节流
FileInputStream常用方法:
  • FileInputStream(File file)//创建文件输入流
  • read()//从该输入流读取一个字节的数据
  • read(byte[] b)//从该输入流读取最多 b.length个字节的数据为字节数组。
  • read(byte[] b, int off, int len) //从该输入流读取最多 len字节的数据为字节数组。
读文件
mport java.io.File; import java.io.FileInputStream; import java.io.IOException; public class FileInput { public static void main(String[] args) throws IOException { //utf-8进行存储,一个英文字母占一个字节,一个中文占3个字节 //如果文本文件,那么就不要使用字节流读取了,建议使用字符流 //read()读取一个字节,返回int类型,都是正数 //方式一: Input01(); //方式二 Input02(); } public static void Input01() throws IOException { //利用字节流读取文件 File file = new File("E:\\test.txt"); FileInputStream fi = new FileInputStream(file); int read = fi.read(); while(read!=-1){ System.out.print((char)read); read=fi.read(); }fi.close(); } public static void Input02() throws IOException { FileInputStream fi=new FileInputStream(new File("E:\\test.txt")); byte[] b=new byte[8]; int len=fi.read(b); while(len!=-1){ for(int i=0; i

FileOutputStream FileOutputStream用于写入诸如图像数据的原始字节流。
FileOutputStream常用方法:
  • FileOutputStream(File file)//创建文件输出流以写入由指定的 File对象表示的文件。
  • FileOutputStream(File file,boolean append)//创建文件输出流以覆盖(false)或者追加(true)的方式写入。
  • write(int b)//将指定的字节写入此文件。
  • write(byte[] b)//将b.lenth个字节从指定数组写入此文件中。
写文件
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; public class FileOutput { public static void main(String[] args) throws IOException { FileOutputStream fo=new FileOutputStream(new File("E:\\demo.txt")); String str="hello java!"; //写入的内容 byte[] b = str.getBytes(StandardCharsets.UTF_8); //按utf-8编码格式转成字节数组 fo.write(b); //写入操作 fo.close(); //关闭流 } }

文件拷贝
import java.io.*; public class FileCopy { public static void main(String[] args) throws IOException { File f1 = new File("E:\\test.txt"); File f2 = new File("E:\\demo.txt"); FileInputStream fi = new FileInputStream(f1); FileOutputStream fo = new FileOutputStream(f2); byte[] b = new byte[8]; int len = fi.read(b); while (len != -1) { fo.write(b, 0, len); len = fi.read(b); } fo.close(); fi.close(); } }

字符流 Java基础|Java这些IO流你了解嘛
文章图片

FileReader FileReader:是用于读取字符流。
FileReader常用方法:
  • new FileReader(File file); //构造方法
  • read(); //每次读取单个字符,返回该字符,如果读到文件末尾返回-1
  • read(char[] ch); //读取多个到数组,返回读取到的字符数,如果到文件末尾返回-1
读文件
import java.io.File; import java.io.FileReader; import java.io.IOException; public class FileRead { public static void main(String[] args) throws IOException { //方式一 Read01(); //方式二 Read02(); }public static void Read01() throws IOException { String path = "E:\\Test\\test01.txt"; File file = new File(path); FileReader fileReader = new FileReader(file); int read = fileReader.read(); while (read != -1) { System.out.print((char) read); read = fileReader.read(); } fileReader.close(); }public static void Read02() throws IOException { File file = new File("E:\\Test\\test01.txt"); FileReader fileReader = new FileReader(file); char[] ch = new char[8]; int len = fileReader.read(ch); //缓冲数组 while (len != -1) { //for (int i=0; i

FileWriter FileWriter:是用于写入字符流。
FileWriter常用方法:
  • new FileWriter(File file,boolean true); //构造方法,如果目标文件不存在,就自动创建该文件,默认为false,对源文件进行覆盖操作,true,对源文件末尾进行追加。
  • write(); //写入单个字符
  • write(char[] ch); //写入指定数组内容,也可写入数组的指定部分
  • write(String str); //写入指定字符串,也可写入字符串的指定部分
注意:FileWriter使用后,必须要关闭(close)或者刷新(flush),否者写入不到指定文件!
写文件
import java.io.*; public class FileWrite { public static void main(String[] args) throws IOException { //一个一个字符写入 // new FileWriter(file,false)对源文件按进行覆盖操作 // new FileWriter(file,true)对源文件进行追加,而不是覆盖 Write01(); //利用缓冲数组输出 Write02(); }public static void Write01() throws IOException { //如果目标文件不存在的话,那么会自动创建此文件 File file = new File("E:\\test.txt"); FileWriter fileWrite = new FileWriter(file, true); String str = "hello java!!!"; for (int i = 0; i < str.length(); i++) { fileWrite.write(str.charAt(i)); } fileWrite.close(); }public static void Write02() throws IOException { File file = new File("E:\\test.txt"); FileWriter fileWriter = new FileWriter(file, true); String str = "你好,java!"; char[] chars = str.toCharArray(); fileWriter.write(chars); fileWriter.close(); } }

文件拷贝
import java.io.*; //注意:不要用字符流去操作非文本文件 /* * 文本文件:.txt/.java/.c/.cpp-->建议使用字符操作 * 非文本文件:.jpj/.mp3/.mp4/.doc/.ppt-->建议使用字节流操作 * */public class FileCopy { public static void main(String[] args) throws IOException { //有一个源文件和一个目标文件 File f1 = new File("E:\\test.txt"); File f2 = new File("E:\\demo.txt"); //输入输出 FileReader fileReader = new FileReader(f1); FileWriter fileWriter = new FileWriter(f2); //一个一个字符复制 //int read=fileReader.read(); //while (read!=-1){ //fileWriter.write(read); //read=fileReader.read(); //}//利用字符数组 char[] ch=new char[1024]; int len=fileReader.read(ch); while(len!=-1){ String str=new String(ch,0,len); fileWriter.write(str); //fileWriter.write(ch,0,len); len=fileReader.read(ch); }//关闭流 fileWriter.close(); fileReader.close(); } }

缓冲(处理)流 一般情况下,我们使用字节字符流时,每次都是从源文件中读取/写入数据,这种操作效率比较低。
Java基础|Java这些IO流你了解嘛
文章图片

而利用缓冲(处理流),在程序(内存)里开辟一个缓冲区,然后在缓冲区里进行数据的读写,这样就不用每次都到源文件中操作。
Java基础|Java这些IO流你了解嘛
文章图片

缓冲流的使用
  • 创建文件对象(new File())
  • 创建输入输出流对象(new FileInputStream()/new FileReader())
  • 创建缓冲流对象(new BufferedInputStream(fi)/new BufferedReader(fr))
  • 利用缓冲流操作读写(read()/write())
  • 关闭流(bf.close())
如果处理流包裹着节点流的话,那么其实只要关闭高级流(处理流),那么里面的字节流也会随之被关闭。
缓冲字节流 当创建BufferedInputStream时,将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。
BufferedOutputStream实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
常用方法:
  • new BufferedInputStream(InputStream in)//创建一个 BufferedInputStream并保存其参数,输入流 in
  • new BufferedInputStream(InputStream in,int size)//创建 BufferedInputStream具有指定缓冲区大小,并保存其参数,输入流 in
  • read()//与InputStream中read()用法相同
  • read(byte[] b,int off,int len)// 与InputStream中read(byte[] b,int off,int len)相同
  • BufferedOutputStream(OutputStream out) //创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
  • BufferedOutputStream(OutputStream out, int size) //创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流
  • write(byte[] b, int off, int len) //从指定的字节数组写入 len个字节,从偏移 off开始到缓冲的输出流。
  • write(int b)//将指定的字节写入缓冲的输出流。
利用缓冲字节流对文件的拷贝
import java.io.*; public class BufferedStream { public static void main(String[] args) throws IOException { FileInputStream fi = new FileInputStream(new File("E:\\test.txt")); FileOutputStream fo = new FileOutputStream(new File("E:\\demo.txr")); BufferedInputStream bis=new BufferedInputStream(fi); BufferedOutputStream bos=new BufferedOutputStream(fo); byte[] b=new byte[1024]; int len=bis.read(b); while(len!=-1){ bos.write(b,0,len); len=bis.read(b); } bos.close(); bis.close(); } }

缓冲字符流
在使用字符缓冲流读文件时,使用readLine()可以读一行文字,返回的是一个字符串,如果我们要对这读取到这一行进行写操作时,就要手动的在下面添加换行,newLine(),不然的话会把所有的内容都写在同一行
利用缓冲字符流对文件的拷贝
import java.io.*; public class BufferedRW { public static void main(String[] args) throws IOException { FileReader fr=new FileReader(new File("E:\\test.txt")); FileWriter fw=new FileWriter(new File("E:\\demo.txt")); BufferedReader bfr=new BufferedReader(fr); BufferedWriter bfw=new BufferedWriter(fw); String str=bfr.readLine(); while(str!=null){ bfw.write(str); bfw.newLine(); str=bfr.readLine(); } bfw.close(); bfr.close(); } }

打印流
【Java基础|Java这些IO流你了解嘛】System.out:标准的输出流,默认情况下输出到控制台,返回的是打印流(PrintStream)
import java.io.PrintStream; public class Test { public static void main(String[] args) { PrintStream out = System.out; out.print("hello"); //直接在控制台上写出,不换行 out.println("java"); //直接在控制台上写出,并且换行操作 System.out.println("hello world"); } }

System.in:标准输入流,默认情况下,从键盘输入
Scanner:起扫描作用,扫描从键盘上输入的数据,还可以扫描其他流的数据
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Scanner; public class input { public static void main(String[] args) throws IOException { InputStream in = System.in; //得到标准的输入流 int a=in.read(); System.out.println(a); //Scanner可以扫描其他流的数据 Scanner sc=new Scanner(System.in); int b=sc.nextInt(); System.out.println(b); //Scanner扫描文件 Scanner input=new Scanner(new FileInputStream(new File("E:\\test.txt"))); while(input.hasNext()){ System.out.println(input.next()); } } }

转换流 转换流的作用
将字节流和字符流进行转换
转换流属于字节流还是字符流?
属于字符流
InputStreamReader:字节输入流–>字符输入流
OutputStreamWriter:字符输出流–>字节输出流
Java基础|Java这些IO流你了解嘛
文章图片

使用转换流对文件的复制
import java.io.*; public class Test02 { //这是一个main方法,是程序的入口: public static void main(String[] args) throws IOException { //1.有一个源文件 File f1 = new File("d:\\Test.txt"); //2.有一个目标文件: File f2 = new File("d:\\Demo.txt"); //3.输入方向: FileInputStream fis = new FileInputStream(f1); InputStreamReader isr = new InputStreamReader(fis,"utf-8"); //4.输出方向: FileOutputStream fos = new FileOutputStream(f2); OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk"); //5.开始动作: char[] ch = new char[20]; int len = isr.read(ch); while(len!=-1){ osw.write(ch,0,len); len = isr.read(ch); } //6.关闭流: osw.close(); isr.close(); } }

数据流
数据流:就是用来操作基本数据类型和字符串的
DataInputStream:将文件中存储的基本数据类型和字符串写入内存变量中
DataOutputStream:将内存中的基本数据类型和字符串的变量写出文件中
利用DataOutputStream向外写出变量
public class Test01 { //这是一个main方法,是程序的入口: public static void main(String[] args) throws IOException { //DataOutputStream:将内存中的基本数据类型和字符串的变量 写出文件中 File f = new File("d:\\Demo2.txt"); FileOutputStream fos = new FileOutputStream(f); DataOutputStream dos = new DataOutputStream(fos); //向外将变量写到文件中去: dos.writeUTF("你好"); dos.writeBoolean(false); dos.writeDouble(6.9); dos.writeInt(82); //关闭流: dos.close(); } }

打开文件可以看到,内容我们看不懂,这是给程序看的
Java基础|Java这些IO流你了解嘛
文章图片

我们用程序读取
import java.io.*; public class Test02 { //这是一个main方法,是程序的入口: public static void main(String[] args) throws IOException { //DataInputStream:将文件中存储的基本数据类型和字符串写入内存的变量中 DataInputStream dis = new DataInputStream(new FileInputStream(new File("d:\\Demo2.txt"))); //将文件中内容读取到程序中来: System.out.println(dis.readUTF()); System.out.println(dis.readBoolean()); System.out.println(dis.readDouble()); System.out.println(dis.readInt()); //关闭流: dis.close(); } }

输出
Java基础|Java这些IO流你了解嘛
文章图片

要求:写出的类型跟读入的类型 必须 要匹配!
对象流
数据流:就是用来操作基本数据类型和字符串的
DataInputStream:将文件中存储的基本数据类型和字符串写入内存变量中
DataOutputStream:将内存中的基本数据类型和字符串的变量写出文件中
序列化和反序列化
  • 序列化就是在保存数据时,保存数据的值和数据类型
  • 反序列化就是在恢复数据时,恢复数据的值和数据类型
需要让某个对象支持序列化和反序列化机制,则必须让其类是可序列化的,为了让某个类可序列化的,该类必须实现两个接口之一:
  • Serializable:标记接口,接口内部,什么都没有,这种接口叫 标识接口。起到标识作用,标识什么呢?只要实现这个接口的类的对象才能序列化,否则不可以。
  • Externalizable:一般不使用
serialVersionUID:凡是实现Serializable接口(标识接口)的类都有一个表示序列化版本标识符的静态常量
  • private static final long serialVersionUID
  • serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序加化时是否兼容
  • 如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
  • 简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
IDEA配置序列化版本号
Java基础|Java这些IO流你了解嘛
文章图片

alt+enter
Java基础|Java这些IO流你了解嘛
文章图片

序列化细节:
  • 被序列化的类的内部的所有属性,必须是可序列化的 (基本数据类型都是可序列化的)
  • static,transient修饰的属性 不可以被序列化。
public class Person implements Serializable { private static final long serialVersionUID = 8027651838638826533L; private transient String name; private static int age; 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 Person() { } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }

测试方法
public class Test01 { public static void main(String[] args) throws IOException { //序列化:将内存中对象 ---》 文件: //有一个对象: Person p = new Person("张三",19); //有对象流: ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:\\Demo4.txt"))); //向外写: oos.writeObject(p); //关闭流: oos.close(); } }

public class Test02 { public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:\\Demo4.txt"))); //读入内存: Person p = (Person)(ois.readObject()); System.out.println(p); //关闭流: ois.close(); } }

    推荐阅读