Java基础——IO流

一、IO 流体系结构

1.字节流(万能流)

抽象类抽象方法
InputStream字节输入流 FileInputStream
OutputStream字节输出流 FileOutputStream

2.字符流(纯文本文件)

抽象类抽象类的子类
Reader 字符输入流FileReader
Writer 字符输出流FileWriter

二、FileOutputStream 字节输出流

构造方法说明
FileOutputStream(String name)输出流关联文件, 文件路径以字符串形式给出
FileOutputStream(File file)输出流关联文件, 文件路径以File对象形式给出
成员方法说明
void write(int b)写出单个字节
void write(byte[] b)写出一个字节数组
void write(byte[] b, int off, int len)写出字节数组的一部分
public static void main(String[] args) throws IOException {
        // 创建字节输出流对象, 关联文件
        //输出流关联文件, 文件如果不存在: 会自动创建出来
        //如果文件存在: 会清空现有的内容, 然后再进行写入操作
        //第二个参数决定是否可以继续写入
        FileOutputStream fos = new FileOutputStream("D:\\A.txt", true);

        byte[] bys = {97, 98, 99};

        // 写出数据
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(bys);
        fos.write("你好".getBytes());
        fos.write(bys, 1, 2);
}

流对象使用完毕后, 记得调用 close 方法关闭 不然会占用资源 

/*
        流对象使用完毕后需要关闭
     */
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("D:\\B.txt");

        fos.write("abc".getBytes());

        fos.close();
    }

 try (需要调用close方法的对象) {  逻辑代码... } catch (异常类名 对象名) {  异常的处理方式 }

注:try () 中的对象, 需要实现过 AutoCloseable 接口

/*
        IO流的异常处理方式: jdk7版本开始
     */
    public static void main(String[] args)  {

        try(FileOutputStream fos = new FileOutputStream("D:\\B.txt");) {
            fos.write("abc".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

自己写类的时候要重写close()方法

class Demo implements AutoCloseable {
        @Override
        public void close() throws Exception {
            
        }
}

三、FileInputStream 字节输入流

构造方法说明
FileInputStream(String name)输入流关联文件, 文件路径以字符串形式给出
FileInputStream(File file)输入流关联文件, 文件路径以File对象形式给出

注:关联的文件不存在会抛出 FileNotFoundException 异常 ,文件夹的话会拒绝访问

成员方法说明
int read()读取一个字节并返回, 如果到达文件结尾则返回 -1
int read(byte[] b)将读取到字节, 放到传入的数组 返回读取到的有效字节个数 如果到达文件结尾则返回 -1
    /*字节流读取数据 throws IOException可以try(){}catch{}*/
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("D:\\A.txt");

        int i;

        //用达文件结尾则返回 -1的特性标记循环
        while ((i = fis.read()) != -1) {
            System.out.println((char) i);
        }
        
        //结束后关闭流
        fis.close();

    }
    /*
        将读取到的字节, 存入数组容器, 返回读取到的有效字节个数
     */
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("D:\\A.txt");

        // 准备容器, 用于装(字节)
        byte[] bys = new byte[2];

        int len;
        while( (len = fis.read(bys)) != -1 ){

            /*
            public String(byte[] bytes, int offset, int length)
            将字节数组转换为字符串
            参数1 : 字节数组
            参数2 : 起始索引
            参数3 : 转换的个数
            */
            String s = new String(bys, 0, len);
            System.out.print(s);
        }

        fis.close();

    }

案例:将 D:\1.png,拷贝到 E:\ 根目录下

  public static void main(String[] args) throws IOException {
        // 1. 创建输入流对象读取文件
        FileInputStream fis = new FileInputStream("D:\\1.png");
        // 2. 创建输出流对象关联数据目的
        FileOutputStream fos = new FileOutputStream("E:\\1.png");
        // 3. 读写操作,1024是为了方便计算机搬运,提高效率
        byte[] bys = new byte[1024];
        int len;
        while( (len = fis.read(bys)) != -1){
            fos.write(bys, 0, len);
        }
        // 4. 关流释放资源
        fis.close();
        fos.close();
    }

四、字节缓冲流

字节缓冲流在源代码中内置了字节数组,可以提高读写效率

构造方法说明
BufferedInputStream(InputStream in)对传入的字节输入流进行包装
BufferedOutputStream(OutputStream out)对传入的字节输出流进行包装

注:缓冲流不具备读写功能, 它们只是对普通的流对象进行包装 ,真正和文件建立关联的, 还是普         通的流对象 

private static void method() throws IOException {
    // 1. 创建字节缓冲输入流
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\1.ogg"));
    
    // 2. 创建字节缓冲输出流
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\1.ogg"));

    // 3. 读写操作
    int i;
    while ((i = bis.read()) != -1) {
        bos.write(i);
    }

    // 4. 关流
    bis.close();
    bos.close();
 }

 在缓冲流中定义了数组拷贝new byte[8192],所以加快了速度,相对于普通流 加上自定义数组拷贝的效率很多时候是差不多的,缓冲流也可以加上自定义数组一起进行拷贝,效率会更好些,如果加大普通流 加上自定义数组的数组容量也会有相应的速度。

public static void copyFile() throws IOException {

   BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\1.mp4"));
   BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\1.mp4"));

        int len;
        byte[] bys = new byte[1024];
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
        }

        bis.close();
        bos.close();

 }

五、FileReader 字符输入流

用于读取纯文本文件,解决中文乱码问题

构造方法说明
FileReader(String fileName)字符输入流关联文件,路径以字符串形式给出
FileReader(File file)字符输入流关联文件,路径以File对象形式给出
成员方法说明
public int read()读取单个字符
public int read(char[] cbuf)读取一个字符数组, 返回读取到的有效字符个数
private static void method() throws IOException {

     FileReader fr = new FileReader("D:\\A.txt");

     int i;
     while ((i = fr.read()) != -1) {
          System.out.print((char)i);
     }

     fr.close();
 }
public static void main(String[] args) throws IOException {

        FileReader fr = new FileReader("D:\\A.txt");

        char[] chs = new char[1024];

        int len;
        while( (len = fr.read(chs)) != -1 ){
            String s = new String(chs, 0, len);
            System.out.println(s);
        }

        fr.close();

   }

字符编码:字符编码是指一种映射规则 根据这个规则可以将某个字符映射成其他形式的数据以便
                   在计算机中存储和传输 

                   GBK: 每个中文占用2个字节
                             英文字符占用1个字节
                             中文字符占用2个字节
                   Unicode: 每个中文占用3个字节
                                   UTF-8编码规则:用1~4个字节保存
编码和解码:

编码: 字符转字节 (基于String的)

成员方法说明
public byte[] getBytes() 使用平台默认字符编码方式, 对字符串编码
public byte[] getBytes(String charsetName)使用使用字符编码方式, 对字符串编码

解码: 字节转字符

构造方法说明
public String(byte[] bytes)使用平台默认字符编码方式, 对字符串解码
public String(byte[] bytes, String charsetName)使用使用字符编码方式, 对字符串解码
public static void main(String[] args) throws IOException {
        String s = "你好,你好";
        byte[] bytes = s.getBytes();
        System.out.println(Arrays.toString(bytes));

        byte[] gbks = s.getBytes("gbk");
        System.out.println(Arrays.toString(gbks));

        System.out.println("----------------------------");

        byte[] utf8Bytes = {-28, -67, -96, -27, -91, -67, 44, -28, -67, -96, -27, -91, -67};
        byte[] gbkBytes = {-60, -29, -70, -61, 44, -60, -29, -70, -61};

        String s1 = new String(gbkBytes, "GBK");
        System.out.println(s1);
}

 平台默认字符编码 : Unicode - UTF-8的形式
重点记忆: 中文字符, 通常都是由负数的字节进行组成的.
特殊情况: 可能会出现正数, 但是就算有正数, 第一个字节肯定是负数
注意事项: 今后如果出现乱码问题, 大概率是因为编解码方式不一致所导致的.

六、FileWriter 字符输出流

构造方法说明
FileWriter(String fileName)字符输出流关联文件,路径以字符串形式给出
FileWriter(String fileName, boolean append)参数2: 追加写入的开关
FileWriter(File file)字符输出流关联文件,路径以File对象形式给出
FileWriter(File file, boolean append)参数2: 追加写入的开关
成员方法说明
public void write(int c)写出单个字符
public void write(char[] cbuf)写出一个字符数组
public write(char[] cbuf, int off, int len)写出字符数组的一部分
public void write(String str)写出字符串
public void write(String str, int off, int len)写出字符串的一部分

注:字符输出流写出数据,需要调用flush或close方法,数据才会写出

        Flush后可以继续写出 Close 后不能继续写出

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

        FileWriter fw = new FileWriter("D:\\C.txt");

        char[] chs = {'a','b','c'};

        fw.write('a');
        fw.write(chs);
        fw.write(chs, 0, 2);
        fw.write("你好你好~");
        fw.write("哈哈哈哈哈", 0, 2);

        fw.close();


    }

七、案例

1.图片文件加密解密

        加密思路:改变原始文件中的字节,就无法打开了
                          字节 ^ 2
        解密思路:将文件中的字节还原成原始字节即可
                          字节 ^ 2

public static void main(String[] args) throws IOException {
        // 1. 创建字节输入流对象, 关联要加密的图片
        FileInputStream fis = new FileInputStream("D:\\1.jpg");
        // 2. 创建一个容器, 用来存储读取到的字节
        ArrayList<Integer> list = new ArrayList<>();
        // 3. 循环读取文件中的字节, 并存入集合
        int i;
        while((i = fis.read()) != -1){
            list.add(i);
        }
        // 4. 关闭输入流对象
        fis.close();

        // 5. 创建输出流对象, 关联图片文件.
        FileOutputStream fos = new FileOutputStream("D:\\1.jpg");
        // 6. 遍历集合, 从集合中取出字节, 并写出
        for (Integer myByte : list) {
            fos.write(myByte ^ 2);
        }

        // 7. 关闭输出流对象
        fos.close();

    }

 2.统计文件中每一个字符出现的次数,随后展示在控制台
    效果:A(1)B(2)C(3)

public static void main(String[] args) throws IOException {
        // 1. 准备map集合, 用于统计每一种字符出现的次数
        HashMap<Character, Integer> hm = new HashMap<>();
        // 2. 创建字符输入流读取纯文本文件
        FileReader fr = new FileReader("D:\\info.txt");
        // 3. 读取字符
        int i;
        while ((i = fr.read()) != -1) {
            char c = (char) i;
            // 4. 统计这个字符出现的次数
            if (!hm.containsKey(c)) {
                hm.put(c, 1);
            } else {
                hm.put(c, hm.get(c) + 1);
            }
        }
        // 4. 关闭输入流
        fr.close();

        // 5. 准备StringBuilder用于拼接操作
        StringBuilder sb = new StringBuilder();
        hm.forEach(new BiConsumer<Character, Integer>() {
            @Override
            public void accept(Character key, Integer value) {
                sb.append(key).append("(").append(value).append(")");
            }
        });

        System.out.println(sb);
   }

 3.拷贝一个文件夹, 考虑子文件夹,将D:\\test文件夹, 拷贝到E:\\

public static void main(String[] args) throws IOException {
        File src = new File("E:\\test");
        File dest = new File("D:\\");

        if (src.equals(dest)) {
            System.out.println("目标文件夹是源文件夹的子文件夹");
        } else {
            copyDir(src, dest);
        }


    }

    public static void copyDir(File src, File dest) throws IOException {

        File newDir = new File(dest, src.getName());
        newDir.mkdirs();

        // 从数据源中获取数据(File对象)
        File[] files = src.listFiles();
        // 遍历数组, 获取每一个文件或文件夹对象
        for (File file : files) {
            // 判断当前对象是否是文件
            if (file.isFile()) {
                // 是的话直接拷贝
                FileInputStream fis = new FileInputStream(file);
                FileOutputStream fos = new FileOutputStream(new File(newDir, file.getName()));

                int len;
                byte[] bys = new byte[1024];
                while ((len = fis.read(bys)) != -1) {
                    fos.write(bys, 0, len);
                }

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

            } else {
                // 如果是文件夹, 递归调用方法
                copyDir(file, newDir);
            }
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值