【JAVADAY24】温习之IO流

IO流

输入流:从硬盘读取数据到内存

输出流:从内存写出数据到硬盘

所有输出流都是可以刷新的,即将缓存的数据一次性发送出去,将管道中的剩余数据全部发送出去flush用完输出流一定要flush一下。


1、字节流,字节流是万能的,可以读写任何文件,文本文件、音频、视频…

以Stream结尾的都是字节流。

顶级父类:inputsteam、outputstream

用完流必须关闭,close;

1.1、输入字节流:file inputstream

1.2、输出字节流:file outputstrea

使用方法:

1)文件专属:任何类型的文件都可以使用该流来读写

filerinputstream

fileoutputstream

fileinputstream的read方法,如果无参,且不循环,只会执行一次,每次读一个字节,如a就读出来97…

返回的是一个int类型的。read最开始的指针指向第一个字节的前面,当调用一次它就往后移一次,如果移到某个位置什么也没有就返回-1。

public static void inptu(String sourpath) throws IOException {
        System.out.println("开始读取文件!");
        FileInputStream fileInputStream = new FileInputStream(sourpath);
        int lenth=0;
        while ((lenth=fileInputStream.read())!=-1){
            System.out.println(lenth);
        }
输出结果:
97
98
99
100
101
102
255
17

如果是有参的,即参数是一个字节数组,意思是从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。

System.out.println("开始读取文件!");
FileInputStream fileInputStream = new FileInputStream(sourpath);
//读的数据需要有地方存放
byte[] bytes = new byte[1024];
//fileInputStream.read(bytes);可以单独使用,只执行这个就已经把数据读到bytes中去了
//但是上面方法有一个缺点就是它会一直读文件,即使文件被读完了,它会一直返回-1-1-1-1...直到bytes被填满,然后执行下一句程序
//但是为什么要写一个while呢,因为read方法如果读完了就会返回-1,我们就能终止它继续往下返回-1-1-1,直接让它执行下一条语句
//这个无参的read()方法返回的int类型,是表示数据下一个字节的字节码,如果已经到达流的最后面了,那就返回-1.
int lenth=0;
//从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
while (fileInputStream.read(bytes)!=-1)
{	//这样写有个缺点,就是文件的内容可能早读完了,但是没够1024个字节,那么它就会在后面填满-1直到达到长度
    System.out.println(new String(bytes));
}

改进的方法很简单,加一个lenth
    因为该read的返回值是:
    返回:
读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回-1
            int length=0;
        //从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
        while ((length=fileInputStream.read(bytes))!=-1)
        {
            //取0-length作为子集转化为string输出
            System.out.println(new String(bytes,0,length));
        }



-----------------拷贝原理------------------读一部分写一部分-------------
public static void Copy(String sourPath,String Endpath) throws IOException {
    System.out.println("开始拷贝!");
    FileInputStream fileInputStream = new FileInputStream(sourPath);
    FileOutputStream fileOutputStream = new FileOutputStream(Endpath);
    int lenth=0;
    byte[] bytes = new byte[1024];
    while ((lenth=fileInputStream.read(bytes))!=-1){
        //第一次读最大bytes.length个字节放入bytes中,程序向下执行,即write方法
        //第二次读最大bytes.length个字节放入bytes中,它会把之前的bytes中的给覆盖掉,程序向下执行,即write方法
        //第三次...循环往复就完成了copy
        fileOutputStream.write(bytes,0,lenth);
    }
    fileInputStream.close();
    fileOutputStream.flush();
    fileOutputStream.close();
    System.out.println("拷贝完毕!");
}

fileoutputstream

public static void out(String endpath) throws IOException {
    System.out.println("开始写文件到"+endpath);
    FileOutputStream fileOutputStream = new FileOutputStream(endpath,true);//true追加写入
    string a="我是中国人我骄傲"
    byte[]  arr  =a.getBytes();
    byte[] bytes={'a','b','c','d','e','f', 97,arr};
    //将bytes写入到endpath文件中
    fileOutputStream.write(bytes);
    fileOutputStream.flush();
    fileOutputStream.close();
    System.out.println("写入完毕!");
}
//字节数组中只能写入数字或者字符,这两种有对应的字节比如'a'是97对应的二进制就是97的二进制

a.getBytes() 将字符串转换为字节数组的方法

2)转换流 :将字节流转为字符流,其他步骤没区别。切记write的时候别忘了flush!!!!否则可能就呆在内存中写不到硬盘里了。

inputstreamReader:本来是按字节读取,现在你可以指定格式比如我指定输出时以utf-8输出

FileInputStream fileInputStream = new FileInputStream(path);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");

outputstreamWriter:本来是该按字节输出的,现在可以直接write一个字符串,就这意思

public static void write(String path) throws IOException {
    FileOutputStream fileOutputStream = new FileOutputStream(path);
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
    outputStreamWriter.write("你好");
}

具体代码:

package com.sj.www;

import java.io.*;
import java.util.Arrays;

//此类是写入转换流
public class inputstreamReadAndWriter {
    public static void main(String[] args) throws IOException {
        String path="E:\\test1.txt";
        String writepath="E:\\test2.txt";
        read(path);
        write(writepath);
    }
    public static void read(String path) throws IOException {
        System.out.println("开始读取!");
        FileInputStream fileInputStream = new FileInputStream(path);
        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
        int length=0;
        char[] chars = new char[1024];
        while ((length=inputStreamReader.read(chars))!=-1){
            System.out.println(chars);
        }
        System.out.println("读取完毕!");
        inputStreamReader.close();
    }
    public static void write(String path) throws IOException {
        System.out.println("开始写入!");
        FileOutputStream fileOutputStream = new FileOutputStream(path,true);
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
        outputStreamWriter.write("你好");
        System.out.println("写入完毕!");
        outputStreamWriter.flush();
        outputStreamWriter.close();
    }
}

3)缓冲数据流:在处理字节时仍然写法一样,但是处理字符的时候就不一样呢,可以使用readline了,往下翻。

注意!!在out的时候别忘了flush!!!!!

bufferedinputstream

bufferedoutputstream

package com.sj.www;

import java.io.*;

//学习使用缓冲流
public class BufferedOutandInput {
    public static void main(String[] args) throws IOException {
        String path="E:\\test3.txt";
        out(path);
        input(path);
        String endpath="E:\\tetete.txt";
        copy(path,endpath);
    }
    public static void out(String path) throws IOException {
        System.out.println("开始写入!");
        FileOutputStream fileOutputStream = new FileOutputStream(path,true);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(bufferedOutputStream);
        for (int i = 0; i < 100; i++) {
            outputStreamWriter.write("你好我是keyle"+i+"\n");
        }
        outputStreamWriter.flush();
        outputStreamWriter.close();
        System.out.println("写入完毕!");
    }
    public static void input(String path) throws IOException {
        FileInputStream fileInputStream = new FileInputStream(path);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        InputStreamReader inputStreamReader = new InputStreamReader(bufferedInputStream);
        int length=0;
        char[] chars = new char[1024];
        while ((length=inputStreamReader.read())!=-1){
            System.out.println(chars);
            System.out.println(length);
        }
    }
    //这种显然就麻烦了,看下面bufferedRead
    public static void copy(String sourpath,String endpath) throws IOException {
        System.out.println("开始拷贝!");
        FileInputStream fileInputStream = new FileInputStream(sourpath);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        InputStreamReader inputStreamReader = new InputStreamReader(bufferedInputStream);

        FileOutputStream fileOutputStream = new FileOutputStream(endpath,true);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(bufferedOutputStream);
        int length=0;
        char[] chars = new char[1024];
        while ((length=inputStreamReader.read(chars))!=-1){
                outputStreamWriter.write(chars,0,length);
        }
        outputStreamWriter.flush();
        outputStreamWriter.close();
        inputStreamReader.close();
        System.out.println("拷贝完成!");
    }
}

如果确定要拷贝的是字符文本,则可以使用下面的方法,这里只是说可以这么拷贝,但是如果是单纯的文本,使用fileread,filewtite更简单。

public static void copy(String sourpath,String endpath) throws IOException {
    System.out.println("开始拷贝!");
    //首先先要有个文件字节输入流
    FileInputStream fileInputStream = new FileInputStream(sourpath);
    //然后把字节输入流转为字符输入流
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
    //然后就可以使用包装流bufferedReader了,这里inputStreamReader是节点流
    //括号里面的是节点流,外面的是包装流或者叫处理流
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
	
    FileOutputStream fileOutputStream = new FileOutputStream(endpath,true);
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
    BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
    String flag=null;
    while ((flag=bufferedReader.readLine())!=null){
            bufferedWriter.write(flag);
    }
    bufferedWriter.flush();
    bufferedWriter.close();
    bufferedReader.close();
    System.out.println("拷贝完成!");
}

4)数据流专属:不常用

datainputstream

dataoutputstream

5)标准输出流

print stream

比如我们常用的system.out就是printStream流,会这个就行了

给他提供一个文件输出流就可以输出到与这个输出流连接的文件里了

PrintStream printStream=new PrintStream(new FileOutputStream("E:\\Log.log"))
system.setout(printStream)
改变系统输出方向,将标准输出方向输出到"E:\\Log.log"

会用上面的就行,即改变输出的方向,不仅仅是输出到控制台就行。

6)对象专属流

objectinput stream

objectoutputstream

package com.sj.www;

import java.io.*;
import java.util.Date;

public class ObjectOutAndInput {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Cat[] c = new Cat[5];
        c[0] = new Cat("tom", 22, new Date());
        c[1] = new Cat("keyle", 22, new Date());
        c[2] = new Cat("zhangsan", 22, new Date());
        c[3] = new Cat("wanger", 22, new Date());
        c[4] = new Cat("zhaowu", 22, new Date());
        //可以序列化一个数组或集合
        serializable1("E:\\tom.txt", c);
        serializeable2("E:\\tom.txt");
    }

    //序列化一个类
    public static void serializable1(String path, Cat[] objects) throws IOException {
        //object需要一个与文件连接的输出流
        System.out.println("开始序列化!");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
        objectOutputStream.writeObject(objects);
        objectOutputStream.flush();
        objectOutputStream.close();
        System.out.println("序列化成功!");
    }

    //反序列化
    public static void serializeable2(String path) throws IOException, ClassNotFoundException {
        System.out.println("反序列化开始!");
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path));
        Cat[] o = (Cat[]) objectInputStream.readObject();
        for (Cat cat : o) {
            System.out.println("姓名:" + cat.getName() + " 年龄:" + cat.getAge() + " 生成日期:" + cat.getDate());
        }
        objectInputStream.close();
        System.out.println("反序列化结束!");
    }

}

//serializable可序列化的
class Cat implements Serializable {
    private String name;
    private int age;
    private Date date;

    public Cat(String name, int age, Date date) {
        this.name = name;
        this.age = age;
        this.date = date;
    }

    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 Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", date=" + date +
                '}';
    }
}

序列化注意了!!如果是在同一个类下,那么可能序列化和反序列化你不会发生因为位置不同导致的错误

如果在不同的包下,那么记得所在类的名字一定要一样!!!

  1. 类的对象序列化后,类的序列化ID不能改,否则反序列化会失败
  2. 序列化对象必须实现序列化接口
  3. 如果序列化对象的属性也是对象的话,也要实现序列化接口
  4. 类对象序列化后,类的属性有增加或删除不影响序列化,但是值会丢失
  5. 如果父类序列化了,子类不需要添加序列化接口即可直接继承父类的
  6. 如果父类没有序列化,子类序列化了,子类中的属性能正常序列化,但父类的属性会丢失,不能序列化
  7. 用java序列化的二进制字节数据只能由java反序列化。如果需要前后端或不同语言交互,一般需要将对象转成json或xml,而不是二进制
  8. 不想序列化的字段,前加transient关键字。
  9. 静态变量不能被序列化,即public static类型变量,不会被序列化,则如果在其序列化后、反序列化前修改值,则会展示新值。
  10. 如果你是out.write写进入的值注意读的时候字段顺序一定要一样
  11. 序列化与反序列化的类所在的包的相对路径名字一定要是一样的,在一个程序里可能遇不到这种问题,如果是2个窗口就不一定了。
报错的原因,原来序列化的那个类发生了变化,但是你没有序列化,导致反序列化报错
stream classdesc serialVersionUID = 1119075047339766943, local class serialVersionUID = -5001678293221878007 

2、字符流,以Reader/Writer结尾的都是字符流

顶级父类:reader、writer

用完流必须关闭,close;

使用方法:

1)标准输出流

print writer

2)缓冲流,只有这个流读的时候有readline方法,条件为null说明读完,其他都没有,依旧是-1才读完

我们不需要在自己定义一个char或者byte数组,该流自带

如果你比较懒,不想写一个数组,你就可以用该方法,自带数组,比较爽,可以直接readline输出一行,但不带换行符

bufferedReader

bufferedWriter

上面那个例子明显是用反了,哈哈哈哈哈哈。

public static void copy(String sourpath,String endpath) throws IOException {
    System.out.println("开始拷贝!");
    FileInputStream fileInputStream = new FileInputStream(sourpath);
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

    FileOutputStream fileOutputStream = new FileOutputStream(endpath,true);
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
    BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
    String flag=null;
    while ((flag=bufferedReader.readLine())!=null){
            bufferedWriter.write(flag);
    }
    bufferedWriter.flush();
    bufferedWriter.close();
    bufferedReader.close();
    System.out.println("拷贝完成!");
}

3)文件专属:文本文件,如果你直到自己想要读的是文本文件,使用这个方法,中文也能读出来不想字节只能读ascii码中存在的,用法和file inputstream 一样。

filereader

filewriter

package com.sj.www;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReadandWrite {
    public static void main(String[] args) throws IOException {
        String path="E:\\read.txt";
        read(path);
    }
    public static void read(String path) throws IOException {
        FileReader fileReader = new FileReader(path);
        char read = (char)fileReader.read();
        //fileReader.read() 返回int,int可以转为字符
        //返回的是字符的10进制形式,print默认转为string
        System.out.println(read);
        System.out.println((char) fileReader.read());
        //可以看出read无参时,每次只会读一个字符

        //还可以
        int length=0;
        //while ()..我就不演示了 一样,但是记住它只能处理文本文件
    }
}

缓冲流与普通流的关系

  • 不带缓冲的流读取到一个字节或字符,就直接写出数据
  • 带缓冲的流读取到一个字节或字符,先不输出,等达到了缓冲区的最大容量再一次性写出去
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Keyle777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值