Java学习 day17_IO

  • 第二种 try-with-resourses

  • //语法
    try(资源,实现AutoCloseable接口){
        // 代码
    }catch{
        
    }finally{
        
    }
    特点:try代码块中的代码执行完  会自动close
    
  • Demo

  • package com.cskaoyan.bytestream.out;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /**
     * @description: 异常处理方式二
     * @author: songtao@cskaoyan.onaliyun.com
     **/
    
    public class Demo1 {
        public static void main(String[] args) {
            try(FileOutputStream out = new FileOutputStream("a.txt");){
                // write data
                out.write(97);
                
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
  • package com.cskaoyan.bytestream.out;
    
    /**
     * @description:
     * @author: songtao@cskaoyan.onaliyun.com
     **/
    
    public class Demo2 {
        public static void main(String[] args) {
            try(A a = new A()){
                a.call();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    // 定义一个类  实现AutoCloseable接口
    class A implements AutoCloseable{
        public void call() {
            System.out.println("执行了call方法");
        }
    
        @Override
        public void close() throws Exception {
            System.out.println("执行了close方法");
        }
    }
    
字节缓冲输出流BufferedOutputStream

该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统

继承关系

在这里插入图片描述

构造方法

BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 默认缓冲区大小为8KB
BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

注意:

像这种需要底层流最为参数的叫做包装流, 而这个参数叫做底层流

原因是因为需要底层流的功能

简单理解就是,要创建一个缓冲输出流,就必须使用更低层流的功能,所以创建时的参数就是一个低层流

demo

package com.cskaoyan.bytestream.buff;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo1 {
    public static void main(String[] args) throws IOException {
        // 构造方法
        BufferedOutputStream bo =
                new BufferedOutputStream(new FileOutputStream(new File("a.txt")));
        //
        BufferedOutputStream bufferedOutputStream = 
                new BufferedOutputStream(new FileOutputStream("a.txt"),1024);
    }
}

成员方法

3个write方法

write demo

package com.cskaoyan.bytestream.buff;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 创建缓冲输出流对象
        BufferedOutputStream bo =
                new BufferedOutputStream(new FileOutputStream("a.txt"));
        // write
        bo.write("hello world".getBytes());
        // flush
        //bo.flush();
        bo.close();
    }
}

在这里插入图片描述

注意

  • 如果没有执行flush方法 数据会在缓冲区当中 并不会写入底层流当中
  • 一定要close close里面执行了flush方法
  • 哪些流需要flush?
    • 所有带缓冲区的输出流 都要flush

装饰器设计模式(了解)

在原有类的基础上扩展一点新的功能

例子:

抽象基类:Beverage

子类:MilkTea

基础款 加冰

小料: 加椰果 加珍珠的 布丁

在这里插入图片描述

package com.cskaoyan.bytestream.decorate;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

// 定义抽象基类  饮料类
public abstract class Beverage {
    // 该方法表示加小料
    abstract void add();
}

// 定义子类  奶茶类
class MilkTea extends Beverage{

    @Override
    void add() {
        System.out.println("老板,来杯奶茶,加冰!");
    }
}

// 定义一个装饰器类
class Decorate extends Beverage{
    // 定义一个成员变量
    Beverage beverage;

    public void setBeverage(Beverage beverage) {
        this.beverage = beverage;
        // 虽然抽象类不可以实体化,但是可以定义引用指向其子类
    }

    @Override
    void add() {
        beverage.add();
    }
}

//定义小料类
class DecorateA extends Decorate{
    @Override
    void add() {
        super.add();
        // 加椰果
        addYg();
    }

    private void addYg() {
        System.out.println("再加点椰果!");
    }
}

class DecorateB extends Decorate{
    @Override
    void add() {
        super.add();
        // 加珍珠
        addZz();
    }

    private void addZz() {
        System.out.println("再加点珍珠!");
    }
}



package com.cskaoyan.bytestream.decorate;

/**
 * @description: 测试类
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo {
    public static void main(String[] args) {
        // 创建一个基础款的奶茶
        System.out.println("基础款---------");
        MilkTea milkTea = new MilkTea();
        milkTea.add();
        System.out.println("加小料-------");
        DecorateA decorateA = new DecorateA();
        decorateA.setBeverage(milkTea);
        decorateA.add();
        System.out.println("-------------");
        DecorateB decorateB = new DecorateB();
        decorateB.setBeverage(decorateA);
        decorateB.add();
    }
}

注意:关闭包装流就相当于也关闭了包装的对象,所以不需要特意关闭包装对象


练习:

包装BufferedInputStream , 扩展功能 , 把大写转换为小写字符 ABC → abc

怎么做呢?

继承FilterInputStream 重写read方法 read() , read(byte[] b, int off, int len)

在这里插入图片描述

package com.cskaoyan.bytestream.decorate;

import java.io.*;

/**
 * @description: 大写转小写
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo2 {
    public static void main(String[] args) throws IOException{
        // 包装BufferedInputStream
        BufferedInputStream br = new BufferedInputStream(new FileInputStream("a.txt"));
        LowerCaseInputStream lowerCaseInputStream = new LowerCaseInputStream(br);
        //int readData = lowerCaseInputStream.read();
        //System.out.println(((char) readData));
        //int readData2 = lowerCaseInputStream.read();
        //System.out.println(((char) readData2));

        // 字节数组
        byte[] bytes = new byte[1024];
        int readCount = lowerCaseInputStream.read(bytes, 0, bytes.length);
        System.out.println(new String(bytes,0,readCount));
        // close
        lowerCaseInputStream.close();
    }
}

class LowerCaseInputStream extends FilterInputStream{

    /**
     * Creates a <code>FilterInputStream</code>
     * by assigning the  argument <code>in</code>
     * to the field <code>this.in</code> so as
     * to remember it for later use.
     *
     * @param in the underlying input stream, or <code>null</code> if
     *           this instance is to be created without an underlying stream.
     */
    protected LowerCaseInputStream(InputStream in) {
        super(in);
    }
    // 目标就是改造 重写read方法  把读到的大写 字符 修改成小写的  返回

    //重写read()

// 这里写了俩read方法是因为本身FileOutputStream就有两个read方法 remember?
    @Override
    public int read() throws IOException {
        int readData = super.read();
        // 大写 → 小写
        //char c = Character.toLowerCase(((char) readData));

        return (readData == -1 ? -1: ((byte) Character.toLowerCase(((char) readData))));
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int readCount = super.read(b, off, len);
        // 关键是处理字节数组b
        for (int i = off; i < off + len; i++) {
            b[i] = ((byte) Character.toLowerCase(((char) b[i])));
        }
        return readCount;
    }
}

利用缓冲流去实现文件复制

package com.cskaoyan.bytestream.buff;

import java.io.*;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo4 {
    public static void main(String[] args) throws IOException {
        // 创建缓冲输入流
        BufferedInputStream br =
                new BufferedInputStream(new FileInputStream("D:\\aa.mp4"));
        // 创建缓冲输出流
        BufferedOutputStream bo =
                new BufferedOutputStream(new FileOutputStream("copy_aa.mp4"));
        // 边读边写
        // 单字节
        long start = System.currentTimeMillis();
        //int readData;
        //while ((readData = br.read()) != -1) {
        //    bo.write(readData);
        //}
        // 字节数组
        int readCount;
        byte[] bytes = new byte[1024];
        while ((readCount = br.read(bytes)) != -1) {
            bo.write(bytes, 0, readCount);
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时" + (end - start) + "ms");

        // close
        bo.close();
        br.close();
    }
}


字节输入流

基类

InputStream

继承关系

在这里插入图片描述

成员方法

abstract intread() 从输入流中读取数据的下一个字节。
intread(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
intread(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。

注意:

从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。

具体子类

FileInputStream

继承关系

构造方法:

FileInputStream(File file) 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(String name) 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
        // File file
        FileInputStream inputStream = new FileInputStream(new File("a.txt"));
        // String 文件名
        FileInputStream inputStream1 = new FileInputStream("a.txt");

成员方法

3个read方法

对于read(byte[] b) 读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。

在这里插入图片描述

package com.cskaoyan.bytestream.in;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * @description: read
 * @author: songtao@cskaoyan.onaliyun.com
 **/
/*
    读取数据的步骤
    1.创建字节输入流对象
    2.read方法读取数据
    3.close
 */
public class Demo2 {
    public static void main(String[] args) throws IOException {
        //1.创建字节输入流对象
        FileInputStream in = new FileInputStream("a.txt");
        //2.read方法读取数据
        // 读取单个字节
        // readData 表示的是读取的字节值
        //readSingle(in);
        // 读取多个字节 字节数组

        //前提是a.txt存了abcdef
        byte[] bytes = new byte[4];
        int readCount = in.read(bytes);
        System.out.println(readCount);
        System.out.println(new String(bytes,0,readCount));
        // abcd
        int readCount2 = in.read(bytes);
        System.out.println(readCount2);
        System.out.println(new String(bytes,0,readCount2));
        // 如果仍然输出四个byte,那就输出efcd
        //3.close
        in.close();
    }

    private static void readSingle(FileInputStream in) throws IOException {
        int readData = in.read();
        System.out.println((readData));
        int readData2 = in.read();
        System.out.println((readData2));
        int readData3 = in.read();
        System.out.println((readData3));
        int readData4 = in.read();
        System.out.println((readData4));
        int readData5 = in.read();
        System.out.println((readData5));
    }
}

循环读取

package com.cskaoyan.bytestream.in;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * @description: 循环读取
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo3 {
    public static void main(String[] args) throws IOException {
        // 方式一
        // 创建输入流对象
        // while true 形式去读取
        FileInputStream in = new FileInputStream("a.txt");
        //readWhile1(in);


        // 方式二 推荐
        // 单字节形式
        //readWhile2(in);
        // 多字节
        int readCount; // 表示读取的字节个数
        byte[] bytes = new byte[1024];
        while ((readCount = in.read(bytes)) != -1) {
            System.out.println(new String(bytes,0,readCount));
        }

        //close
        in.close();
    }

    private static void readWhile2(FileInputStream in) throws IOException {
        int readData;
        while ((readData = in.read()) != -1) {
            System.out.println(((char) readData));
        }
    }

    private static void readWhile1(FileInputStream in) throws IOException {
        while (true) {
            int readData = in.read();

            if (readData == -1) {
                break;
            }
            System.out.println(((char) readData));
        }
    }
}

BufferedInputStream

继承关系

在这里插入图片描述

构造方法

BufferedInputStream(InputStream in) 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。默认缓冲区大小8KB
BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

成员方法:

3个read方法

demo

package com.cskaoyan.bytestream.buff;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @description: 缓冲输入流
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo3 {
    public static void main(String[] args) throws IOException {
        // 创建输入流对象
        BufferedInputStream bi =
                new BufferedInputStream(new FileInputStream("a.txt"));
        // read 读取数据
        //int readData = bi.read();
        //System.out.println(readData);
        byte[] bytes = new byte[1024];
        int readCount = bi.read(bytes);
        System.out.println(new String(bytes,0,readCount));
        // close
        bi.close();
    }
}

利用字节流实现文件复制

思路:

在这里插入图片描述

文本文件

package com.cskaoyan.bytestream.ex;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @description: 文件复制
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo1 {
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象
        FileInputStream in = new FileInputStream("a.txt");
        // 创建字节输出流对象
        FileOutputStream out = new FileOutputStream("D:\\b.txt");
        // 边读边写
        // 单字节 耗时2ms
        long start = System.currentTimeMillis();
        //copy1(in, out);

        //多字节  耗时0ms
        byte[] bytes = new byte[1024];
        int readCount;
        while ((readCount = in.read(bytes)) != -1) {
            // 写数据
            out.write(bytes,0,readCount);
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时"+(end-start)+"ms");
        // close
        in.close();
        out.close();
    }

    private static void copy1(FileInputStream in, FileOutputStream out) throws IOException {
        int readData;
        while ((readData = in.read()) != -1) {
            // 写数据
            out.write(readData);
        }
    }
}

图片文件

package com.cskaoyan.bytestream.ex;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @description: 图片文件复制
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo2 {
    public static void main(String[] args) {
        // 创建输入流对象
        FileInputStream in = null;
        // 创建输出流对象
        FileOutputStream out = null;
        try {
            in = new FileInputStream("D:\\mm.jpg");
            out = new FileOutputStream("copy_mm.jpg");
            // 边读边写
            long start = System.currentTimeMillis();
            // 单字节 耗时127ms

            //copy1(in, out);

            // 多字节
            byte[] bytes = new byte[1024];
            int readCount;
            while ((readCount = in.read(bytes)) != -1) {
                out.write(bytes, 0, readCount);
            }
            long end = System.currentTimeMillis();
            System.out.println("耗时"+(end-start)+"ms");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // close

            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private static void copy1(FileInputStream in, FileOutputStream out) throws IOException {
        int readData;
        while ((readData = in.read()) != -1) {
            out.write(readData);
        }
    }
}

视频复制

package com.cskaoyan.bytestream.ex;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @description: 图片文件复制
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo3 {
    public static void main(String[] args) {
        // 创建输入流对象
        FileInputStream in = null;
        // 创建输出流对象
        FileOutputStream out = null;
        try {
            in = new FileInputStream("D:\\aa.mp4");
            out = new FileOutputStream("copy_aa.mp4");
            // 边读边写
            long start = System.currentTimeMillis();
            // 单字节 耗时10993msms

            //copy1(in, out);

            // 多字节  耗时22ms
            byte[] bytes = new byte[1024];
            int readCount;
            while ((readCount = in.read(bytes)) != -1) {
                out.write(bytes, 0, readCount);
            }
            long end = System.currentTimeMillis();
            System.out.println("耗时"+(end-start)+"ms");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // close

            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private static void copy1(FileInputStream in, FileOutputStream out) throws IOException {
        int readData;
        while ((readData = in.read()) != -1) {
            out.write(readData);
        }
    }
}

问题:

为啥单字节 多字节效率上差别这么大?

举例:

我在京东买了5件商品, 我家离快递站有10公里

按照单字节的方式: 快递小哥一次给我送1个商品 100公里

按照字节数组方式:东哥说了 我们都是兄弟 给每个兄弟配一个五菱 5个商品一下放到车里 只需要1次就能完成配送 20公里.

字符流(重点)

为什么有字符流

  • 用字节流读取英文字符和数字
    • 没有啥问题
  • 用字节流读取中文字符
    • 有可能有问题 (不同的编码表,一个字符组成的单位不同)

编解码

一个字符是如何存储在计算机中的

基于某个编码表 与之对应的编码值(整数值) 存储到计算机中的

编码

基于某个编码表,把字符数据转化为编码值存储到计算机中的 ( 把人看懂的东西转为计算机看懂的东西)

解码

基于某个编码表 ,把计算机中存储的编码值转为字符数据的过程(把计算机看懂的东西转为人看懂的东西)

编码表(了解)

ASCII:美国标准信息交换码。
用一个字节的7位可以表示。0000 0000 - 0111 1111
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。0000 0000 - 1111 1111

GB2312:中国的中文编码表。2个字节表示一个中文字符
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
GB18030:GBK的取代版本
BIG-5码 :通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。

Unicode:国际标准码,融合了多种文字。(理论 能够融合所有国家的文化符号)

UTF-8:可变长度来表示一个字符。
UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容:

它将Unicode编码为00000000-0000007F的字符,用单个字节来表示 0111 1111 = 7F
它将Unicode编码为00000080-000007FF的字符用两个字节表示
它将Unicode编码为00000800-0000FFFF的字符用3字节表示

1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx

utf-16:

jvm使用的编码表,用2个字节来编解码

char : 2 字节,所以用Java的char类型可以表示一个汉字

工作中常用的编码表

  • ASCII
  • ISO8859-1
  • gbk
  • utf-8 3个字节代表一个中文

默认编码表

  • Win 默认gbk编码
  • idea 默认UTF-8

java中的编解码

package com.cskaoyan.charstream.encode;

import java.io.UnsupportedEncodingException;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "什么是快乐星球";
        // 编码
        byte[] utfEncode = s.getBytes();

        // 解码
        // String(byte[] bytes)
        // 过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
        //String s1 = new String(utfEncode);
        //System.out.println(s1);
        // String(byte[] bytes, String charsetName)
        //通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String
        String gbkStr = new String(utfEncode, "Utf-8");
        System.out.println(gbkStr);
    }
}

乱码问题

  • 产生的本质原因 编码与解码的不一致

解决乱码问题

  • 要么使编码一致
  • 要么使解码一致

注意:

操作系统中的ANSI编码其实就是操作系统默认的编码表, win中 GBK

字符流的本质(重点)

在这里插入图片描述

中文编码表:

你 0x001

日文编码表

の 0x001


字符输出流

基类

Writer

写入字符流的抽象类

继承关系

在这里插入图片描述

成员方法

voidwrite(char[] cbuf) 写入字符数组。
abstract voidwrite(char[] cbuf, int off, int len) 写入字符数组的某一部分。
voidwrite(int c) 写入单个字符。
voidwrite(String str) 写入字符串。
voidwrite(String str, int off, int len) 写入字符串的某一部分。

注意:

  • write(int c) 写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略

具体子类

转换流OutputStreamWriter

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

继承关系

在这里插入图片描述

构造方法

OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter。
package com.cskaoyan.charstream.transf;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo1 {
    public static void main(String[] args) throws IOException {
        //使用默认字符集
        OutputStreamWriter out =
                new OutputStreamWriter(new FileOutputStream("a.txt"));
        // 使用指定的字符集
        OutputStreamWriter out2 = 
                new OutputStreamWriter(new FileOutputStream("a.txt"), "GBk");
    }
}

成员方法

5个write方法

package com.cskaoyan.charstream.transf;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 5个write方法
        // 创建字符输出流对象
        OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream("a.txt"));
        // 写数据
        String s = "大郎,来喝药";
        // 字符串转字符数组
        //write2(out, s);

        // 特有的 写字符串
        out.write(s,0,s.length());
        // close
        out.close();
    }

    private static void write2(OutputStreamWriter out, String s) throws IOException {
        char[] chars = s.toCharArray();
        //write1(out, chars);
        out.write(chars);
        out.flush();
    }

    private static void write1(OutputStreamWriter out, char[] chars) throws IOException {
        for (int i = 0; i < chars.length; i++) {
            out.write(chars[i]);
        }
    }
}


字符输入流

基类

Reader

用于读取字符流的抽象类

继承关系

在这里插入图片描述

成员方法

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

注意:

read() 作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1

具体子类

InputStreamReader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

继承关系

在这里插入图片描述

构造方法

InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。

成员方法:

3个read方法

read() 单个字符
read(char[] c ) 字符数组
read(char[] c,int off ,int len) 字符数组的部分
package com.cskaoyan.charstream;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo1 {
    public static void main(String[] args) throws IOException {
        // 创建一个输入流对象
        InputStreamReader in =
                new InputStreamReader(new FileInputStream("a.txt"));
        // read
        //int readData = in.read();
        //System.out.println(((char) readData));
        // 多个字符
        char[] chars = new char[1024];
        // 表示读取到的字符的个数
        int readCount;
        while ((readCount = in.read(chars)) != -1) {
            System.out.println(new String(chars,0,readCount));
        }
        // close
        in.close();
    }
}

作业

1.利用字节流去复制文本文件 图片文件 视频文件 (2种方式 单字节 多字节) 体会一下效率上的差别

public class Demo000 {
    public static void main(String[] args) throws IOException {
        FileInputStream inputStream = new FileInputStream("a.txt");
        FileOutputStream outputStream = new FileOutputStream("b.txt");

        long startTime = System.currentTimeMillis();
        //copyText(inputStream, outputStream);
        long endTime = System.currentTimeMillis();
        //System.out.println("耗时"+ (endTime - startTime) + "ms");

        startTime = System.currentTimeMillis();
        endTime = System.currentTimeMillis();
        copyText2(inputStream, outputStream);
        System.out.println("耗时:" + (endTime - startTime) + "ms");
        inputStream.close();
        outputStream.close();
    }

    private static void copyText(FileInputStream inputStream, FileOutputStream outputStream) throws IOException {

        int readData;
        while((readData = inputStream.read()) != -1){
            outputStream.write(readData);
        }
    }

    public static void copyText2(FileInputStream inputStream, FileOutputStream outputStream) throws IOException{
        int readCount = -1;
        byte[] bytes = new byte[1024];
        while((readCount = inputStream.read(bytes)) != -1){
            outputStream.write(bytes,0,readCount);
        }
    }
}

2.读取一个文件,这个文件中有随机的一些数字字符,统计这些数字有几个偶数,几个奇数,并且追加写入到该文件末尾。
例如:
a.txt文件:
3241256364789629090126581212515
奇数:xx个
偶数:xx个

public class Demo010 {
    public static void main(String[] args) throws IOException {

        File file = new File("a.txt");
        FileInputStream in = null;
        FileOutputStream out = null;
        int readData;
        int num;
        int countEven = 0;
        int countOdd = 0;
        
        try{
            in = new FileInputStream(file);
            out = new FileOutputStream(file,true);
            while((readData = in.read()) != -1){
                num = readData - '0';
                if(num % 2 == 0){
                    countEven++;
                }else {
                    countOdd++;
                }
            }
            out.write("\n".getBytes());
            out.write("偶数个数为:".getBytes());

            // 一开始没反应过来如何把int正确的输入的文件当中,因为你一写就都变成了对应的字符,直接转换成String类型就行了
            out.write((countEven+"").getBytes());
            out.write(System.lineSeparator().getBytes());
            out.write("奇数个数为:".getBytes());
            out.write((countOdd+"").getBytes());

        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(in != null){
                try {
                    in.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            if(out != null){
                try{
                    out.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        System.out.println(countEven);
        System.out.println(countOdd);

        in.close();
        out.close();
    }
}

3.在一个磁盘的文件里保存26个英文小写字母(乱序),将他们读入内存中,进行排序,把排好顺序的数再重新追加写到磁盘的该文件中。

public class Demo011 {
    public static void main(String[] args) throws IOException {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            out = new FileOutputStream("/Users/chelsea-he/Documents/JAVA33th/testFile/letters.txt", true);
            in = new FileInputStream("/Users/chelsea-he/Documents/JAVA33th/testFile/letters.txt");
            byte[] bytes = new byte[26];
            int readcount = in.read(bytes);
            Arrays.sort(bytes);
            out.write("\n".getBytes());
            out.write(bytes);
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(in != null){
                try{
                    in.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            if(out != null){
                try {
                    out.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

4.递归查找指定目录中(包括子目录中),所有的.java文件,
并且,把所有这些找到的java文件,复制(是复制不是移动)到一个指定的目录下

package homework;

import java.io.*;

/**
 * 递归查找指定目录中(包括子目录中),所有的.java文件,
 * 并且,把所有这些找到的java文件,复制(是复制不是移动)到一个指定的目录下
 */

public class Demo100 {
    public static void main(String[] args) throws IOException {
        File fileIn = new File("/Users/chelsea-he/Documents/csJava/homework/dir");
        File fileOut = new File("/Users/chelsea-he/Documents/JAVA33th/testFile2");
        copyJavaFile(fileIn, fileOut);

    }

    public static void copyJavaFile(File fileIn, File fileOut) {
        File[] files = fileIn.listFiles();
        if(files == null && fileIn.getName().endsWith(".java")){
            FileOutputStream out = null;
            FileInputStream in = null;
            try {
                 in = new FileInputStream(fileIn.getAbsolutePath());
                 out = new FileOutputStream(fileOut + "/" + fileIn.getName());
                copy(in, out);
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                if(in != null){
                    try{
                        in.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
                if(out != null){
                    try {
                        out.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }

            return;
        }else if(files == null) return;
        else if(files.length == 0) return;
        for(int i = 0; i < files.length; i++){
            copyJavaFile(new File(files[i].getAbsolutePath()), fileOut);
        }

    }
    public static void copy(FileInputStream inputStream, FileOutputStream outputStream) throws IOException {
        int readCount = -1;
        byte[] bytes = new byte[1024];
        while((readCount = inputStream.read(bytes)) != -1){
            outputStream.write(bytes,0,readCount);
        }
    }
}

字符流

有能力的同学可以先看一下BufferedReader中的readLine方法 可以尝试开始做一下阶段7

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值