Java学习-07 IO学习

Java学习-07 IO学习

I : 即input,代表读取。O:即output,代表输出。

1、File

主要字段:
在这里插入图片描述

示例:

System.out.println(File.pathSeparator);
System.out.println(File.pathSeparatorChar);
System.out.println(File.separator);
System.out.println(File.separatorChar);;

输出:

;
;
\
\

构造方法:
在这里插入图片描述

常用方法:
createNewFile, delete, exists(),getAbsolutePath(),getName(),getParent(),getPath(),isAbsolute(),isDirectory(),isFile(),length(),listFiles(),listFiles(FileFilter filter),listFiles(FilenameFilter filter),mkdir(),renameTo(File dest)
使用FileFilter 和匿名内部类案例:

File[] files2 = f.listFiles(new FileFilter() {
    @Override
    public boolean accept(File pathname) {
        return pathname.getName().endsWith(".jpg");
    }
});

if (files2 != null && files2.length > 0){
    for (File file :
         files2) {
        System.out.println("找到了一个jpg文件:" + file.getAbsolutePath());
    }
}

2、IO流

IO流概述:
可以将这种数据传输操作,看做一种数据的流动 , 按照流动的方向分为输入Input和输出Output

Java中的IO操作主要指的是 java.io包下的一些常用类的使用. 通过这些常用类对数据进行读取(输入Input) 和 写出(输出Output)

IO流的分类:

  • 按照流的方向来分,可以分为:输入流和输出流.
  • 按照流动的数据类型来分,可以分为:字节流和字符流

字节流:

  • 输入流 : InputStrea
  • 输出流 : OutputStream

字符流:

  • 输入流 : Reader
  • 输出流 : Writer

一切皆字节:
计算机中的任何数据(文本,图片,视频,音乐等等)都是以二进制的形式存储的.
在数据传输时 也都是以二进制的形式存储的.
后续学习的任何流 , 在传输时底层都是二进制.

2.1、FileOutputStream

OutputStream本身是输出流的抽象基类,所以使用它的实现类。
FileOutputStream的三种write方法:
在这里插入图片描述

一定要注意使用close方法释放资源。
案例练习:

package java03.com.app.core.section4;

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

public class OutputStreamDemo {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream(".\\a.txt");
        fos.write(65);
        fos.write(66);
        fos.write(67);

        byte[] bytes = {65,66,67};
        fos.write(bytes);

        byte[] bytes1 = "abc".getBytes();
        fos.write(bytes1);

        fos.write(bytes1, 1, 2);
        System.out.println("end");
        fos.close();
    }
}

/*
输出结果:
ABCABCabcbc
*/

需要注意的是,第二次打开这个文档的时候,如果还是同样的命令,那么会先清空文档中的内容,再写入,如果不想清空,想在原来的内容后边追加,可以:
把new FileOutputStream(".\a.txt")写为:new FileOutputStream(".\a.txt",true);第二个参数就是表示是否追加。
注意,不能读取字符串,会导致乱码,因为对于UTF-8编码集,字符有的占两个字节,有的占三个字节。

2.2、FileInputStream

InputStream本身是输出流的抽象基类,所以使用它的实现类。
FileInputStream的三种read方法:
在这里插入图片描述

机翻存在一定问题,这里解释一下:

  • 第一种不传参数的是读取单个字节数据,然后返回读取的字节数据。
  • 第二种会读取最多b.length个字节,返回实际读取的字节数,注意是实际,比如你的b数组的长度为10,但是最后读取的字节不够10个,比如-还剩5个,那么会返回5,而不是10!
  • 第三种从输入流最多读取len个字节的数据,并放入字节数组b中,是从第二个参数off的位置开始读取, 同样返回的是实际读取的长度。

案例演示:
第一种读取方式:

package java03.com.app.core.section4;

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

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 10:37
 * @Modified By:
 */
public class InputStreamDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream(".\\a.txt");
        // a.txt : ABCABCabcbc
        char r1 = (char) fis.read();
        int r2 = fis.read();
        byte r3 = (byte) fis.read();
        System.out.println(r1);
        System.out.println(r2);
        System.out.println(r3);
    }
}

/*
输出:
A
66
67
*/

第二种读取方式:

package java03.com.app.core.section4;

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

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 10:37
 * @Modified By:
 */
public class InputStreamDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream(".\\a.txt");
        // a.txt : ABCABCabcbc
	    byte[] bytes = new byte[5];
        int len = fis.read(bytes);
        System.out.println("读取到的长度为:" + len + ", 字符为:" + new String(bytes,0,len));
        len = fis.read(bytes);
        System.out.println("读取到的长度为:" + len + ", 字符为:" + new String(bytes,0,len));
        len = fis.read(bytes);
        System.out.println("读取到的长度为:" + len + ", 字符为:" + new String(bytes,0,len));
        fis.close();

    }
}

/*
读取到的长度为:5, 字符为:ABCAB
读取到的长度为:5, 字符为:Cabcb
读取到的长度为:1, 字符为:c
*/

第三种读取方式:

package java03.com.app.core.section4;

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

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 10:37
 * @Modified By:
 */
public class InputStreamDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream(".\\a.txt");
        // a.txt : ABCABCabcbc
        byte[] bytes = new byte[5];
        int length = bytes.length;
        // 为了便于观察,把这里的bytes数组元素全部变为 *
        for (int i = 0; i < length; i++) {
            bytes[i] = '*';
        }
        System.out.println("读取前bytes中字符为:" + new String(bytes,0,length));

        int len = fis.read(bytes, 1, 3);
        System.out.println("读取到的长度为:" + len + ", bytes中字符为:" + new String(bytes,0,length));
        len = fis.read(bytes, 1, 3);
        System.out.println("读取到的长度为:" + len + ", bytes中字符为:" + new String(bytes,0,length));
        len = fis.read(bytes, 1, 3);
        System.out.println("读取到的长度为:" + len + ", bytes中字符为:" + new String(bytes,0,length));
        fis.close();

    }
}


/*
读取前bytes中字符为:*****
读取到的长度为:3, bytes中字符为:*ABC*
读取到的长度为:3, bytes中字符为:*ABC*
读取到的长度为:3, bytes中字符为:*abc*
*/

可以看到,第三种方式读取的时候,读取的长度不再是bytes.length,而是第三个参数len,并且在存放的时候,会从第二个参数 off的位置开始往bytes数组中存放。
注意不能写字符串。

2.3、Writer

以下为它提供的write方法,可以看到,除了可以写字节,还可以直接写字符串。
在这里插入图片描述

用法和前面的字节流用法一样,所以就简单的举个栗子,然后主要说一说其他的方法。

abstract void flush() 刷新流。

先说说这个flush,这对应一个缓冲区,为什么要缓冲呢?因为计算机底层是二进制,传递的时候是一个字节一个字节的,但是对于UTF-8中的很多字符,它们都是占好几个字节,所以需要缓冲区先把它们拼起来,然后再放进去,这样就能避免乱码问题,所以你写入的东西,都是先保存在缓冲区的,直到调用flush方法,强制刷新缓冲区,才能把东西放进文档,close会自动调用。
比如如下代码:

package java03.com.app.core.section4;

import java.io.FileWriter;
import java.io.IOException;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 11:21
 * @Modified By:
 */
public class WriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
        writer.write("艳阳天那个风光好,");
        writer.write("红的花是绿的草,");
        writer.write("我乐乐呵呵向前跑,");
        writer.write("踏遍青山人未老。");
        // writer.close();
    }
}

/*
会发现test.txt中什么也没有
*/

如果调用flush方法:

package java03.com.app.core.section4;

import java.io.FileWriter;
import java.io.IOException;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 11:21
 * @Modified By:
 */
public class WriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
        writer.write("艳阳天那个风光好,");
        writer.write("红的花是绿的草,");
        writer.write("我乐乐呵呵向前跑,");
        writer.write("踏遍青山人未老。");
        writer.flush();
        // writer.close();
    }
}

/*
会看到test.txt中:
艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
*/

然后需要说说这个append方法,很有意思。
在这里插入图片描述

先上代码:

package java03.com.app.core.section4;

import java.io.FileWriter;
import java.io.IOException;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 11:21
 * @Modified By:
 */
public class WriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
        writer.append("艳阳天那个风光好,").append("红的花是绿的草.");
        writer.close();
    }
}

/*
test.txt中:
艳阳天那个风光好,红的花是绿的草.
*/

可以看到,这次不用每次writer了,直接在后边.append就可以放入大量文字,因为它返回的是writer对象。
需要注意的是,这个append也只是在本次打开有效,下次再打开这个文件,用append写入的时候,可不是在原文件内容后边追加,是先清空源文件内容,再写入,控制在原内容后边追加的还是创建Writer时的第二个参数true,同上边的字节流。
那么append的第三种是什么意思呢?

package java03.com.app.core.section4;

import java.io.FileWriter;
import java.io.IOException;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 11:21
 * @Modified By:
 */
public class WriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
        writer.append("艳阳天那个风光好,").append("红的花是绿的草.").append("踏遍青山人未老。", 2,4);
        writer.close();
    }
}

/*
test.txt中:
艳阳天那个风光好,红的花是绿的草.青山
*/

原来是把字符串按照start和end进行切片后,把切片得到的子字符串追加,注意是左闭右开的,即不包含右边索引对应的字符。

2.4 Reader

先说基本的Reader方法:三种read
在这里插入图片描述

可以看到,这三种和字节流的基本一样,只是把byte[] 换成了char[] ,所以用法都是一样的。
演示代码:

package java03.com.app.core.section4;

import java.io.FileReader;
import java.io.IOException;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 12:05
 * @Modified By:
 */
public class ReaderDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("src/java03/com/app/core/section4/test.txt");
        // test.txt 内容:艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
        char[] chars = new char[9];
        int read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        fr.close();
    }
}

/*
读取到9个字符,分别是:艳阳天那个风光好,
读取到9个字符,分别是:红的花是绿的草,我
读取到9个字符,分别是:乐乐呵呵向前跑,踏
读取到7个字符,分别是:遍青山人未老。,踏
*/

可以看到最后的输出怎么多了个,踏,这是啥?还记得缓冲区吗?这就是因为读取到的字符,是先保存在缓冲区的,而最后一次读取,要读取9个字符,但是只剩下7个字符了,那怎么办?从缓冲区哪里拿两个过来补上。见图:
在这里插入图片描述

第四次取的时候,只取到了7个字符,所以去上一行读取的拿了两个过来补上,对应黄色框框。

2.5、关于读入时的结束判断

不论是字节读取还是字符读取,读取到最后都会会返回-1, 所以可以根据这个判断是否读取到了最后。
还是拿上一节的代码,再读取一次,会看到最后输出变成了“读取到-1个字符,分别是:遍青山人未老。,踏”,返回了-1,表明没有读取到新的字符,所以没有修改chars数组,因此最后的输出文字和上一行的一样。

package java03.com.app.core.section4;

import java.io.FileReader;
import java.io.IOException;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 12:05
 * @Modified By:
 */
public class ReaderDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("src/java03/com/app/core/section4/test.txt");
        // test.txt 内容:艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
        char[] chars = new char[9];
        int read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        read = fr.read(chars);
        System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
        fr.close();
    }
}

/*
读取到9个字符,分别是:艳阳天那个风光好,
读取到9个字符,分别是:红的花是绿的草,我
读取到9个字符,分别是:乐乐呵呵向前跑,踏
读取到7个字符,分别是:遍青山人未老。,踏
读取到-1个字符,分别是:遍青山人未老。,踏
*/

2.6、转换流

转换流 将字节流转换成字符流,使用了装饰者模式,也可以成为装饰器设计模式。
包括两个:InputStreamReader 和OutputStreamWriter,见名知意,就是把字节流变成字符流。
在这里插入图片描述

可以传递输入流和字符集。
练习代码:

package java03.com.app.core.section4;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 13:30
 * @Modified By:
 */
public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
		// test.txt 内容:艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
        // 将字节输入流转换为字符输入流  参数为要转换的字节流和编码集
        InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
        // 查看一下所使用的编码
        System.out.println(isr.getEncoding());
        while (true){
            int read = fis.read();
            int c = isr.read();
            if(c==-1){
                break;
            }
            System.out.println("转换之前返回的字节数据是:" + read + ",转换为字符是:" + (char) read);
            System.out.println("转换之后返回的字节数据是:" + c + ",转换为字符是:" + (char)c);
            System.out.println("------------------------------------------------------------------");
        }


        fis.close();
    }
}

/*
UTF8
转换之前返回的字节数据是:232,转换为字符是:è
转换之后返回的字节数据是:65533,转换为字符是:�
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:65533,转换为字符是:�
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:38451,转换为字符是:阳
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:22825,转换为字符是:天
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:37027,转换为字符是:那
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:20010,转换为字符是:个
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:39118,转换为字符是:风
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:20809,转换为字符是:光
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:22909,转换为字符是:好
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:65292,转换为字符是:,
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:32418,转换为字符是:红
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:30340,转换为字符是:的
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:33457,转换为字符是:花
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:26159,转换为字符是:是
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:32511,转换为字符是:绿
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:30340,转换为字符是:的
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:33609,转换为字符是:草
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:65292,转换为字符是:,
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:25105,转换为字符是:我
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:20048,转换为字符是:乐
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:20048,转换为字符是:乐
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:21621,转换为字符是:呵
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:21621,转换为字符是:呵
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:21521,转换为字符是:向
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:21069,转换为字符是:前
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:36305,转换为字符是:跑
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:65292,转换为字符是:,
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:36367,转换为字符是:踏
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:36941,转换为字符是:遍
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:38738,转换为字符是:青
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:23665,转换为字符是:山
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:20154,转换为字符是:人
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:26410,转换为字符是:未
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:32769,转换为字符是:老
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:￿
转换之后返回的字节数据是:12290,转换为字符是:。
------------------------------------------------------------------
*/

这个输出这里,有一点问题,前边两个不知道为什么显示错误,但是能看到这个转换前和转换后的对比,后边能正确输出,可能是IDEA的问题。

OutputStreamWriter:
在这里插入图片描述

package java03.com.app.core.section4;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 14:01
 * @Modified By:
 */
public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");

        fos.write('帅');
        // 将字节输入流转换为字符输入流  参数为要转换的字节流和编码集
        OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
        // 查看所使用的编码集
        System.out.println(osw.getEncoding());
        osw.write("帅");


        osw.close();
    }
}

输出:

在这里插入图片描述

2.7、PrintStream和PrintWriter

它们都属于打印流,顾名思义,就是为了输出文本的。它属于处理流,使用处理流的方法:用处理流来包装节点流,程序通过处理流来执行输入输出功能,而节点流与底层的I/O设备、文件交互。
简单代码演示:

package java03.com.app.core.section4;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.io.PrintWriter;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 14:00
 * @Modified By:
 */
public class PrintStreamDemo {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps = new PrintStream("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
        ps.println("面朝大海");
        ps.println("春暖花开");
        /*test.txt:
        面朝大海
        春暖花开
        */

        PrintWriter pw = new PrintWriter("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
        pw.println("王大卖瓜");
        pw.println("老鼠的儿子会打洞");

        ps.flush();
        ps.close();

        pw.flush();
        pw.close();
         /*test.txt:
        王大卖瓜
        老鼠的儿子会打洞
        */
    }
}

 /*
 最终test.txt:
 王大卖瓜
 老鼠的儿子会打洞
 */

我们一直使用的System.out就是PrintStream类
在这里插入图片描述

2.8、BufferedReader

缓冲流,BufferedReader流具有缓冲功能,他可以一次读取一行文本,以换行符为标志,如果没有读到换行符,那么程序会堵塞,等到读到换行符为止。
因为它具有一个readLine方法,可以方便的一次读取一行内容,所以经常把读取文本内容的输入流包装为BufferedReader,用来方便的读取输入流的文本内容。
案例演示:

package java03.com.app.core.section4;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 17:07
 * @Modified By:
 */
public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
        /*
        test.txt内容:
        王大卖瓜
        老鼠的儿子会打洞*/
        BufferedReader br = new BufferedReader(fr);
        String s = br.readLine();
        System.out.println(s);
    }
}

/*
王大卖瓜
*/

2.9、利用IO流进行异常日志收集

程序在运行时总会出现异常,我们不可能一直盯着控制台去看,那么就需要收集这些异常信息。简单练习如下:

package java03.com.app.core.section4;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 17:14
 * @Modified By:
 */
public class ExceptionDemo {
    public static void main(String[] args) throws FileNotFoundException {
        //收集异常信息
        try {
            String s = null;
            s.toString();
        }catch (Exception e){
            PrintWriter pw = new PrintWriter(".\\bug.txt");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            pw.println(format.format(new Date()));
            e.printStackTrace(pw);
            pw.close();
        }
    }
}

/*
可以看到bug.txt中多了几行文字:
2020-08-07 17:19
java.lang.NullPointerException
	at java03.com.app.core.section4.ExceptionDemo.main(ExceptionDemo.java:19)

*/

这个就是简单的演示一下,了解就行,因为有好多封装很好地异常日志类可以使用。

3、简单的加密解密

因为计算机底层保存的都是二进制,所以可以简单地进行加密解密操作,即通过异或,异或的规则为:pqq = p
那么,第一次异或即为加密,第二次即为解密。

package java03.com.app.core.section4;

import java.io.*;
import java.util.Scanner;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 18:40
 * @Modified By:
 */
public class EncryptionDemo {
    public static void main(String[] args) throws IOException {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入文件的绝对路径:");
        String fileName = input.nextLine();

        // 为了得到上一级路径,需要用File读入
        File oldFile = new File(fileName);
        // 对于加密的文件,加上前缀mi-,区分
        File newFile = new File(oldFile.getParent(), "mi-" + oldFile.getName());
        // 为了进行读取写出,需要流
        FileInputStream fis = new FileInputStream(oldFile);
        FileOutputStream fos = new FileOutputStream(newFile);
        // 循环读入进行加密,加密解密原理为 进行^操作。p^4^4 = p, 任何一个数连续异或同一个数两次得到的结果还是它
        System.out.println("正在进行操作,这可能需要一段时间");
        while (true){
            // 每次读取一个字节
            int b = fis.read();
            // 如果返回 -1 表明读取完毕
            if (b == -1) break;
            fos.write(b^4);
        }

        System.out.println("加密/解密完成");
    }
}

/* 第一次我们输入要加密的文件路径
请输入文件的绝对路径:
C:\Users\zlz1314\Desktop\close.png
正在进行操作,这可能需要一段时间
加密/解密完成
*/

/*第二次我们输入加密了的文件的路径进行解密
请输入文件的绝对路径:
C:\Users\zlz1314\Desktop\mi-close.png
正在进行操作,这可能需要一段时间
加密/解密完成
*/

4、Properties

properties文件与properties类,配置文件格式,它是Map类,所以存的是键值对。
put放入键值对,store保存到本地文件,因为需要I/O操作,所以需要创建I/O流。
简单实例:

package java03.com.app.core.section4;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 17:26
 * @Modified By:
 */
public class PropertiesDemo {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
        // 存放键值对
        properties.put("1", "雕虫小技");
        properties.put("2", "竟敢班门弄斧!");
        // 保存为文件, 需要输出流
        FileWriter fw = new FileWriter(".\\a.txt");
        properties.store(fw, "最强法海");
        // 不要忘记关闭流
        fw.close();


    }
}

/* 第一行乱码,使用Unicode解析可以看到就是最强法海四个字
#\u6700\u5F3A\u6CD5\u6D77
#Fri Aug 07 17:32:12 CST 2020
1=雕虫小技
2=竟敢班门弄斧\!
*/

保存完了,怎么读取呢?load方法。

package java03.com.app.core.section4;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 17:26
 * @Modified By:
 */
public class PropertiesDemo {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
       
        FileReader fr = new FileReader(".\\a.txt");
        properties.load(fr);
        System.out.println(properties.getProperty("1"));
        System.out.println(properties.get("2"));


    }
}

/*
雕虫小技
竟敢班门弄斧!
*/

可以看到,这个get和getProperty都是可以的。

5、序列化和反序列化

目前我们能在文件中存取文本了,那能不能存取类呢?所以出现了序列化与反序列化技术,可以把类放进去!这个简直太牛了,所以一经提出,就被广泛使用,但是听老师说,近两年java官方给出的一份报告显示这个技术会引起大量的bug,java官方将推出新技术取代这个技术,所以能不用就不用,万一过两年没了呢。
要实现序列化,必须实现Serializable接口。然后使用的是ObjectInputStream和ObjectOutputStream,通过readObject和writeObject进行读写。
练习代码:

package java03.com.app.core.section4;

import java.io.*;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 17:40
 * @Modified By:
 */
public class SerializableDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //序列化与反序列化
        /*Book b = new Book("金苹果","讲述了种植过程");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(".//b.txtx"));
        oos.writeObject(b);
        oos.close();*/

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(".//b.txtx"));
        Object o = ois.readObject();
        System.out.println(o);
        Book b = (Book)o;
        System.out.println(b.getName());
        System.out.println(b.getInfo());
        ois.close();

    }
    static class Book implements Serializable {
        private String name;
        private String info;

        public Book(String name, String info) {
            this.name = name;
            this.info = info;
        }

        public Book() {
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getInfo() {
            return info;
        }

        public void setInfo(String info) {
            this.info = info;
        }

        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", info='" + info + '\'' +
                    '}';
        }
    }
}

/*
Book{name='金苹果', info='讲述了种植过程'}
金苹果
讲述了种植过程
*/

序列化与反序列化下面被注释的是序列化的代码,因为没有什么输出,文档也是打不开的,所以就不做演示了,可以看到反序列化之后可以正确的输入这个类,而且可以进行类型强转,从而可以访问类的方法。
需要注意的是,如果,这个类的属性中还有其他的类,那么这个类也必须实现Serializable接口。

6、try-catch对于I/O流的支持

try-catch现在支持自动关闭I/O流,在之前的老版本还需要写在finall中,但是有很多不方便,比如,I/O流需要写在try里面才能捕捉,那我之后的代码还要用,怎么办,我有多个流怎么办,等等问题,所以后来推出了1.9版本中的写法,可以写在try外面,然后把引用给try的(),有多个可以用;分开。
注意的是,所有可以被try-catch自动关闭的,必须实现Closeable接口。
案例演示:

package java03.com.app.core.section4;

import java.io.*;

/**
 * @Author: deemoHui
 * @Description:
 * @Date Created in 2020-08-07 18:00
 * @Modified By:
 */
public class TryCatchIODemo {
    public static void main(String[] args) throws IOException {
        //try-with-resources
        /*try {
            FileReader fr = new FileReader(".//a.txt");
            int c = fr.read();
            System.out.println((char)c);
            fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }*/

        //jdk9
        FileReader fr = new FileReader(".//a.txt");
        // a.txt : 哈哈啊哈
        PrintWriter pw = new PrintWriter(".//bug.txt");
        try(fr;pw){
            int c = fr.read();
            System.out.println((char)c);
            pw.println((char)c);

        }catch (IOException e) {
            e.printStackTrace();
        }

        CloseDemo c = new CloseDemo();
        try(c){

        }catch (Exception e){

        }

    }


    static class CloseDemo implements Closeable{
        @Override
        public void close() throws IOException {
            System.out.println("close方法执行。");
        }
    }
}

/*
可以看到bug.txt中多了哈哈啊哈
close方法执行。
*/

猜你喜欢

转载自blog.csdn.net/deemo_hui/article/details/108174202
今日推荐