Java基础——IO流(一)

一、IO 流体系结构

1.字节流(万能流)

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

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

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

二、FileOutputStream 字节输出流

构造方法说明

FileOutputStream(String name)

FileOutputStream(String name,boolean append)

输出流关联文件, 文件路径以字符串形式给出,第二个参数是追加写入的开关

FileOutputStream(File file)

FileOutputStream(File file,boolean append)

输出流关联文件, 文件路径以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 (异常类名 对象名) {  异常的处理方式 }finally{

                无论代码有没有异常都会执行这部分代码

}

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

/*
        IO流的异常处理方式: jdk7版本开始
     */
    public static void main(String[] args)  {
        //JDK7版本之后将需要关的流放到try的小括号中会自动关流,不需要写finally 调用close()
        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、付费专栏及课程。

余额充值