JavaIO流二

JavaIO流二

IO流的概述和分类

  • IO流的概述:
    • IO:输入/输出(Input/Output)
    • 流:是一种抽象概念:是对数据传输的总称也就是说数据在设备间的传输称为流,流的本质就是数据传输
    • IO流就是用来处理设备间数据传输问题的
      • 常见应用场景:文件复制,文件上传,文件下载
  • IO流分类:
    • 按照数据的流向
      • 输入流:读数据
      • 输出流:写数据
    • 按照数据类型来分
      • 字节流
        • 字节输入流、字节输出流
      • 字符流
        • 字符输出流、字符输入流
  • 一般我们把IO流按照数据类型来分的,而对于能读懂里面内容的可以采用字符流,否则就采用字节流。如果不知使用哪种流,就使用字节流

一、字节流

1.1、字节流写数据

字符流抽象基类

  • InputStream:这个抽象类就是表示字节输入流的所有类的超类
  • OutputStream:这个抽象类就是表示字节输出流的所有类的超类
  • 子类名特点:子类名称都是父类名作为子类名的后缀

FileOutputStream:文件输出流用于将数据写入File

  • FileOutputStream(String name):创建文件输出流以指定的名称写入文件

使用字节输出流写数据的步骤:

  • 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
  • 调用字节输出流对象的写数据方法
  • 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
        //创建字节输出流对象
        FileOutputStream file = new FileOutputStream("java基础语法\\javase.txt");
        /*
        * FileOutputStream三个功能:
        * 1、调用了系统功能创建文件
        * 2、创建字节输出流对象
        *3、让字节输出流对象指向创建好的文件
        * */
        //write(int b):将指定的字节写入此文件输出流。
        file.write(99);
//        file.write(57);
//        file.write(57);
        //所有IO流都需要释放资源
        //close():关闭此文件输出流并释放与此流相关联的任何系统资源。
        file.close();
    }

1.2、字节流写数据的三种方式

void write(int b) 将指定的字节写入此文件输出流。

void write(byte[] b) 将b.length个字节从指定的字节数组写入此文件输出流。

void write(byte[] b, int off, int len) 将len字节从位于偏移量 off的指定字节数组写入此文件输出流。 
public class FileOutputStreamdemo02 {
    public static void main(String[] args) throws IOException {
        //FileOutputStream(String name):创建文件输出流以指定的名称写入文件。
        FileOutputStream fos = new FileOutputStream("java基础语法\\fos.txt");
        //下面是上面创建fos.txt文件完整写法
//        FileOutputStream fos = new FileOutputStream(new File("java基础语法\\fos.txt"));

        //FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
//        File file = new File("java基础语法\\fos.txt");
//        FileOutputStream fos2 = new FileOutputStream(file);
//        FileOutputStream fos2 = new FileOutputStream(new File("java基础语法\\fos.txt"));

//        fos.write(97);
//        fos.write(98);
//        fos.write(99);
//        fos.write(100);
//        fos.write(101);

//        byte[] b = {97,98,99,100,101};
        //byte[] getBytes() :返回字符串对应的字节数组
        byte[] b = "abcde".getBytes();
//        fos.write(b);

        fos.write(b,0,b.length);
    }
}

1.3、字节流写数据的两个问题

  • 1、如何实现换行呢?
    • 写完数据后,加换行符
      • Windows:\r\n
      • linux:\n
      • mac:\r
  • 2、如何实现追加写入呢?
    • public FileOutputStream(String name,boolean append)
    • 创建文件输出流以指定的名称写入文件。如果第二个参数为true,则字节将写入文件的末尾而不是开头
 public static void main(String[] args) throws IOException {
        //创建字节输出流对象
//        FileOutputStream fos = new FileOutputStream("Java基础语法\\demo01.txt");
        //实现追加写入的方法
        FileOutputStream fos = new FileOutputStream("Java基础语法\\demo01.txt",true);
        //写入数据
        for (int i = 0; i < 10; i++) {
            fos.write("hello".getBytes());
            //实现换行的方法
            fos.write("\n".getBytes());
        }
        //释放资源
        fos.close();
    }

1.4、字节流写数据加异常处理

finally:在异常处理时提供finally块来执行所有的清除操作。比如说IO流中的释放资源

特点:被finally控制的语句一定会执行,除非JVM退出FileOutputStreamdemo03

    public static void main(String[] args){
//            try {
//                FileOutputStream fos = new FileOutputStream("Java基础语法\\demo02.txt");
//                fos.write("hello".getBytes());
//                fos.close();
//            }catch (IOException e){
//                e.printStackTrace();
//            }
        //加入finally来实现释放资源
    FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("Java基础语法\\demo02.txt");
            fos.write("hello".getBytes());
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

1.5、字节流读数据(一次读一个字节数据)01

FileInputStream:从文件系统中的文件获取输入字节

FileInputStream(String name):通过打开与实际文件的连接来创建一个 `FileInputStream ,该文件由文件系统中的路径名name命名。

public class FileInputStreamdemo01 {
    public static void main(String[] args) throws IOException {
        //创建字节流输入流对象
        FileInputStream fis = new FileInputStream("java基础语法\\demo02.txt");
        //调用字节流读数据的方法
        //int read():从该输入流读取一个字节的数据

//        //第一次读取数据
//        int by = fis.read();
//        System.out.println(by);
//        System.out.println((char)by);
//        //第二次读取数据
//        int by1 = fis.read();
//        System.out.println(by1);
//        System.out.println((char)by1);
        //上面的操作太过繁琐了
        //下面用循环做
//        int by = fis.read();
//        while(by != -1){
//            System.out.print((char)by);
//            by=fis.read();
//        }
        //优化
        int by;
        while((by=fis.read())!=-1){
            System.out.print((char)by);
        }
        //释放资源
        fis.close();
    }
}
//-----------------------------------------------------------------------------------------------------
//案例:复制文本文件
public class Demo01 {
    public static void main(String[] args) throws IOException {
        //创建字节输入流对象
        FileInputStream fis = new FileInputStream("D:\\test\\javase.txt");
        //创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("Java基础语法\\javase.txt");
        //读写数据
        int by;
        while((by=fis.read())!=-1){
            fos.write(by);
        }
        //释放资源
        fis.close();
        fos.close();
    }
}

1.6、字节流读数据(一次读一个字节数据数组)02

public class FileInputStreamdemo02 {
    public static void main(String[] args) throws IOException {
        //创建字节输入流对象
        FileInputStream fis = new FileInputStream("Java基础语法\\demo02.txt");
        //调用字节输入流对象的读数据方法
        //int read(byte[] b):从该输入流读取最多 b.length个字节的数据为字节数组
        /*
        byte[] bys = new byte[5];
        //第一次读数据
        int len = fis.read(bys);
        System.out.println(len);
        //String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的 String
//        System.out.println(new String(bys));
        System.out.println(new String(bys,0,len));
        //第二次读数据
        len = fis.read(bys);
        System.out.println(len);
//        System.out.println(new String(bys));
        System.out.println(new String(bys,0,len));
        //第三次读数据
        len = fis.read(bys);
        System.out.println(len);
        //String(byte[] bytes, int offset, int length):通过使用平台的默认字符集解码指定的字节子阵列来构造新的String
        System.out.println(new String(bys,0,len));
        */
        /*分析:
        * 第一次:hello
        * 第二次:\r\nwor
        * 第三次:ldwor
        * */

        byte[] bys = new byte[1024];//1024及其整数倍
        int len;
        while((len=fis.read(bys))!=-1){
            System.out.println(new String(bys,0,len));
        }
        //释放资源
        fis.close();
    }
}
//---------------------------------------------------------------------------------------------------------------
//案例:复制图片
public class Demo02 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:\\test\\AL.png");
        FileOutputStream fos = new FileOutputStream("Java基础语法\\AL.png");

        byte[] by = new byte[1024];
        int len;
        while((len=fis.read(by))!=-1){//read位置注意写要读取的对象
            fos.write(by,0,len);
        }

        fis.close();
        fos.close();
    }
}

1.7、字节缓冲流

  • BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流入字节,而不必为写入的每个字节导致底层系统的调用
  • BufferedInputStream:创建BufferedInputStream将创建一个内容缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

构造方法:

  • 字节缓冲输出流:BufferedOutputStream(OutputStream out)
  • 字节缓冲输入流:BufferedInputStream(InputStream in)

为何构造方法所需的是字节流,而不是具体的文件或者路径?

  • 这是因为字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
public class BufferedStreamdemo {
    public static void main(String[] args) throws IOException {
//        FileOutputStream fos = new FileOutputStream("Java基础语法\\fos.txt");
        //创建字节缓冲输出流
//        BufferedOutputStream bos = new BufferedOutputStream(fos);
        //合并上面两步
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Java基础语法\\fos.txt"));
        //写数据
        bos.write("hello\r\n".getBytes());
        bos.write("world\r\n".getBytes());
        //释放资源
        bos.close();

        //创建字节缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("Java基础语法\\\\fos.txt"));
        //读数据
        //一次读一个字节数据
//        int by;
//        while((by=bis.read())!=-1){
//            System.out.print((char)by);
//        }
        //一次读取一个字节数组的数据
        byte[] bys = new byte[1024];
        int len;
        while((len=bis.read(bys))!=-1){
            System.out.print(new String(bys,0,len));
        }
        //释放资源
        bis.close();
    }
}
//-------------------------------------------------------------------------------------------------------------
//案例:复制视频
public class Demo03 {
    public static void main(String[] args) throws IOException{
        //记录开始时间
        long startTime = System.currentTimeMillis();

        //复制视频
//        method1();//用时77834毫秒
//        method2();//用时99毫秒
//        method3();//用时321毫秒
        method4();//用时44毫秒
        //记录结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("共耗时"+(endTime-startTime)+"毫秒");
    }
    //字节缓冲流一次读写一个字节数组
    public static void method4() throws IOException{
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\deng.mp4"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Java基础语法\\deng.mp4"));
        byte[] bys = new byte[1024];
        int len;
        while((len=bis.read(bys))!=-1){
            bos.write(bys,0,len);
        }
        bis.close();
        bos.close();
    }
    //字节缓冲流一次读写一个字节
    /*
    public static void method3() throws IOException{
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\deng.mp4"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Java基础语法\\deng.mp4"));
        int by;
        while((by=bis.read())!=-1){
            bos.write(by);
        }
        bis.close();
        bos.close();
    }*/

    //基本字节流一次读写一个字节数组
    /*
    public static void method2() throws IOException{
        FileInputStream fis = new FileInputStream("D:\\test\\deng.mp4");
        FileOutputStream fos = new FileOutputStream("Java基础语法\\deng.mp4");
        byte[] bys = new byte[1024];
        int len;
        while((len=fis.read(bys))!=-1){
            fos.write(bys,0,len);
        }
        fis.close();
        fos.close();
    }*/

    //基本字节流一次读写一个字节
    //这种方式运行起来是非常慢的
    /*
    public static void method1() throws IOException {
        FileInputStream fis = new FileInputStream("D:\\test\\deng.mp4");
        FileOutputStream fos = new FileOutputStream("Java基础语法\\deng.mp4");
        int by;
        while((by=fis.read())!=-1){
            fos.write(by);
        }
        fis.close();
        fos.close();
    }*/
}

二、字符流

2.1、字符流的一些基本内容

  • 因为字节流操作中文不是特别的方便,所以Java就提供字符流
  • 字符流=字节流+编码表
  • 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
  • 采用何种规则编码,就要采用对应的规则解码,否则就会出现乱码

2.2、字符串和字符流中的编码解码问题

编码:

  • byte[] getBytes():使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中
  • byte[] getBytes(String charsetName):使用命名的字符集将此 String编码为字节序列,将结果存储到新的字节数组中

解码:

  • String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String

  • String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的String

字符流的抽象基类

  • Reader:字符输入流的抽象类
  • Writer:字符输出流的抽象类

字符流中和编码解码问题相关的两个类:

  • InputStreamReader
  • OutPutStreamWriter
//字符串中的编码解码问题
public class StringDemo01 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //定义一个字符串
        String s = "中国";
        //byte[] getBytes():使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中
        byte[] bys = s.getBytes();//[-28, -72, -83, -27, -101, -67]
        //byte[] getBytes(String charsetName):使用命名的字符集将此 `String`编码为字节序列,将结果存储到新的字节数组中
//        byte[] bys = s.getBytes("UTF-8");//[-28, -72, -83, -27, -101, -67]
//        byte[] bys = s.getBytes("GBK");//[-42, -48, -71, -6]
        System.out.println(Arrays.toString(bys));

        //String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
//        String ss = new String(bys);//结果为中国
        //String(byte[] bytes,  String charsetName):通过指定的字符集解码指定的字节数组来构造新的String
//        String ss = new String(bys,"UTF-8");//结果为中国
        String ss = new String(bys,"GBK");//乱码了
        System.out.println(ss);
    }
}

//字符流中的编码解码问题
public class CharacterStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //OutputStreamWriter(OutputStream out):创建一个使用默认字符编码的OutputStreamWriter
        //OutputStreamWriter(OutputStream out, String charsetName):创建一个使用命名字符集的OutputStreamWriter

//        FileOutputStream fos = new FileOutputStream("Java基础语法\\osw.txt");
//        OutputStreamWriter osw = new OutputStreamWriter(fos);
        //把上面两句合并写
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\osw.txt"));
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\osw.txt"),"UTF-8");
        osw.write("中国");
        osw.close();
//      InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader。
//      InputStreamReader(InputStream in, String charsetName):创建一个使用命名字符集的InputStreamReader。
        InputStreamReader isr = new InputStreamReader(new FileInputStream("Java基础语法\\osw.txt"),"UTF-8");
        //一次读取一个字符数据
        int ch;
        while ((ch=isr.read())!=-1){
            System.out.print((char)ch);
        }
    }
}

2.3、字符流写数据的5种方式

public class OutputStreamWriterdemo {
    public static void main(String[] args) throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\osw.txt"));
        //void writer(int c):写一个字符的
//        osw.write(97);
//        //void flush():刷新流
//        osw.flush();
//        osw.write(98);
//        osw.flush();
//        osw.write(99);

        //void writer(char[] cbuf):写一个字符数组
        char[] chs = {'a','b','c','d','e'};
//        osw.write(chs);
        //void writer(char[] cbuf,int off,int len):写一个字符数组的一部分
//        osw.write(chs,0,chs.length);
//        osw.write(chs,1,3);

        //void writer(String str):写一个字符串
//        osw.write("abcde");
        //void writerString str,int off,int len):写一个字符串的一部分
        osw.write("abcde",1,3);
        
        osw.close();
    }
}

2.4、字符流读数据的2种方式

  • int read():读一个字符

  • int read(char[] cbuf, int offset, int length):将字符读入数组的一部分。

public class InputStreamdemo {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("Java基础语法\\osw.txt"));
        //int read():读一个字符
//        int ch;
//        while((ch=isr.read())!=-1){
//            System.out.print((char)ch);
//        }
        //int read(char[] cbuf,  int offset, int length):将字符读入数组的一部分。
        char[] chs = new char[1024];
        int len;
        while((len=isr.read(chs))!=-1){
            System.out.print(new String(chs,0,len));
        }
        //释放资源
        isr.close();
    }
}

2.5、字符流复制java文件

public class Demo01 {
    public static void main(String[] args) throws IOException {
        //创建输入流对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream("Java基础语法\\CharacterStreamDemo01.java"));
        //创建输出流对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\Copy.java"));
        //读写数据,复制文件
        //一次读取一个字符
//        int ch;
//        while((ch=isr.read())!=-1){
//            osw.write(ch);
//        }

        //一次读取一个字符数组
        char[] chs = new char[1024];
        int len;
        while((len=isr.read(chs))!=-1){
            osw.write(chs,0,len);
        }
        //释放资源
        isr.close();
        osw.close();
    }
}
//改进版,所需用到InputStreamReader和OutputStreamWriter的子类
//FileReader:用于读取字符文件的便捷类
//FileWriter:用于写入字符文件的便捷类
//FileReader(String fileName):创建一个新的 FileReader ,给定要读取的文件的名称。
//FileWriter(String fileName):构造一个给定文件名的FileWriter对象。
public class Demo02 {
    public static void main(String[] args) throws IOException {
        //创建字符输入流对象
        FileReader fr = new FileReader("Java基础语法\\CharacterStreamDemo01.java");
        //创建字符输出流对象
        FileWriter fw = new FileWriter("Java基础语法\\Copy.java");
        //读取数据,复制文件
        //一次读取一个字符
//        int ch;
//        while((ch=fr.read())!=-1){
//            fw.write(ch);
//        }

        //一次读取一个字符数组
        char[] chs = new char[1024];
        int len;
        while((len=fr.read(chs))!=-1){
            fw.write(chs,0,len);
        }
        //释放资源
        fr.close();
        fw.close();
    }
}

2.6、字符缓冲流

  • BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。

  • BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。

构造方法:

  • BufferedWriter(Writer out):创建使用默认大小的输出缓冲区的缓冲字符输出流。
  • BufferedReader(Reader in): 创建使用默认大小的输入缓冲区的缓冲字符输入流。
public class BufferedStreamdemo {
    public static void main(String[] args) throws IOException {
//        FileWriter fw = new FileWriter("Java基础语法\\bw.txt");
//        BufferedWriter bw = new BufferedWriter(fw);
        //合并
//        BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\bw.txt"));
//        bw.write("hello\r\n");
//        bw.write("js");
//        bw.close();
        BufferedReader br = new BufferedReader(new FileReader("Java基础语法\\bw.txt"));
        //一次读取一个字符
//        int ch;
//        while((ch=br.read())!=-1){
//            System.out.print((char)ch);
//        }
        //一次读取一个字符数组
        char[] chs = new char[1024];
        int len;
        while((len=br.read(chs))!=-1){
            System.out.print(new String(chs,0,len));
        }
        br.close();
    }
}

//案例:利用字符缓冲流来复制java文件
public class demo03 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("Java基础语法\\CharacterStreamDemo01.java"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\Copy.java"));

//        int ch;
//        while((ch=br.read())!=-1){
//            bw.write(ch);
//        }
        char[] chs = new char[1024];
        int len;
        while((len=br.read(chs))!=-1){
            bw.write(chs,0,len);
        }

        br.close();
        bw.close();
    }
}

2.7、字符缓冲流特有功能

  • BufferedWriter
    • void newLine():写一行行分隔符,行分隔符字符串由系统属性定义
  • BufferedReader
    • public String readLine():读一行文字,结构包含行的内容的字符串,不包括任何终止字符,如果流的结尾已经到达,则为null
public class BufferedStreamdemo02 {
    public static void main(String[] args) throws IOException {
//        BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\bw.txt"));
//        for (int i=0;i<=10;i++){
//            bw.write("hello"+i);
////            bw.write("\r\n");
//            bw.newLine();
//            bw.flush();
//        }
//        bw.close();

        BufferedReader br = new BufferedReader(new FileReader("Java基础语法\\bw.txt"));
        String ch;
       while((ch=br.readLine())!=null){
           System.out.println(ch);
       }
        br.close();
    }
}

//案例:利用字符流特有功能复制java文件
public class demo04 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("Java基础语法\\CharacterStreamDemo01.java"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\Copy.java"));

        String line;
        while((line=br.readLine())!=null){
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        br.close();
        bw.close();
    }
}
posted @ 2022-02-09 21:03  Devin-Y  阅读(27)  评论(0编辑  收藏  举报