JavaSE进阶05-IO流

01 Java流概述

  文件通常是由一连串的字节或字符构成,组成文件的字节序列称为字节流,组成文件的字符序列称为字符流。Java中根据流的方向可以分为输入流和输出流。输入流是将文件或其他输入设备的数据加载到内存的过程;输出流恰恰相反,是将内存中的数据保存到文件或其他输出设备。
IO流的分类:

  • 按照流的方向进行分类:以内存作为参照物,往内存中去,叫做输入(Input)。或者叫做读(Read)。从内存中出来,叫做输出(Output)。或者叫做写(Write)。
  • 按照读取数据方式不同进行分类:有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等…有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取。
    综上所述:流的分类
  • 输入流、输出流
  • 字节流、字符流

java.io包下需要掌握的流有16个:

文件专属:
	java.io.FileInputStream(掌握)
	java.io.FileOutputStream(掌握)
	java.io.FileReader
	java.io.FileWriter

转换流:(将字节流转换成字符流)
	java.io.InputStreamReader
	java.io.OutputStreamWriter

缓冲流专属:
	java.io.BufferedReader
	java.io.BufferedWriter
	java.io.BufferedInputStream
	java.io.BufferedOutputStream

数据流专属:
	java.io.DataInputStream
	java.io.DataOutputStream

标准输出流:
	java.io.PrintWriter
	java.io.PrintStream(掌握)

对象专属流:
	java.io.ObjectInputStream(掌握)
	java.io.ObjectOutputStream(掌握)

02 IO流四大家族

		java.io.InputStream  字节输入流
		java.io.OutputStream 字节输出流
		java.io.Reader		字符输入流
		java.io.Writer		字符输出流

四大家族的首领都是抽象类。(abstract class)

  • 所有的流都实现了:
    java.io.Closeable接口,都是可关闭的,都有close()方法。
    流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,
    不然会耗费(占用)很多资源。养成好习惯,用完流一定要关闭。

  • 所有的输出流都实现了:
    java.io.Flushable接口,都是可刷新的,都有flush()方法。
    养成一个好习惯,输出流在最终输出之后,一定要记得flush()
    刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据
    强行输出完(清空管道!)刷新的作用就是清空管道。
    注意:如果没有flush()可能会导致丢失数据。

注意:在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。

2.1 InputStream(字节输入流)

InputStream是字节输入流,InputStream是一个抽象类,所有继承了该类的都是字节输入流。
在这里插入图片描述
主要方法介绍:

voidclose() 关闭此输入流并释放与该流关联的所有系统资源
abstract intread() 从输入流读取下一个数据字节
intread(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲区数组b中
intread(byte[] b,int off,int len) 将输入流中最多len个数据字节读入字节数组

2.2 OutputStream(字节输出流)

所有继承OutputStream的都是字节输出流
在这里插入图片描述
主要方法介绍:

voidclose() 关闭此输出流并释放与此流有关的所有系统资源
voidflush() 刷新此输出流并强制写出所有缓冲的输出字节
voidwrite(byte[] b) 将b.length个字节从指定的字节数组写入此输出流
voidwrite(byte[] b,int off,int len) 将指定字节数组中从偏移量off开始的len个字节写入到输出流
abstract voidwrite(int b) 将指定的字节写入输出流

2.3 Reader(字符输入流)

所欲继承了Reader的都是字符输入流
在这里插入图片描述
主要方法介绍:

abstract voidclose() 关闭该流
intread() 读取单个字符
intread(char[] cbuf) 将字符读入数组
abstract intread(char cbuf,int off,int len) 将字符读入数组的某一部分

2.4 Writer(字符输出流)

所有继承了Writer的都是字符输出流
在这里插入图片描述
主要方法介绍:

Writerappend(char c) 将指定字符追加到此Writer
abstract voidclose() 关闭此流,但要先刷新它
abstract voidflush() 刷新此流
voidwriter(char cbuf) 写入字符数组
abstract voidwriter(char cbuf,int off,int len) 写入字符数组的某一部分
voidwriter(int c) 写入单个字符
voidwriter(String str) 写入字符串
voidwriter(String str,int off,int len) 写入字符串的某一部分

03 文件流

文件流主要分为:文件字节输入流、文件字节输出流、文件字符输入流、文件字符输出流

3.1 FileInputStream(文件字节输入流)

public class FileInputStreamTest {
    public static void main(String[] args) {
        InputStream is=null;
        try {
            is=new FileInputStream("test.txt");

            int b=0;
            while((b=is.read())!=-1){
                System.out.print((char)b);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

文件可以正确读取,但输出为这是一首简单的小æƒæ­Œï¼Œå”±ç€äººä»¬å¿ƒè‚ 的曲折乱码,原因在于字节输入流是一个字节一个字节读取的,而汉字是两个字节,因此读出一个字节就打印的输出是不完整的。

3.2 FileOutputStream(文件字节输出流)

FileOutputStream主要按照字节的方式写文件

public class FileOutputStreamTest {
    public static void main(String[] args) {
        InputStream is=null;
        OutputStream os=null;
        try {
            is=new FileInputStream("test.txt");
            os=new FileOutputStream("F:\\JavaTest\\JavaSE\\src\\test.txt.bak");
            int b=0;
            while((b=is.read())!=-1){
                os.write(b);
            }
            System.out.println("文件复制完毕!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                if(is!=null){
                    is.close();
                }
                if(os!=null){
                    os.close();
                }
            }catch (IOException e){}
        }
    }
}

3.3 FileReader(文件字符输入流)

FileReader是以字符为单位读取文件,即一次读取两个字节

public class FileReaderTest {
    public static void main(String[] args) {
        Reader r=null;
        try {
            r=new FileReader("test.txt");
            int b=0;
            while((b=r.read())!=-1){
                System.out.print((char)b);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(r!=null){
                try {
                    r.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

可以正确读取文本文件,汉字无乱码

3.4 FileWriter(文件字符输出流)

public class FileWriterTest {
    public static void main(String[] args) {
        Writer w=null;
        try {
            // append参数为true则表示在文件后面追加,默认为flase即覆盖原始文件内容
            w=new FileWriter("test.txt",true);
            w.write("我想我很快乐");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(w!=null){
                try {
                    w.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

04 缓冲流

  缓冲流主要是为了提高效率而存在的,减少物理读取次数,缓冲流主要有:BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter,并且 BufferedReader 提供了实用方法readLine(),可以直接读取一行,BufferWriter 提供了 newLine()可以写换行符。

4.1 采用字节缓冲流改造文件复制代码

public class BufferedStreamTest {
    public static void main(String[] args) {
        InputStream is=null;
        OutputStream os=null;
        try {
            is=new BufferedInputStream(new FileInputStream("test.txt"));
            os=new BufferedOutputStream(new FileOutputStream("src\\test.txt.bak"));
            int b=0;
            while((b=is.read())!=-1){
                os.write(b);
            }
            System.out.println("文件复制完毕!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
                try {
                    if(is!=null){
                    	is.close();   // 在close前会调用flush,将缓冲区的内容写入到磁盘
                    }
                    if(os!=null){
                        os.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
            }
        }
    }
}

可以显示的调用flushflush的含义是刷新缓冲区,即将缓冲区中的数据写到磁盘上,不再放到内存中。在执行os.close()时,默认执行了os.flush(),因此可以不显示的调用。

4.2 采用字符缓冲流改造文件复制代码

public class BufferedStreamTest {
    public static void main(String[] args) {
        BufferedReader br=null;
        BufferedWriter bw=null;
        try {
            br=new BufferedReader(new FileReader("test.txt"));
            bw=new BufferedWriter(new FileWriter("src\\test.txt.bak"));
            String s=null;
            while((s=br.readLine())!=null){
                bw.write(s);
            }
            System.out.println("文件复制完毕!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
                try {
                    if(br!=null){
                        br.close();   // 在close前会调用flush,将缓冲区的内容写入到磁盘
                    }
                    if(bw!=null){
                        bw.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
            }
        }
    }
}

05 转换流

转换流主要有两个 InputStreamReaderOutputStreamWriter

  • InputStreamReader 主要是将字节流输入流转换成字符输入流
  • OutputStreamWriter 主要是将字节流输出流转换成字符输出流

5.1 InputStreamReader

FileInputStreamTest.java 进行改造,使用字符流

public class InputStreamReaderTest {
    public static void main(String[] args) {
        BufferedReader br=null;
        try {
            br=new BufferedReader(new InputStreamReader(new FileInputStream("test.txt")));

            String s=null;
            while((s=br.readLine())!=null){
                System.out.print(s);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

5.2 OutputStreamWriter

FileOutputStreamTest.java 进行改造,使用字符流

public class OutputStreamWriterTest {
    public static void main(String[] args) {
        BufferedWriter bw=null;
        try {
            bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("test.txt")));
            bw.write("这是一首简单的小情歌");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                if(bw!=null){
                    bw.close();
                }
            }catch (IOException e){}
        }
    }
}

06 对象流

  对象流可以将 Java 对象转换成二进制写入磁盘,这个过程通常叫做序列化,并且还可以从磁盘读出完整的 Java 对象,而这个过程叫做反序列化
对象流主要包括:ObjectInputStreamObjectOutputStream

6.1 如何实现序列化和反序列化

如果实现序列化该类必须实现序列化接口 java.io.Serializable,该接口没有任何方法,该接口只是一种标记接口,标记这个类是可以序列化的

  • 序列化
public class ObjectStreamTest {
    public static void main(String[] args) {
        ObjectOutputStream oos=null;
        try {
            oos=new ObjectOutputStream(new FileOutputStream("src\\test.txt.bak"));
            Person p=new Person();
            p.name="张三";
            oos.writeObject(p);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(oos!=null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
    }
}

// 实现序列化接口,否则不能序列化
class Person implements Serializable {
    String name;
    int age;
}
  • 反序列化
public class ObjectStreamTest02 {
    public static void main(String[] args) {
        ObjectInputStream ois=null;
        try {
            ois=new ObjectInputStream(new FileInputStream("src\\test.txt.bak"));

            // 反序列化
            Person p=(Person)ois.readObject();
            System.out.println(p.name);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(ois!=null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

// 实现序列化接口,否则不能序列化
class Person implements Serializable {
    String name;
    int age;
}

6.2 关于transient关键字

采用transient关键字修饰的属性,在序列化时会忽略

class Person implements Serializable {
    String name;
    transient int age;
}

6.3 关于serialVersionUID属性

在序列化存储某类时,会为该类生成一个serialVersionUID,而在该类进行改动后,使用它时程序会为该类生成一个新的serialVersionUID,两个serialVersionUID不用,Java认为是不兼容的两个类,因此会出现错误。
如果在序列化类中定义了成员域serialVersionUID,系统会把当前的serialVersionUID成员域的值作为类的序列号,这样不管如何升级该类,它的序列号都不变。

class Person implements Serializable {
    private static final long serialVersionUID=-123455678754L;
    String name;
    int age;
}

重点:
参与序列化的类型必须实现java.io.Serializable接口。
并且建议将序列化版本号手动的写出来。private static final long serialVersionUID = 1L;

07 File类

  File 提供了大量的文件操作:删除文件,修改文件,得到文件修改日期,建立目录、列表文件等等。

  • 如何递归读取目录及子目录下的文件
public class FileTest {
    public static void main(String[] args) {
        listFile(new File("F:\\JavaTest"),0);
    }

    // 递归读取某个目录及子目录下所有文件
    private static void listFile(File f, int level){
        String s="";
        for (int i = 0; i < level; i++) {
            s+="--";
        }
        File[] files=f.listFiles();
        for (int i = 0; i < files.length; i++) {
            System.out.println(s+files[i].getName());
            if(files[i].isDirectory()){
                listFile(files[i],level+1);
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值