Java-IO流

导读:本篇文章讲解 Java-IO流,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

IO流

1. 概述

输入输出(I/O):

Input:输入,将硬盘中的数据读入程序中,进行程序的read操作

Output:输出,从程序往外部设备数据,进行程序的write操作

分类:

从数据流编码格式上可以分为字节流字符流

  • 字节流:InputStream和OutputStream的子类,读写二进制文件,处理音频,图片;处理单元为1个字节 字节流将读取到的字节数据,去指定的编码表中获取对应文字
  • 字符流:Reader和Writer的子类,处理字符或字符串,处理单元为一个字符.

按照数据流的传输方向分为输入流(从程序中往进读)和输出流(从程序中往外写)

按照流的功能不同分为节点流处理流

节点流

处理流

IO体系图如下:

在这里插入图片描述

2. 节点流

输入输出字节流

InputStream的常用方法

InputStream的常用方法 说明
int read() throws IOException 读取一个字节并以整数的形式返回(0~255),如果返回-1已到输入流的末尾。
int read(byte[] buffer) throws IOException 读取一系列字节并存储到一个数组buffer, 返回实际读取的字节数,如果读取前已到输入流的末尾返回-1
void close() throws IOException 关闭流释放内存资源
//首先告诉java输入流去读计算机上的哪个文件
File file =new File("E:/temp/1.txt");
//使用字节输入流读取文件
FileInputStream in = new FileInputStream(file);
for (int i = 0; i < 5; i++) {
    System.out.print((char)in.read());//从文件中每read一次,输入一个字节
}

在这里插入图片描述

运行结果:

在这里插入图片描述

OutputStream的常用方法

OutputStream的常用方法 说明
void write(int b) throws IOException 向输出流中写入一个字节数据,该字节数据为参数b的低8位
void write(byte[] b, int off, int len) throws IOException 将一个字节类型的数组中的从指定位置(off)开始的 len个字节写入到输出流
void close() throws IOException 关闭流释放内存资源
File file1 = new File("E:/temp/2.txt");
//使用字节输出流写入
FileOutputStream out = new FileOutputStream(file1);
//循环读写   从上次读取的位置开始
for (int i=5;i<file.length();i++){
	out.write(in.read());
}

执行后:

在这里插入图片描述

System.out.println("复制的新文件字节: "+file1.length());
FileInputStream in1 = new FileInputStream(file1);
System.out.println("复制的新文件内容:");
for (int i = 0; i < file1.length(); i++) {
	System.out.print((char)in1.read());
}
in.close();//读取工作完成,关闭输入流
in1.close();
out.close();//关闭输出流

运行结果:

在这里插入图片描述

read()/write(int b)

package iostreamdemo;
import java.io.*;
public class IoStreamDemo2 {
    public static void main(String[] args){
        
        FileInputStream in=null;
        FileOutputStream out=null;
        File f = new File("E:/temp/3.txt");
        try {
            in = new FileInputStream("E:/temp/1.txt");
            out= new FileOutputStream(f);
            int a = 0;//记录read()
            //一直读取直到读完内容   read()读到文件末尾返回-1
            while ((a=in.read())!=-1){
               out.write(a);
            }
            System.out.println("写入的新文件字节: "+f.length());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件未找到");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("读写异常");
        } finally {
            try {
                if(in!=null){
                    in.close();
                }
                if(out!=null){
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    }
}

运行结果:

在这里插入图片描述

在这里插入图片描述

read(byte[] b)/write(byte[] b, int off, int len)

package iostreamdemo;
import java.io.*;
public class IoStreamDemo3 {
    public static void main(String[] args) {

        /*
        read()
        每次只读一个字节并返回,读完返回-1 ,效率低

        read(byte[] b)
        每次最多读byte的数组长度个字节,返回数组中实际装入的字节个数
        266,读完返回-1
         */

        FileInputStream in=null;
        FileOutputStream out=null;
        File f = new File("E:/temp/4.txt");

        try {
             in= new FileInputStream("E:/temp/1.txt");
             out= new FileOutputStream(f);

            byte [] b = new byte[15];
            //记录数组元素数
            int length=0;
            //read(byte[],开始位置,数组长度)
            while ((length=in.read(b))!=-1){
                out.write(b,0,length);
                //每次向外写一个byte个字节,从指定位置开始(一般情况从0开始,向外写length个长度)
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件未找到");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("读取异常");
        } finally {
            try {
                if(in!=null){
                    in.close();
                }
                if(out!=null){
                    out.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

输入输出字符流

Reader的基本方法

方法 声明
read() 读一个字符,以整数返回,如果读取前已到输入流的末尾返回-1
read(char[] cbuf) 将字符读入数组,返回实际读取的字符,如果读取前已到输入流的末尾返回-1
close() 关闭流并释放与之相关联的任何系统资源

Writer的基本方法

方法 声明
write(int c) 写入一个字符
write(String str) 写入一个字符串
write(String str, int off, int len) 将一个字符串类型的数组中的从指定位置(offset)开始的 length个字符写入到输出流
write(char[] cbuf) 写入一个字符数组。
write(char[] cbuf, int off, int len) 将一个字符类型的数组中的从指定位置(offset)开始的 length个字符写入到输出流
flush() 刷新流
close() 关闭流(先刷新)
//新建空文件
File file = new File("E:/temp/6.txt");
//新建字符输入流
FileReader fileReader = new FileReader("E:/temp/1.txt");
//新建字符输出流
FileWriter fileWriter = new FileWriter(file);

read()/write(int c)

int a = 0;
System.out.println("文件内容: ");
//当读到文件末尾时,结束读取
while ((a=fileReader.read())!=-1){
    //将读取到的字符传给输出流对象,写入目标文件
    fileWriter.write(a);
    System.out.print((char)a);
}

运行结果:

在这里插入图片描述

在这里插入图片描述

read(char[] cbuf)/write(char[] cbuf, int off, int len)

		File file = new File("E:/temp/7.txt");
        FileReader fileReader = new FileReader("E:/temp/1.txt");
        FileWriter fileWriter = new FileWriter(file);
		
            char [] chars = new char[5];
            int length = 0;
            while ((length=fileReader.read(chars))!=-1){
                fileWriter.write(chars,0,length);
            }

            fileReader.close();
            fileWriter.close();

在这里插入图片描述

3. 处理流

对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写

常用类

缓冲流Buffer–

  • BufferedInputStream

  • BufferedOutputStream

package iostreamdemo;
import java.io.*;
public class BufferedDemo1 {
    public static void main(String[] args) {
        
        BufferedInputStream bin=null;
        BufferedOutputStream bout=null;
        
        try {
            //原始底端通道
            FileInputStream in = new FileInputStream("E:/temp/1.txt");
            //用带缓冲区的高级管道包装
             bin= new BufferedInputStream(in,2048);

            FileOutputStream out = new FileOutputStream("E:/temp/8.txt");
            bout=new BufferedOutputStream(out,2048);

            byte [] bytes = new byte[1024];
            int length=0;
            while ((length=bin.read(bytes))!=-1){
                bout.write(bytes, 0, length);
            }
            
            bin.close();
            bout.flush();//刷新缓冲区
            bout.close();//先刷新再关闭

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件未找到");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("读取异常");
        }
    }
}

在这里插入图片描述

  • BufferedReader

  • BufferedWriter

新建流

 File file1 = new File("E:/temp/9.txt");
FileReader fileReader = new FileReader(file1);
BufferedReader bufferedReader = new BufferedReader(fileReader);

File file2 = new File("E:/temp/10.txt");
//FileWriter fileWriter = new FileWriter(file2);//this(file, false); 每运行一次,写入数据会覆盖上一次的数据
FileWriter fileWriter = new FileWriter(file2,true);//(运行多次)追加,不会覆盖
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

在这里插入图片描述

读写

String line = null;
int i =0;
while ((line=bufferedReader.readLine())!=null){//当读一行为null时,结束循环
    //输出读取的文件内容
    System.out.println("第"+(++i)+"行:"+line);
    //一次写入一行数据
    bufferedWriter.write(line);
    //换行
    bufferedWriter.newLine();
}

关闭流

bufferedReader.close();//关闭输入缓冲流
bufferedWriter.close();//关闭输出缓冲流

运行结果:

在这里插入图片描述

在这里插入图片描述

我们再执行一次程序 ,目标文件变为:

在这里插入图片描述

注意:FileOutputStream及子类构造方法(File file, boolean append)

append=false不写该参数 表示写入会覆盖上一次的内容

append=true 表示写入会在原文件末尾添加

4. Print流

Print 打印流:只做输出没有输入 打印流分为字节打印流和字符打印流

PrintWriter:字符打印流 print方法可以打印各种类型数据

       /*
        打印流:只有输出,没有输入
        PrintWriter:字符打印流
        Print:打印各种数据
         */

		//PrintStream
        PrintStream printStream = new PrintStream("E:/temp/html/1.html");
        printStream.println("<h1>一级标题</h1>");
        printStream.println("<h2>二级标题</h2>");
        printStream.println("<h3>三级标题</h3>");
        printStream.println("<h4>四级标题</h4>");
        printStream.println("<h5>五级标题</h5>");
        printStream.close();

运行结果:

在这里插入图片描述

 		/*
        PrintWriter
         */
        PrintWriter printWriter = new PrintWriter("E:/temp/html/2.txt");
        printWriter.println("呼吸之野");
        printWriter.println("寻宝游戏");
        printWriter.println("青年晚报");
        printWriter.println("不如吃茶去");
        printWriter.println("梦游记");
        printWriter.println("苏格拉没有底");
        printWriter.println("寻雾启事");
        printWriter.println("自定义");
        printWriter.close();

运行结果:

在这里插入图片描述

5. 对象输入输出流

对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息。

对象信息 一旦写到文件上那么对象的信息就可以做到持久化了

对象的输出流: ObjectOutputStream

对象的输入流: ObjectInputStream

要将序列化之后的对象保存下来,需要通过对象输出流(ObjectOutputStream) 将对象状态保存,之后再通过对象输入流(ObjectInputStream)将对象状态恢复。 在ObjectInputStream 中用readObject()方法可以直接读取一个对象, ObjectOutputStream中用writeObject()方法可以直接将对象保存到输出流中

创建一个学生类

package objout;
import java.io.Serializable;
/*
    若需将一个类的对象信息序列化到文件中时,此类需要生成一个序列化ID号(版本号)
    implements Serializable 接口,默认会在类中生成一个版本号
    一旦类中的信息发生改变,版本号自动变化
    (实现接口,可以显式生成版本号,当类信息变化时,版本号不变)
 */
public class Student implements Serializable {

    private static final long serialVersionUID = -5854781956022497290L;
    private String xuehao;
    private String name;
    //关键字 transient 在对象序列化时,忽略此属性
    //private transient String name;
    

    //int temp;//测试有无版本号时,增删信息对InvalidClassException异常的影响
    public Student(String xuehao, String name) {
        this.xuehao = xuehao;
        this.name  = name;
    }

    public String getXuehao() {
        return xuehao;
    }

    public void setXuehao(String xuehao) {
        this.xuehao = xuehao;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "xuehao='" + xuehao + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

对象输出流

//实例化两个学生对象
Student student1 = new Student("1001", "张三");
Student student2 = new Student("1002", "李四");

//文件输出流
FileOutputStream fileOutputStream = new FileOutputStream("E:/temp/studentInfo.txt");
//对象输出流
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//将对象输出到文件中---序列化
objectOutputStream.writeObject(student1);
objectOutputStream.writeObject(student2);
//关闭流
objectOutputStream.close();

对象输入流

//创建文件输入流
FileInputStream fileInputStream = new FileInputStream("E:/temp/studentInfo.txt");
//创建对象对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
//读取文件中的对象,读入程序中---反序列化
Student student1 = (Student)objectInputStream.readObject();
Student student2 = (Student)objectInputStream.readObject();
//关闭流
objectInputStream.close();
//输出对象
System.out.println(student1);
System.out.println(student2);
/*
报错:
InvalidClassException
原因: 类中信息改变
解决: 显式地生成版本号,类信息改变不再报错
*/

在这里插入图片描述

package objout;
import java.io.*;
import java.util.Date;
public class ObjectOutputStreamDemo1 {
    private static Object FileInputStream;

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        /*
        将程序运行时那一刻的时间保存到文件中
        直接将对象信息存起来-->对象序列化
         */

        //对象输出流
        //实例化日期类
        Date date = new Date(1299999123123L);
        //文件输出流
        FileOutputStream fileOutputStream = new FileOutputStream("E:/temp/date.txt");
        //对象输出流
        ObjectOutputStream objout = new ObjectOutputStream(fileOutputStream);//对象序列化
        //将对象写入文件--序列化
        objout.writeObject(date);//写入参数为Object的对象
        //关闭对象输出流
        objout.close();


        /*
        对象输入流
         */
        FileInputStream fileInputStream = new FileInputStream("E:/temp/date.txt");
        ObjectInputStream objin = new ObjectInputStream(fileInputStream);

        Object obj = objin.readObject();//将对象反序列化

        if(obj instanceof Date){//判断obj是否是Date类型
            Date date1 = (Date)obj;//向下强转
            System.out.println(date1);
        }

    }
}

在这里插入图片描述

6. 对象序列化

对象的寿命通常随着生成该对象的程序的终止而终止。

有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。

对象的输出流将指定的对象写入到文件的过程,就是将对象序列化的过程,

对象 的输入流将指定序列化好的文件读出来的过程,就是对象反序列化的过程。

既然 对象的输出流将对象写入到文件中称之为对象的序列化,所以必须要实现 Serializable接口。

Serializable接口中没有任何方法。

当一个类声明实现Serializable接口后, 表明该类可被序列化。

在类中可以生成一个编号 private static final long serialVersionUID = -5974713180104013488L;

随机生成 唯一的 serialVersionUID 用来表明实现序列化类的不同版本间的兼容性。

某个类在 与之对应的对象已经序列化出去后做了修改,该对象依然可以被正确反序列化

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/15637.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!