小黑子—Java从入门到入土过程:第九章-IO流

news/2024/10/30 9:36:01/

Java零基础入门9.0

  • Java系列第九章- IO流
    • 1. 初识IO流
    • 2. IO流的体系
      • 2.1 字节流
        • 2.1.1 FileOutputStream 字符串输出流
          • 2.1.1 - I 字符串输出流的细节
          • 2.1.1 - II FileOutputStream写数据的3种方式
          • 2.1.1 -III FileOutputStream写数据的两个小问题
        • 2.1.2 FileInputStream 字符串输入流
          • 2.1.2 - I FileInputStream 书写细节
          • 2.1.2 - II FileInputStream 循环读取
      • 2.2 文件拷贝
        • 2.2.1 文件拷贝的弊端
        • 2.2.2 FileInputStream 一次读取多个字节
        • 2.2.3 文件拷贝改写
      • 2.3 字符流
        • 2.3.1 FileReader
          • 2.3.1 - I 空参read
          • 2.3.1 - II 有参read
          • 2.3.1- III 字符输入流原理解析
        • 2.3.2 FileWriter
          • 2.3.2 - I 字符输入流原理解析
      • 2.4 字节流和字符流综合练习
        • 2.4.1 练习一:拷贝文件夹
        • 2.4.2 练习二:加密和解密文件夹
        • 2.4.3 练习三:修改文件夹中的数据
    • 3. IO流中不同JDK版本捕获异常的方式
    • 4.字符集
      • 4.1 计算机储存规则
      • 4.2 ASCII 字符集
      • 4.3 GBK 字符集
      • 4.4 字符集详解
      • 4.5 乱码
      • 4.6 编码和解码的方法
    • 5.IO流体系高级流
      • 5.1 缓冲流
        • 5.1.1 字节缓存流
          • 5.1.1 - I 字节缓存流提高效率原理
        • 5.1.2 字符缓存流
        • 5.1.3 综合练习
          • 5.1.3 - I 练习一:拷贝文件
          • 5.1.3 - II 练习二:拷贝文件
          • 5.1.3 - III 练习三:软件运行次数
      • 5.2 转换流
        • 5.2.1 基本练习
        • 5.2.1 - I 练习1:手动创建GBK文件把中文读取到内存当中
        • 5.2.2 - II 把一段中文按照GBK的形式写到本地文件
        • 5.2.3 - III 将本地文件的GBK转换为UTF-8
        • 5.2.4 - IIIV
      • 5.3 序列流(对象操作输出流)
        • 5.3.1 序列化流(对象操作输出流)
        • 5.3.2 反序列化流(对象操作输出流)
        • 5.3.3 序列化流和反序列化流的细节
        • 5.3.4 序列化流和反序列化流的综合练习:用对象流读写多个对象
      • 5.4 打印流
        • 5.4.1 字节打印流
        • 5.4.2 字符打印流
      • 5.5 解压缩流
      • 5.6 压缩流
        • 5.6.1 压缩单个文件
        • 5.6.2 压缩多个文件
      • 5.7 常用工具包 Commons-io
      • 5.8 Hutool工具包
    • 6. IO流的综合练习
      • 6.1 网络爬虫
        • 6.1.1 爬取姓式
        • 6.1.2 爬取名字
        • 6.1.3 数据处理
      • 6.2 利用糊涂包生成假数据
      • 6.3 带权重的随机数
      • 6.4 登录注册
      • 6.5 配置文件
        • 6.5.1 properties配置文件

Java系列第九章- IO流

1. 初识IO流

IO流:存储和读取数据的解决方案

比如:

在玩游戏的时候,游戏进度的数据是保存在内存当中的
内存中的数据特点就是不能永久化的存储程序,程序停止,数据丢失
这时就需要添加一个存档功能,在存储的过程当中就是把数据保存到文件当中

想实现以上:

  1. 要知道文件在哪里
  2. 要知道如何进行数据传输,包括如何保存数据、如何读取数据
  3. IO流就是为此出现的,其与File文件息息相关

在这里插入图片描述

File类只能对文件本身进行操作,不能读写文件里面储存的数据

IO流做的事情:
IO流:用于读写文件中的数据(可以读写文件,或网络中的数据…)

  1. output:写出数据,把程序中的数据保存到本地文件当中
  2. input:读取数据,把本地数据加载到程序当中

IO流中,谁在读,谁在写?以谁为参照物看读写的方向呢?
以程序(内存)为参照物进行读写

IO流的分类:
在这里插入图片描述
纯文本文件:Windows自带的记事本打开能读懂的文件

小结:
在这里插入图片描述

2. IO流的体系

在这里插入图片描述

2.1 字节流

字节流子类:
在这里插入图片描述
字节流读取中文的时候会出现乱码,文件中不要有中文

2.1.1 FileOutputStream 字符串输出流

FileOutputStream

操作本地文件的字节输出流,可以把程序中的数据写到本地文件中

在这里插入图片描述

import java.io.FileOutputStream;
import java.io.IOException;public class Main {public static void main(String[] args) throws IOException {//1.创建对象//写出 输出流 OutputStream//本地文件 File//异常抛出处理,检查一下当前文件下是否有a.txtFileOutputStream fos = new FileOutputStream("javaprogram1\\a.txt");//写出数据fos.write(97);//3.释放资源fos.close();}}

在这里插入图片描述
图解:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

FileOutputStream的原理

就是创建了一个程序与文件之间的通道
write就是将书写的内容通过通道传输到文件之中
close就是再将这个连接的通道“敲碎”

2.1.1 - I 字符串输出流的细节

1、创建字节输出流对象

  • 细节1:参数是字符串表示的路径或者是File对象都是可以的
  • 细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
  • 细节3:如果文件已经存在,则会清空文件

2、写数据

  • 细节:write方法的参数是整数,但是实际上写道本地文件中的是整数在ASCII上对应的字符
    比如:97 - a100 - d
    如果想要写入97,就57-"9",55 - "7"写两次
    在这里插入图片描述

3、释放资源

  • 每次使用完流之后都要释放资源,就是将文件从内存运行中停止,这样后续就能够继续操作文件了,不然是操作不了的
2.1.1 - II FileOutputStream写数据的3种方式

在这里插入图片描述
1.一次写一个字节数据
在这里插入图片描述
在这里插入图片描述

2.一次写一个字节数组的数据
在这里插入图片描述
原本a.txt文件存在,那么清空时就把文件内容删除掉,然后重新写入想要的内容,所以不会是覆盖效果
在这里插入图片描述

3.一次写一个数组的部分数据
在这里插入图片描述

关于wirte的第三种使用:

  • 参数一:数组
    参数二:起始索引
    参数三:个数
2.1.1 -III FileOutputStream写数据的两个小问题

写数据的两个小问题:想要换行写以及再次写不会清空而是继续写的续写

在这里插入图片描述
换行写:
再次写出一个换行符就可以了

  1. windows:\r\n, \r表示回车,\n表示换行
  2. Linux:\n
  3. Mac:\r

细节:

  • 在Windows操作系统当中,java对回车换行进行了优化,
    虽然完整的是\r\n,但是我们写其中一个\r或者\n就可以
    java也可以实现换行,因为java在底层会补全

建议:

不要省略,还是写全了

续写:
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true:表示打开续写,此时创建对象不会清空文件

public class Main {public static void main(String[] args) throws IOException {//1.创建对象FileOutputStream fos = new FileOutputStream("javaprogram1\\a.txt",true);//写出数据String str = "fklwesnmfgklsdrniogjdlsdkg";byte[] bytes1 = str.getBytes();fos.write(bytes1);String wrap = "\r\n";//换行符byte[] bytes2 = wrap.getBytes();fos.write(bytes2);String str2 = "6666666666";byte[] bytes3 = str2.getBytes();fos.write(bytes3);//3.释放资源fos.close();}}

在这里插入图片描述
小结:
在这里插入图片描述

2.1.2 FileInputStream 字符串输入流

在这里插入图片描述

public class Main {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");int b1 = fis.read();//只能读取一个字符,读不到了就返回-1System.out.println(b1);fis.close();}}

在这里插入图片描述
如果还想读后面的数据,笨方法是一个一个写
在这里插入图片描述

2.1.2 - I FileInputStream 书写细节

1、创建字节输入流对象

细节:如果文件不存在,就直接报错

java为什么会这么设计呢?

  • 输出流:不存在,创建——把数据写到文件当中
  • 输入流:不存在,为什么不直接创建而是报错? 因为创建出来的文件是没有数据的,没有任何意义。

所以java就没有设计这种无意义的逻辑,文件不存在直接报错

程序中最重要的是:数据

2、读取数据

  • 细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字
  • 细节2:读到文件末尾了,read方法返回-1
  • 细节3:如果后面是空格,空格对应的ASCII码是32
  • 细节4:如果后面是-1的,那么读取时先读-,再读1,不会把其作为一个整体
    在这里插入图片描述

3、释放资源

  • 细节:每一次使用完流必须要释放资源
2.1.2 - II FileInputStream 循环读取

在这里插入图片描述

    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");//循环读取int b;while((b=fis.read())!=-1){System.out.print((char)b);}fis.close();}a.txt:
fsdejfkijsadrhgeasdklhgukjsadrhg

在这里插入图片描述
为什么要定义b,我把读取到的数据直接进行判断然后打印不行吗?

比如:

    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");//循环读取while ((fis.read()) != -1) {System.out.println(fis.read());}fis.close();}a.txt:
abcde

在这里插入图片描述
read:表示读取数据,而且每读取一个数据就移动一次指针

  1. 当写了两个read的时候,在开始的时候读取到a进入到循环体当中,又调用了一次fis.read,所以第二次读的时候读到b,也就是98
  2. 再次进行循环,循环中又有一个read,第三次读取读到c,然后到循环体中第四次读取读到d,所以就是100
  3. 再循环,第五次读到e,到循环体中第六次读取,往后指针指向为空,所以返回-1

2.2 文件拷贝

在这里插入图片描述

    public static void main(String[] args) throws IOException {//读取文件FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");//要拷贝到的文件FileOutputStream fos = new FileOutputStream("javaprogram1\\b.txt");//循环读取int b;long beginTime = System.currentTimeMillis();//开始时间while ((b = fis.read()) != -1) {fos.write(b);}//一个释放资源原则:先开的最后关闭fos.close();fis.close();//计算拷贝时间long endTime = System.currentTimeMillis();//结束时间System.out.println("拷贝文件花费了:" + (endTime - beginTime) + "毫秒");}

在这里插入图片描述

2.2.1 文件拷贝的弊端

在这里插入图片描述
为什么会慢呢?
在这里插入图片描述

2.2.2 FileInputStream 一次读取多个字节

在这里插入图片描述

   public static void main(String[] args) throws IOException {//读取文件FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");//设计读取的数组byte[] bytes = new byte[2];//一次读取多个字节数据,具体读多少,跟数组长度有关//返回值:本次读取到了多少给字节数据int len1 = fis.read(bytes);System.out.println(len1);String str1 = new String(bytes);System.out.println(str1);int len2 = fis.read(bytes);System.out.println(len2);String str2 = new String(bytes);System.out.println(str2);int len3 = fis.read(bytes);System.out.println(len3);String str3 = new String(bytes);System.out.println(str3);//为什么是ed?int len4 = fis.read(bytes);System.out.println(len4);//-1String str4 = new String(bytes);System.out.println(str4);//为什么最后还是edfis.close();}

在这里插入图片描述
图解:
第一次读取:

在这里插入图片描述
第二次读取:

  • 在第二次读取到cd的时候,会把原来ab的位置覆盖
    然后把数组里面的内容拿出来变成字符串,所以打印cd
    在这里插入图片描述

第三次读取:

  • 第三次读取的时候,数据只剩下e没有两个,所以只能读到一个e把c覆盖了,而d没有被覆盖
    读了一个数据,所以这次len为1
    因此,在读取的时候打印的就是e和残留的d
    在这里插入图片描述
    如果还要读取第四次,那么不管还是原来空参的read方法,还是现在带有数组的read方法,只要读不到数据方法就返回-1,还要打印的话里面数组数据没有被任何数据覆盖,所以打印的就是ed

解决方案:
字符串中的方法可以把字节数组的一部分变成字符串

    public static void main(String[] args) throws IOException {//读取文件FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");//设计读取的数组byte[] bytes = new byte[2];//一次读取多个字节数据,具体读多少,跟数组长度有关//返回值:本次读取到了多少给字节数据int len1 = fis.read(bytes);System.out.println(len1);String str1 = new String(bytes,0,len1);//表示每次获取数组中从0索引开始,一共要把len1个元素变成字符串System.out.println(str1);int len2 = fis.read(bytes);System.out.println(len2);String str2 = new String(bytes,0,len2);System.out.println(str2);int len3 = fis.read(bytes);System.out.println(len3);String str3 = new String(bytes,0,len3);System.out.println(str3);fis.close();}

在这里插入图片描述

2.2.3 文件拷贝改写

    public static void main(String[] args) throws IOException {//读取文件FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");FileOutputStream fos = new FileOutputStream("javaprogram1\\b.txt");//拷贝int len;long start = System.currentTimeMillis();byte[] bytes = new byte[1024];while((len=fis.read(bytes))!=-1){fos.write(bytes,0,len);System.out.println(len);}//释放资源fos.close();fis.close();long end = System.currentTimeMillis();System.out.println((end - start)+"毫秒");}

在这里插入图片描述

2.3 字符流

在这里插入图片描述

2.3.1 FileReader

2.3.1 - I 空参read

1、创建字符输入流对象
在这里插入图片描述
2、读取数据
在这里插入图片描述

3、释放资源
在这里插入图片描述
read() 细节:

  1. read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
  2. 在读取之后,方法的底层还会进行解码并转成十进制
    最终把这个十进制作为返回值
    这个十进制的数据也表示在字符集上的数字

英文:
文件里面的二进制数据比如 0110 0001
read方法进行读取,解码并转成十进制比如27721

想要看到中文汉字,就是把这些十进制数据,再进行强转就可以了

    public static void main(String[] args) throws IOException {//1.创建对象并关联本地文件FileReader fr = new FileReader("javaprogram1\\a.txt");//2.读取数据//字符流的底层也是字节流,默认也是一个字节,UTF-8一次读三给字节//如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节int ch;while((ch= fr.read())!=-1){System.out.print((char) ch);}//3.释放资源fr.close();}

2.3.1 - II 有参read
    public static void main(String[] args) throws IOException {//1.创建对象并关联本地文件FileReader fr = new FileReader("javaprogram1\\a.txt");char[] chars = new char[2];int len;//read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中//相当于空参的read+强转类型转换while ((len= fr.read(chars))!=-1){//把数组中的数据变成字符串再进行打印System.out.print(new String(chars,0,len));}fr.close();}

在这里插入图片描述

2.3.1- III 字符输入流原理解析

创建输入流对象,底层会创建长度为:8192的字节数组——缓冲区
在这里插入图片描述

在这里插入图片描述

1、在内存中定义未赋值的变量ch

2、第一次读取,判断数据是否可以被读取;如果没有,从文件中读取数据,尽可能装满缓冲区,每次都从缓冲区中读取数据提高效率

3、第一次从缓冲区中读,读的是第一个字节,按照UTF-8的形式进行解码并且转成十进制,再赋值给变量ch,所以其记录的就是97,然后强制打印a

4、第二次读取中,发现剩下的3个字节是中文的,所以一次性会读取3个字节按照UTF-8的形式进行解码,转成十进制25105,再赋值给ch,然后强转成字符再进行打印

5、第三次读取中,发现在内存当中已经没有要读的东西了,然后从文件中读取。但是,文件中也没有剩余的数据了,那么就返回-1,最后把-1赋值给ch

在这里插入图片描述

    public static void main(String[] args) throws IOException {FileReader fr = new FileReader("javaprogram1\\a.txt");fr.read();//把文件中的数据放到缓冲区当中//然后被FileWriter清空了文件FileWriter fw = new FileWriter("javaprogram1\\b.txt");//如果再次使用fr进行读取,会读取到数据吗?//会把缓冲区中的数据全部读取完毕,但是只能读取缓冲区中的数据,文件中剩余数据无法再次读取//因为已经被清空掉了int ch;while((ch=fr.read())!=-1){System.out.print((char)ch);}fw.close();fr.close();}

在这里插入图片描述

2.3.2 FileWriter

FileWriter构造方法:
在这里插入图片描述
FileWriter成员方法:
在这里插入图片描述
FileWriter书写细节:

在这里插入图片描述

    public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("javaprogram1\\a.txt");//写出一个字符fw.write(25105);//我//写出一个字符串fw.write("我是煞笔");//我是煞笔//写出一个字符串数组char[] chars = {'a','b','c','我'};fw.write(chars);//abc我//写出字符数组的一部分fw.write(chars,0,2);//abfw.close();}
2.3.2 - I 字符输入流原理解析

在这里插入图片描述
在写出的时候,它会把所有的数据按照UTF-8进行编码,一个中文变成3个字节,一个英文变成1个字节

跟字节流是不一样的:
字节流是没有缓冲区,是直接写到文件当中的目的地
字符流是有缓冲区的

  • 那么数据是什么时候才能真正地保存到目的地呢?
    在这里插入图片描述

flush和close方法
在这里插入图片描述
区别:

  1. 如果用flush,那么下面还可以继续写数据
  2. 如果用close,那么就直接关流,下面写数据就报错

在这里插入图片描述
当数据超过缓冲区的存储时,比如8193,缓冲区放不下,那么此时缓冲区装不下,其数据就会自动地保存到文件当中

在这里插入图片描述
flush方法相当于把已经放到缓冲区的数据,刷新到本地文件,所以当程序运行完毕之后,上面的数据在文件当中就已经有了,而下面的数据还在缓冲区当中
在这里插入图片描述
如果下面进行关流,那么它在断开链接之前,首先会检查一下缓冲区里面有没有数据。如果有,就会把剩余的所有数据都刷新到本地当中

2.4 字节流和字符流综合练习

在这里插入图片描述

2.4.1 练习一:拷贝文件夹

在这里插入图片描述

public class Main {public static void main(String[] args) throws IOException {//1.创建数据源File src = new File("F:\\aaa\\ccc");//2.创建对象表示目的地File dest =new File("F:\\aaa\\fff");//3.调用方法开始拷贝copydir(src,dest);}public static void copydir(File src,File dest) throws IOException {dest.mkdirs();//如果dest文件夹不存在那么自动创建//1.进入数据源File[] files = src.listFiles();//2.遍历数组if(files!=null){for (File file : files) {if(file.isFile()){//3.判断为文件,就用字节流拷贝//拷贝的时候一定是从文件开始,从文件结束FileInputStream fis = new FileInputStream(file);//假设a.txt//所以拷贝的时候要拷贝到dest文件夹里面FileOutputStream fos = new FileOutputStream(new File(dest,file.getName()));//将其拷贝到dest当作,这个文件也叫了a.txt//利用字节数组进行拷贝,速度快点byte[] bytes = new byte[1024];int len;while((len=fis.read())!=-1){fos.write(bytes,0,len);}fos.close();fis.close();System.out.println("拷贝成功");}else {//4.为文件夹,就递归//第二个参数表示要拷贝文件夹的里面copydir(file,new File(dest,file.getName()));}}}}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4.2 练习二:加密和解密文件夹

在这里插入图片描述
了解^:异或,在二进制下两给相同就false,两个不同就true
在这里插入图片描述
加密:

   public static void main(String[] args) throws IOException {//1.创建对象关联原始文件FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");//2.创建对象关联加密文件FileOutputStream fos = new FileOutputStream("javaprogram1\\b.txt");//3.加密处理int b;while((b=fis.read())!=-1){fos.write(b^2);//数字任意定}//4.释放资源fos.close();fis.close();}

在这里插入图片描述

2.4.3 练习三:修改文件夹中的数据

在这里插入图片描述
1.

public class Main {public static void main(String[] args) throws IOException {//1.读取数据//在读取的时候我需要的是那个整体,而不是直接索引打印,这样的话只能看而不能用//所以要把其拼接到StringBuilder当中FileReader fr = new FileReader("javaprogram1\\a.txt");StringBuilder sb = new StringBuilder();int b;while ((b = fr.read()) != -1) {sb.append((char) b);}fr.close();System.out.println(sb);//2.排序//那就先把StringBuilder里面的数据先变成字符串之后才能调用split方法按照 - 进行切割String sbStr = sb.toString();String[] arrStr = sbStr.split("-");//然后想要把字符串变成int类型的,就循环一遍用Integer.parseInt,然后把转换的数存到数组当中ArrayList<Integer> list = new ArrayList<>();for (String s : arrStr) {int i = Integer.parseInt(s);list.add(i);}Collections.sort(list);System.out.println(list);//3.写出FileWriter fw = new FileWriter("javaprogram1\\b.txt");for (int i = 0; i < list.size(); i++) {if (i == list.size() - 1) {fw.write(list.get(i) + "");} else {fw.write(list.get(i) + "-");}}fw.close();}}

在这里插入图片描述
2.简化版

public class Main {public static void main(String[] args) throws IOException {//1.读取数据//在读取的时候我需要的是那个整体,而不是直接索引打印,这样的话只能看而不能用//所以要把其拼接到StringBuilder当中FileReader fr = new FileReader("javaprogram1\\a.txt");StringBuilder sb = new StringBuilder();int b;while ((b = fr.read()) != -1) {sb.append((char) b);}fr.close();System.out.println(sb);//2.排序Integer[] arr = Arrays.stream(sb.toString().split("-")).map(Integer::parseInt)//方法引用,把字符串转换为整数.sorted()//默认升序排序.toArray(Integer[]::new);//排完后收集起来,收集到int类型的数组当中System.out.println(Arrays.toString(arr));//3.写出FileWriter fw =new FileWriter("javaprogram1\\b.txt");//那么用上面去把数组里面的 ,变成 - 呢?//用repalce方法String s = Arrays.toString(arr).replace(",", "-");//根据数组逗号位置,从索引1开始截取,到数组最后一个位置停止String result = s.substring(1, s.length() - 1);System.out.println(result);fw.write(result);fw.close();}}

3. IO流中不同JDK版本捕获异常的方式

在这里插入图片描述

老版本try…catch下面还有个finally

特点:finally里面的代码一定被执行,除非虚拟机停止(JVM退出),什么意思?

如果在try当中写了一个system.exit(0)或者因为其他原因导致虚拟机都停止了,那么finally里面的代码是执行不到的
在这里插入图片描述
所以就非常适合将释放资源等扫尾代码放到finally之中

麻烦代码:

public class Main {public static void main(String[] args) {//ctrl + alt + t 快捷迅速环绕FileInputStream fis = null;FileOutputStream fos = null;try {//读取文件fis = new FileInputStream("javaprogram1\\a.txt");fos = new FileOutputStream("javaprogram1\\b.txt");//拷贝int len;byte[] bytes = new byte[1024];while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);System.out.println(len);}} catch (IOException e) {e.printStackTrace();}finally {//释放资源//fos fis只能在try里面的局部变量中使用//一般来说可以把其放到大括号外面,但这次不能把整个创建对象都放到外面去//因为这个创建对象的代码它是有编译时异常的,但如果放到外面没有初始化那也会报错//所以放到外面只定义空值,而不会去创建其对象//之后报错的就是close方法,还要对其进行异常处理//再嵌套try……catch方法即可//可如果读入文件的时候没有当前路径,fis记录的值就还是null//在finall用null去调用方法,就肯定会报空指针异常//因此还要写一个非空判断if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}
}

简化代码的接口:
在JDK7的时候java推出了一个简单的接口AutoCloseable
在这里插入图片描述

不同JDK下的书写方式:
JDK7的方法了解就行,JDK7注意:

不能把所有创建对象的代码都写在小括号当中,只有实现了AutoCloseable的类才能在小括号当中创建对象

在这里插入图片描述

JDK7写法:

    public static void main(String[] args) {try (FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");FileOutputStream fos = new FileOutputStream("javaprogram1\\b.txt")){//拷贝int len;byte[] bytes = new byte[1024];while((len=fis.read(bytes))!=-1){fos.write(bytes,0,len);System.out.println(len);}} catch (IOException e) {e.printStackTrace();}//释放资源的代码直接不要}

JDK9写法:

public static void main(String[] args) throws FileNotFoundException {//在外面进行抛出处理FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");FileOutputStream fos = new FileOutputStream("javaprogram1\\b.txt");try (fis ; fos){//拷贝int len;byte[] bytes = new byte[1024];while((len=fis.read(bytes))!=-1){fos.write(bytes,0,len);System.out.println(len);}} catch (IOException e) {e.printStackTrace();}//释放资源的代码直接不要}

4.字符集

4.1 计算机储存规则

在这里插入图片描述
在这里插入图片描述

4.2 ASCII 字符集

首先是熟悉的ASCII表,就是一个字符集,也叫做编码表
128个数据(对于西方的sucker来说足够使用了)
在这里插入图片描述
所以计算机在存储英文的时候一个字节就足以

ASCII编码规则:前面补0,补齐8位
解码直接转,前面补不补零无所谓
在这里插入图片描述
如果是汉字该怎么办?
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4.3 GBK 字符集

英文用一个字节存储,完全兼容ASCII
GBK英文编码规则:不足8位,前面补0
在这里插入图片描述
汉字:两个字节存储
前面的字节叫做高位字节
后面的字节叫做低位字节
高位字节二进制一定以1开头,转成十进制之后是一个负数
汉字编码规则:不需要变动
在这里插入图片描述
在这里插入图片描述

英文与中文的比较:
在这里插入图片描述
在这里插入图片描述
小结:
在这里插入图片描述

4.4 字符集详解

在这里插入图片描述
在这里插入图片描述
本来可以用1个字节表示的,却硬要用2个字节,导致空间过于浪费

所以后面又出了UTF-8编码规则:

在这里插入图片描述
比如英文UTF-8编码时:
在这里插入图片描述
中文UTF-8编码时:
在这里插入图片描述
练习:

UTF-8是一个字符集吗?
不是,UTF-8只是字符集中的一个编码方式

在这里插入图片描述
小结:
在这里插入图片描述

4.5 乱码

原因1:读取数据时未读完整个汉字
原因2:编码和解码时的方式不统一

在这里插入图片描述
2.
在这里插入图片描述
如何不产生乱码?
在这里插入图片描述
在这里插入图片描述

在拷贝的时候,数据没有丢失,在用记事本打开的时候用的字符集和编码表,同数据源是一样的,那是不会出现乱码的

4.6 编码和解码的方法

在这里插入图片描述

    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {//1.编码String str = "ai你哟";byte[] bytes1 = str.getBytes();//-28-67-96表示你  -27-109-97表示哟System.out.println(Arrays.toString(bytes1));//这个GBK方式有编译时异常,抛出即可byte[] bytes2 = str.getBytes("GBK");System.out.println(Arrays.toString(bytes2));//-60 -29组成 你  -45 -76组成哟//2.解码String s1 = new String(bytes1);System.out.println(s1);String s2 = new String(bytes1, "GBK");System.out.println(s2);//当原本用UTF-8的编码却用GBK解码,结果就会出现乱码}

在这里插入图片描述

5.IO流体系高级流

在这里插入图片描述
在这里插入图片描述

5.1 缓冲流

缓冲流一共有四种
在这里插入图片描述

5.1.1 字节缓存流

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第一个构造是关于字节输入流,在它里面会默认有一个8192长度的缓冲区
第二个是除了传递一个字节输入流以为,还能手动设定缓冲区的大小

小练习:
在这里插入图片描述
1.一次操作一个字节

    public static void main(String[] args) throws IOException {BufferedInputStream bis = new BufferedInputStream(new FileInputStream("javaprogram\\a.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("javaprogram\\b.txt"));int b;while((b=bis.read())!=-1){bos.write(b);}//释放资源//为什么只需要关闭缓冲流,而基本流不用关闭了?//源码在关闭缓冲流的时候会自动关闭基本流bos.close();bis.close();}

2.一次读写多个字节

    public static void main(String[] args) throws IOException {BufferedInputStream bis = new BufferedInputStream(new FileInputStream("javaprogram\\a.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("javaprogram\\b.txt"));byte[] arr= new byte[3];int len;while((len=bis.read(arr))!=-1){bos.write(arr,0,len);}//释放资源//为什么只需要关闭缓冲流,而基本流不用关闭了?//源码在关闭缓冲流的时候会自动关闭基本流bos.close();bis.close();}
5.1.1 - I 字节缓存流提高效率原理

在这里插入图片描述
真正把数据写到文件的还是基本流,它会把缓冲区中的数据写道本地文件当中

细节:缓存输入流的缓冲区与缓冲输出流的不是一同个东西

在这里插入图片描述
中间的变量b就是充当一个倒手,在左右这两个缓冲区之间进行来回的倒腾数据,这一段都是在内存当中进行的,运行速度很快
所以倒手的时间可以忽略不记,其真正节约的是读和写时,跟硬盘打交道的时间

在这里插入图片描述
数组的倒手,运行更快

5.1.2 字符缓存流

在这里插入图片描述
字符缓冲流的构造方法:
在这里插入图片描述
字符缓冲流的特有方法:
在这里插入图片描述
方法会自动判断你是上面操作系统

1.单行输入

    public static void main(String[] args) throws IOException {//1.创建字符缓冲流的对象BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\a.txt"));//2.读取数据//细节//readLine方法在读取的时候,一次读一整行,遇到回车换行结束//         但是不会把回车换行读到内存当中String lien1 = br.readLine();System.out.println(lien1);String line2 = br.readLine();System.out.println(line2);br.close();}

在这里插入图片描述
2.全部输入

    public static void main(String[] args) throws IOException {//1.创建字符缓冲流的对象BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\a.txt"));String line;while((line=br.readLine())!=null){System.out.println(line);}}

在这里插入图片描述
3.字符缓冲输出

    public static void main(String[] args) throws IOException {//1.创建字符缓冲流的对象BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\b.txt"));//2.写出bw.write("阿斯蒂芬和");//换行 br.wirte("\r\n")这个方法不够跨平台bw.newLine();//这个方法是BufferedWriter这个类独有的换行bw.close();}

在这里插入图片描述
小结:
在这里插入图片描述

5.1.3 综合练习

5.1.3 - I 练习一:拷贝文件

在这里插入图片描述
方法2和4都是比较快的
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.1.3 - II 练习二:拷贝文件

在这里插入图片描述
1.ArrayList排序

  public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\a.txt"));String line;ArrayList<String> list = new ArrayList<>();while((line=br.readLine())!=null){list.add(line);}br.close();//2.排序//排序规则:按照每一行前面的序号进行排序Collections.sort(list, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//获取o1 o2int i1 = Integer.parseInt(o1.split("\\.")[0]);int i2 = Integer.parseInt(o2.split("\\.")[0]);return i1-i2;//1 2 3 4 5 6..}});//写出BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\b.txt"));for (String s : list) {bw.write(s);bw.newLine();}bw.close();}

在这里插入图片描述
2.TreeMap排序

    public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\a.txt"));String line;//2.排序TreeMap<Integer,String> tm = new TreeMap<>();while((line=br.readLine())!=null){String[] arr = line.split("\\.");//0索引时 表序号  1索引时  表内容tm.put(Integer.parseInt(arr[0]),arr[1]);//要是想看到序号arr[1]变成line就行}System.out.println(tm);br.close();//写出BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\b.txt"));//然后获取treemap的每个键值对对象entrySet,然后遍历Set<Map.Entry<Integer, String>> entries = tm.entrySet();for (Map.Entry<Integer, String> entry : entries) {//entry表示每个键值对,获取其值String value = entry.getValue();bw.write(value);bw.newLine();}bw.close();}

在这里插入图片描述

5.1.3 - III 练习三:软件运行次数

IO流原则:

什么时候用就什么时候创建
什么时候不用再什么时候关闭

在这里插入图片描述

    public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\a.txt"));String line = br.readLine();//0 字符串int count = Integer.parseInt(line);//表示当前软件又运行了一次count++;//1//2.判断if(count<=3){System.out.println("欢迎使用本软件,第"+count+"次免费使用");}else{System.out.println("本软件只能免费使用3次");}//3.把当前自增之后的count写出到文件当中,这样就可以保证每次重新调用的时候count不被刷新BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\a.txt"));bw.write(count+"");//后面加""的目的是让其变为字符串bw.close();}

在这里插入图片描述

5.2 转换流

转换流是字符流和字节流之间的桥梁

在这里插入图片描述
当创建了转换流对象的时候,需要包装一个字节输入流,再包装之后这个字节流它就变成了字符流,就拥有了字符流的特性:

  1. 读取数据不会乱码
  2. 可以根据字符集一次读取多个字节

所以转换流的输入流也叫InputStreamReader
前面的InputStream表示可以把字节流转换成字符流,后面的Reader表示转化流本身是字符流的一员,爹是Reader

同理,转化流的输出流叫OutputStreamReader
在这里插入图片描述
idea默认的字符编码是UTF-8
文件另存的文件编码ANSI就是GBK
在这里插入图片描述

  1. 第一个参数的是需要关联一个字节输入流,使用平台默认的字符编码
  2. 第二个参数除了关联字节输入流以外,还需要指定char set name字符编码,可以小写也可以大写(专业点)
  3. 下面两个同理一样的,一般都是用上面两个

5.2.1 基本练习

5.2.1 - I 练习1:手动创建GBK文件把中文读取到内存当中

在这里插入图片描述

    public static void main(String[] args) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("javaprogram1\\gbkfile.txt"),"GBK");int ch;while((ch=isr.read())!=-1){System.out.print((char)ch);}isr.close();System.out.println("------------------------------");FileReader fr = new FileReader("javaprogram1\\gbkfile.txt", Charset.forName("GBK"));int b;while((b=fr.read())!=-1){System.out.print((char)b);}fr.close();}

在这里插入图片描述

基本流里指定用来表示字符编码的,使用Charset.forName
在这里插入图片描述

5.2.2 - II 把一段中文按照GBK的形式写到本地文件

  • 需求2
    public static void main(String[] args) throws IOException {OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("javaprogram1\\gbkfile.txt"),"GBK");osw.write("李在干神魔");osw.close();//上面这个方法了解一下就行了FileWriter fw = new FileWriter("javaprogram1\\gbkfile.txt");fw.write("李在干神魔");fw.close();}

在这里插入图片描述

5.2.3 - III 将本地文件的GBK转换为UTF-8

  • 需求3
    JDK11以前的方案
    public static void main(String[] args) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("javaprogram1\\gbkfile.txt"),"GBK");OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("javaprogram1\\a.txt"),"UTF-8");int b;while((b= isr.read())!=-1){osw.write(b);}osw.close();isr.close();}

替代方案:
在这里插入图片描述

5.2.4 - IIIV

在这里插入图片描述

    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");//用fis读取肯定会有乱码,所以要把字节流变成字符流InputStreamReader isr = new InputStreamReader(fis);//要读一整行InputStreamReader搞定不了,缓冲流才行BufferedReader br = new BufferedReader(isr);String line;while ((line=br.readLine())!=null){System.out.println(line);}br.close();}

在这里插入图片描述
总结:
在这里插入图片描述

5.3 序列流(对象操作输出流)

5.3.1 序列化流(对象操作输出流)

在这里插入图片描述
区别于直接写对象进文件当中,序列化流写进的数据我们看不懂,要通过反序列化流把数据在这里插入图片描述
在这里插入图片描述

Serializable接口里面是没有抽象方法,这被称为标记型接口。可以理解成:一个物品的合格证

一旦实现了这个接口,那么就表示当前的类就可以被序列化

    public static void main(String[] args) throws IOException {Student stu = new Student("magua",24);//创建序列化流的对象/对象操作输出流ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("javaprogram1\\a.txt"));//写出数据oos.writeObject(stu);oos.close();}

在这里插入图片描述

5.3.2 反序列化流(对象操作输出流)

在这里插入图片描述

    public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("javaprogram1\\a.txt"));Object o = ois.readObject();System.out.println(o);ois.close();}

在这里插入图片描述

如果说一个类实现了一个接口,表明这个类就是可序列化的,那么Java底层会根据其成员变量、静态变量、构造方法、成员方法……计算出里面的序列号,也就是版本号
在这里插入图片描述
在这里插入图片描述
但是此时如果修改了里面javabean里面的代码,就会重新计算其版本号。当用反序列化流读取版本号1到内存时,两个版本号不一样就直接报错

在这里插入图片描述
处理方案:

固定版本号就行了
在这里插入图片描述
static:表示这类的所有对象都共享同一个版本号
final:最终表示版本号不会发生变化
long:版本号的数字比较长,所以不要用int来说
serialLVersionUID:统一的变量名ID

idea系统设置快速设置serialLVersionUID
在这里插入图片描述
设置完成之后,alt+回车 自动生成
在这里插入图片描述

5.3.3 序列化流和反序列化流的细节

对上面反序化流
1.

Student类:
public class Student implements Serializable {private static final long serialVersionUID = 650157805827481085L;private String name;private int age;private String address;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}//toString重写@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +'}';}
}

在这里插入图片描述
2.如果不想某个进行序列化流本地文件,比如address对其保密,那么重信生成JavaBean即可,然后把自动生成的serialVersionUID删掉,在不想序列化流的地方加transient

  • transient:瞬态关键字
    作用:不会把当前属性序列化到本地文件当中
Student类:
public class Student implements Serializable {@Serialprivate static final long serialVersionUID = 650157805827481085L;private String name;private int age;private transient String address;public Student() {}public Student( String name, int age, String address) {this.name = name;this.age = age;this.address = address;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}/*** 获取* @return address*/public String getAddress() {return address;}/*** 设置* @param address*/public void setAddress(String address) {this.address = address;}public String toString() {return "Student{name = " + name + ", age = " + age + ", address = " + address + "}";}
}序列化测试:public static void main(String[] args) throws IOException {Student stu = new Student("magua",25,"guangdoor");ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("javaprogram1\\a.txt"));oos.writeObject(stu);oos.close();}反序列化测试:public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("javaprogram1\\a.txt"));Student o = (Student) ois.readObject();System.out.println(o);ois.close();}

在这里插入图片描述
可见地址无法被序列查询

小结:

在这里插入图片描述

5.3.4 序列化流和反序列化流的综合练习:用对象流读写多个对象

在这里插入图片描述

Stuend类同上,不用transient
序列化测试类:public static void main(String[] args) throws IOException {Student stu1 = new Student("magua",25,"guangdoor");Student stu2 = new Student("zhangsan",26,"xinrimuli");Student stu3 = new Student("lisi",27,"wuhu");ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("javaprogram1\\a.txt"));oos.writeObject(stu1);oos.writeObject(stu2);oos.writeObject(stu3);oos.close();}反序列化测试类:public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("javaprogram1\\a.txt"));Student o1 = (Student) ois.readObject();Student o2 = (Student) ois.readObject();Student o3 = (Student) ois.readObject();System.out.println(o1);System.out.println(o2);System.out.println(o3);ois.close();}

在这里插入图片描述
但是这样的代码真的好吗?
假设序列化对象是别人创建的,序列化了多少个忘记了,就只能到序列化的文件看,但是这是看不懂的。当进行反序列化的时候,就不知道序列化多少个了,总不能一直读读到出异常
在这里插入图片描述
解决方案:
如果要把多个对象序列化到本地文件当中,就一般都会把这些所有对象放到集合里面,再序列化集合就行了

序列化测试:public static void main(String[] args) throws IOException {Student stu1 = new Student("magua",25,"guangdoor");Student stu2 = new Student("zhangsan",26,"xinrimuli");Student stu3 = new Student("lisi",27,"wuhu");ArrayList<Student> list =new ArrayList<>();list.add(stu1);list.add(stu2);list.add(stu3);ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("javaprogram1\\a.txt"));oos.writeObject(list);oos.close();}反序列化测试:public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("javaprogram1\\a.txt"));ArrayList<Student> list = (ArrayList<Student>)ois.readObject();//强转ois读取的对象为ArrayList<Student>for (Student student : list) {System.out.println(student);}ois.close();}

在这里插入图片描述

5.4 打印流

在这里插入图片描述
在这里插入图片描述

5.4.1 字节打印流

构成方法:
在这里插入图片描述
成员方法:
在这里插入图片描述
细说参数:
在这里插入图片描述

  1. 第一个构造我们可以传递字节输出流
  2. 第二个构造除了可传递字节输出流以外,还有boolean类型的变量autoFlush,自动刷新
  3. 第三个构造,有3个参数,第1参数字节输出流的基本流,第2参数自动刷新,第3参数字符串形式的encoding(字符编码)
  4. 第四个构造,与第三个构造类似,不过后面的字符编码是Charset类型的,不能写成字符串
  5. 第五个构造,直接关联文件的路径(字符串类型的)
  6. 下方构造是关联文件路径的,同理一、二、三、四,只不过有个字符编码类型是csn
    public static void main(String[] args) throws IOException, ClassNotFoundException {PrintStream ps = new PrintStream(new FileOutputStream("javaprogram1\\a.txt"),true,"UTF-8");ps.println(97);//写出+自动刷新+自动换行ps.print(true);ps.printf("%s李在赣神魔%s","akm","阿克曼");ps.close();}

在这里插入图片描述

还有,System.out.println就用到了打印流

  1. System是javabean里面已经定义好的一个类
    在这里插入图片描述
  2. out是在System里面的一个静态变量,System.out相当于获取的就是一个打印流的对象,不需要自己来创建,虚拟机会创建。其默认指向控制台
    在这里插入图片描述
    public static void main(String[] args) throws IOException {//获取打印流的对象,此打印流在虚拟机启动的时候,有虚拟机创建,默认指向控制台//特殊的打印流,系统中的标准输出流,不能关闭,在系统中是唯一的PrintStream ps = System.out;//调用打印流中的方法println//写出数据,自动换行,自动刷新ps.println("123");ps.close();//当流关闭了,再也无法打印ps.println("aslkifdhas");System.out.println("12314");}

在这里插入图片描述

5.4.2 字符打印流

在这里插入图片描述

字符流底层有缓冲区,想要自动刷新需要开启true

构造方法:与字节打印流差不多
在这里插入图片描述
成员方法:基本上与字节打印流一模一样
在这里插入图片描述
代码展示:

    public static void main(String[] args) throws IOException, ClassNotFoundException {PrintWriter pw = new PrintWriter(new FileWriter("javaprogram1\\a.txt"),true);pw.println("阿克曼,李在赣神魔");pw.print("曼?不想look可以blue");pw.close();}

在这里插入图片描述
小结:
在这里插入图片描述

5.5 解压缩流

在这里插入图片描述
要想解压,电脑当中首先要有一个压缩包,那么这个压缩包要是zip作为后缀的,不能是其他

在这里插入图片描述
在这里插入图片描述
1.

public class Main {public static void main(String[] args) throws IOException {//1.创建一个File表示要解压的压缩包File src = new File("F:aaa.zip");//2.创建一个File表示解压的目的地File dest = new File("F:\\");//调用方法unzip(src,dest);}public static void unzip(File src , File dest) throws IOException {//解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中//创建一个解压缩流用来读取压缩包中的数据ZipInputStream zip = new ZipInputStream(new FileInputStream(src));//要先获取到压缩包里面的每一个zipentry对象ZipEntry entry = zip.getNextEntry();System.out.println(entry);}}

在这里插入图片描述
2.

public class Main {public static void main(String[] args) throws IOException {//1.创建一个File表示要解压的压缩包File src = new File("F:aaa.zip");//2.创建一个File表示解压的目的地File dest = new File("F:\\");//调用方法unzip(src,dest);}public static void unzip(File src , File dest) throws IOException {//解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中//创建一个解压缩流用来读取压缩包中的数据ZipInputStream zip = new ZipInputStream(new FileInputStream(src));//要先获取到压缩包里面的每一个zipentry对象ZipEntry entry;//保证zip包里面对各个对象文件不为空才循环while((entry=zip.getNextEntry())!=null){System.out.println(entry);//isDirectory()用于判断是不是文件夹if(entry.isDirectory()){//是文件夹,则需要在目的地 dest处创建一个同样的文件夹File file = new File(dest,entry.toString());//但是第二个参数不能写zip entry,没有这个类型,就要把其变成字符串才行file.mkdirs();//如果创建目录,则该函数返回true}else {//为文件:则需要读取到压缩包中的文件,并把他存放到目的地dest文件夹中(按照层级目录进行存放)FileOutputStream fos = new FileOutputStream(new File(dest,entry.toString()));int b;while((b=zip.read())!=-1){//写到目的地fos.write(b);}fos.close();//表示在压缩包中的一个文件处理完了zip.closeEntry();;}}zip.close();}}

在这里插入图片描述

5.6 压缩流

在这里插入图片描述

5.6.1 压缩单个文件

在这里插入图片描述

ublic class Main {public static void main(String[] args) throws IOException {//1.创建表示要压缩的文件File src = new File("F:\\w.txt");//2.创建表示压缩包的位置File dest = new File("F:\\");toZip(src,dest);}public static void toZip(File src, File dest) throws IOException {//创建压缩流关联压缩包//aaa.zip是在F盘的根目录下面的,压缩的时候把w.txt这文件写到压缩包当中,所以就不能只写一个dest(这个只是表示F盘的目录)//要添加子级路径才可以ZipOutputStream zos =new ZipOutputStream(new FileOutputStream(new File(dest,"aaa.zip")));//创建zipentry对象,表示压缩包里面的每一个文件和文件夹ZipEntry entry = new ZipEntry("w.txt");//把ZipEntry放到压缩包当中 putNextEntryzos.putNextEntry(entry);//把src文件中的数据写到压缩包当中FileInputStream fis = new FileInputStream(src);int b;while((b=fis.read())!=-1){zos.write(b);}fis.close();zos.closeEntry();zos.close();}}

5.6.2 压缩多个文件

ZipEntry里面的参数:表示压缩包里面的路径
所以就可以在压缩包里面,创建不同层级的子文件夹

ZipEntry entry = new ZipEntry("bbb\\w.txt");

在这里插入图片描述
代码案例:

public class Main {public static void main(String[] args) throws IOException {//1.创建File对象表示要压缩的文件夹File src = new File("F:\\aaa");//2.创建表示压缩包放在哪里,也就是父级路径File destParent = src.getParentFile();//根目录F://3.创建表示压缩包的路径File dest = new File(destParent, src.getName() + ".zip");//4.创建压缩流关联压缩包ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));//5.获取src里面的每一个文件,变成ZipEntry对象,放到压缩包当中toZip(src,zos,src.getName());//释放zos.close();}//要获取src里面的每一个文件,变成ZipEntry对象,放入导压缩包当中//参数一:数据流//参数二:压缩流//参数三:压缩包内部的路径public static void toZip(File src,ZipOutputStream zos, String name) throws IOException {//1.进入src文件夹File[] files = src.listFiles();//遍历src文件夹数组for (File file : files) {if(file.isFile()){//如果为文件,则变成ZipEntry对象,放入到压缩包当中//但是如果ZipEntry里面放入file.toString的话,里面会有创建根目录也就是D盘在压缩包里面//当不想要根目录,想要数据源本身的文件夹路径开始时,传递src.getName(相当于传递了aaa)+\\+file.getName(文件名)ZipEntry entry = new ZipEntry(src.getName() + "\\" + file.getName());zos.putNextEntry(entry);//读取文件中的数据写到压缩包FileInputStream fis = new FileInputStream(file);int b;while((b=fis.read())!=-1){zos.write(b);}fis.close();zos.closeEntry();}else {//如果为文件夹-则递归toZip(file,zos,name+"\\"+file.getName());}}}
}

在这里插入图片描述

5.7 常用工具包 Commons-io

在这里插入图片描述
在这里插入图片描述
Commons-io使用步骤:
在这里插入图片描述
Commons-io 常见方法:
1.FileUtils类
在这里插入图片描述
2.IOUtils类
在这里插入图片描述

导入Commons-io到idea的lib中在这里插入图片描述
当包可以展开时就说明导入成功

在这里插入图片描述
代码案例:

public class Main {public static void main(String[] args) throws IOException {File src1 = new File("javaprogram1\\a.txt");File dest1 = new File("javaprogram1\\b.txt");FileUtils.copyFile(src1,dest1); //复制文件src的内容到dest文件里面File src2 = new File("F:\\aaa");File dest2 = new File("F:\\bbb");FileUtils.copyDirectory(src2,dest2);//复制aaa文件夹里面的内容到bbb文件夹当中FileUtils.copyDirectoryToDirectory(src2,dest2);//复制aaa整个文件夹到bbb文件夹当中FileUtils.deleteDirectory(src2);//删除文件夹aaaFileUtils.cleanDirectory(dest2);//清空文件夹bbb}
}

5.8 Hutool工具包

在这里插入图片描述
在这里插入图片描述
Hutool官网
Hutool中文使用文档
API帮助文档

代码案例:

public class Main {public static void main(String[] args) throws IOException {//FileUtil类的file:强大之处:可以便捷拼接路径File file = FileUtil.file("F:\\", "aaa", "bbb");System.out.println(file);//FileUtil类的touch:当父级路径不存在时不会报错,会帮助把父级路径一起创建出来File touch = FileUtil.touch(file);System.out.println(touch);//FileUtil类的writeLines:把集合种的数据写到文件中,覆盖ArrayList<String> list1 = new ArrayList<>();list1.add("abc");list1.add("abc");list1.add("abc");File file2 = FileUtil.writeLines(list1, "F:\\a.txt", "UTF-8");System.out.println(file2);//FileUtil类的appendLines:把集合种的数据添加文件中,不覆盖ArrayList<String> list2 = new ArrayList<>();list2.add("was");list2.add("was");list2.add("was");File file3 = FileUtil.writeLines(list2, "F:\\a.txt", "UTF-8");System.out.println(file3);//FileUtil类的readLines:指定字符编码,把文件中的数据读到集合中List<String> list = FileUtil.readLines("F:\\a.txt", "UTF-8");System.out.println(list);}
}

在这里插入图片描述

6. IO流的综合练习

6.1 网络爬虫

6.1.1 爬取姓式

在这里插入图片描述

public class Test1 {public static void main(String[] args) throws IOException {//1.定义变量记录网址String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";String familyNameNet = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d";//2.爬取数据,把王总上所有的数据拼接成一个字符串String boyNameStr = webCrawler(boyNameNet);String girlNameStr = webCrawler(girlNameNet);String familyNameStr = webCrawler(familyNameNet);//3.这些获取了网站的前端代码字符串,还需要通过正则表达式将想要的内容获取出来ArrayList<String> familyNameTempList = getDate(familyNameStr,"(.{4})(,|。)",1);System.out.println(familyNameTempList);}/*作用:根据正则表达式获取字符串中的数据参数一:代表完整的字符串参数二:正则表达式参数三:代表正则表达式的第几组,赵钱孙李。显然要获取在标点符号前面返回值:真正想要的值*/private static ArrayList<String> getDate(String str, String regex,int index) {//1.创建集合存放数据ArrayList<String> list = new ArrayList<>();//2.按照正则表达式的规则获取数据 Pattern.compilePattern pattern = Pattern.compile(regex);//按照pattern的规则,将网址的前端代码字符串转换为姓氏Matcher matcher = pattern.matcher(str);//文本匹配器while(matcher.find()){//用find查找想要的文本元素是否被找到了list.add(matcher.group(index));//将文本匹配器获取正则第index括号里面的东西}return list;}/*作用:从网络中爬取数据,把数据拼接成字符串返回形参:网址返回值:爬取到所有的数据*/public static String webCrawler(String net) throws IOException {//1.定义StringBuilder拼接爬取到的数据StringBuilder sb = new StringBuilder();//2.创建URL对象,这个就表示网址//统一资源标识符(Uniform Resource Identifier ,URL)是采用一种特定语法标识一个资源的字符串。//所标识的资源可能是服务器上的一个文件。Java的URL网络类可以让你通过URL去练级网络服务器并获取资源URL url = new URL(net);//3.链接上这个网址//细节:必须要保证网络畅通,而且这个网址可以链接上URLConnection conn = url.openConnection();//4.读取数据,怎么读取?//一般通过IO流读取,获取输入流读到,但是InputStream是字节流,网站有中文该怎么办?//所以要转换为字符流InputStreamReaderInputStreamReader isr = new InputStreamReader(conn.getInputStream());int b;while((b=isr.read())!=-1){sb.append((char) b);//一定要强转,不然获取到的是数字}isr.close();//5.直接返回StringBuilder的字符串形式return sb.toString();}
}

在这里插入图片描述
接下来的任务就是把集合里面的姓氏分开

6.1.2 爬取名字

AnyRule插件:在字符编码中获取范围,比如说中文的范围
在这里插入图片描述
在这里插入图片描述
女孩的网站名字需要重新找新的规则,不能以空格和回车为标准进行分割
所以要将一整行作为一个元素来进行分割处理
在这里插入图片描述

        ArrayList<String> boyNameTempList = getDate(boyNameStr,"([\\u4E00-\\u9FA5]{2})(、|。)",1);//如果是(..)(、|。),这样获取的名字里面就有数字标点等组合,而要求的是只要有汉字System.out.println(boyNameTempList);ArrayList<String> girlNameTempList = getDate(girlNameStr,"((.. ){4}(..))",0);System.out.println(girlNameTempList);

在这里插入图片描述

6.1.3 数据处理

      //4.处理数据//先处理familyNameTempList姓氏//方案:把每一个姓氏拆开并添加到一个新的集合当中ArrayList<String> familyNameList = new ArrayList<>();for (String str : familyNameTempList) {//此时str为 赵钱孙李 周吴郑王//任务就是将每个姓氏都拆开for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);familyNameList.add(c+"");//以字符串的形式放进集合}}System.out.println(familyNameList);//男生名字//处理方案:去除其中的重复元素ArrayList<String> boyNameList = new ArrayList<>();for (String str : boyNameTempList) {if(!boyNameList.contains(str)){//如果男生名字集合里面没有相同的内容才指向添加boyNameList.add(str);}}System.out.println(boyNameList);//女生的名字//处理方案:把里面读到每一个元素用空格进行切割,就可以得到ArrayList<String> girlNameList = new ArrayList<>();for (String str : girlNameTempList) {String[] arr = str.split(" ");//获取到分割后的女孩名字字符串数组后,再将器每个元素循环出来放到集合当中for (int i = 0; i < arr.length; i++) {girlNameList.add(arr[i]);}}System.out.println(girlNameList);

在这里插入图片描述

生成数据

public class Test1 {public static void main(String[] args) throws IOException {//1.定义变量记录网址String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";String familyNameNet = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d";//2.爬取数据,把王总上所有的数据拼接成一个字符串String boyNameStr = webCrawler(boyNameNet);String girlNameStr = webCrawler(girlNameNet);String familyNameStr = webCrawler(familyNameNet);//3.这些获取了网站的前端代码字符串,还需要通过正则表达式将想要的内容获取出来ArrayList<String> familyNameTempList = getDate(familyNameStr,"(.{4})(,|。)",1);ArrayList<String> boyNameTempList = getDate(boyNameStr,"([\\u4E00-\\u9FA5]{2})(、|。)",1);//如果是(..)(、|。),这样获取的名字里面就有数字标点等组合,而要求的是只要有汉字ArrayList<String> girlNameTempList = getDate(girlNameStr,"((.. ){4}(..))",0);//4.处理数据//先处理familyNameTempList姓氏//方案:把每一个姓氏拆开并添加到一个新的集合当中ArrayList<String> familyNameList = new ArrayList<>();for (String str : familyNameTempList) {//此时str为 赵钱孙李 周吴郑王//任务就是将每个姓氏都拆开for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);familyNameList.add(c+"");//以字符串的形式放进集合}}System.out.println(familyNameList);//男生名字//处理方案:去除其中的重复元素ArrayList<String> boyNameList = new ArrayList<>();for (String str : boyNameTempList) {if(!boyNameList.contains(str)){//如果男生名字集合里面没有相同的内容才指向添加boyNameList.add(str);}}System.out.println(boyNameList);//女生的名字//处理方案:把里面读到每一个元素用空格进行切割,就可以得到ArrayList<String> girlNameList = new ArrayList<>();for (String str : girlNameTempList) {String[] arr = str.split(" ");//获取到分割后的女孩名字字符串数组后,再将器每个元素循环出来放到集合当中for (int i = 0; i < arr.length; i++) {girlNameList.add(arr[i]);}}System.out.println(girlNameList);//5.生成数据//姓名(唯一)-性别-年龄ArrayList<String> list = getInfos(familyNameList, boyNameList, girlNameList, 10, 10);Collections.shuffle(list);System.out.println(list);//6.写出数据,用流BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\a.txt"));for (String str : list) {bw.write(str);bw.newLine();}bw.close();}/*作用:获取男生和女生的信息:比如张三-男-24参数一:装着姓氏的集合参数二:装着男生名字的集合参数三:装着女生名字的集合参数四:表示男生的个数参数五:表示女生的个数*/public static ArrayList<String> getInfos(ArrayList<String> familyNameList,ArrayList<String> boyNameList,ArrayList<String> girlNameList,int boyCount,int girlCount){//1.生成男生不重复的姓名HashSet<String> boyhs = new HashSet<>();while(true){if(boyhs.size()==boyCount){//男生名字足够了break;}//随机通过Collections.shuffle打乱集合的方式进行Collections.shuffle(familyNameList);Collections.shuffle(boyNameList);//拼接boyhs.add(familyNameList.get(0)+boyNameList.get(0));}System.out.println(boyhs);//2.生成女生不重复的姓名HashSet<String> girlhs = new HashSet<>();while(true){if(girlhs.size()==girlCount){//男生名字足够了break;}//随机通过Collections.shuffle打乱集合的方式进行Collections.shuffle(familyNameList);Collections.shuffle(girlNameList);//拼接girlhs.add(familyNameList.get(0)+girlNameList.get(0));}System.out.println(girlhs);//3.调试成名字-男-年龄 添加到集合当中ArrayList<String> list = new ArrayList<>();Random r = new Random();//想要[18~27] - 18 = 0~9//例如:尾部+1 => 9+1=10for (String boyName : boyhs) {int age = r.nextInt(10) + 18;//加上18后就到了18~27的范围选取list.add(boyName+"-男"+"-"+age);}//4.调试成名字-女-年龄 添加到集合当中for (String girlName : boyhs) {int age = r.nextInt(8) + 18;//加上18后就到了16~25的范围选取list.add(girlName+"-女"+"-"+age);}return list;}/*作用:根据正则表达式获取字符串中的数据参数一:代表完整的字符串参数二:正则表达式参数三:代表正则表达式的第几组,赵钱孙李。显然要获取在标点符号前面返回值:真正想要的值*/private static ArrayList<String> getDate(String str, String regex,int index) {//1.创建集合存放数据ArrayList<String> list = new ArrayList<>();//2.按照正则表达式的规则获取数据 Pattern.compilePattern pattern = Pattern.compile(regex);//按照pattern的规则,将网址的前端代码字符串转换为姓氏Matcher matcher = pattern.matcher(str);//文本匹配器while(matcher.find()){//用find查找想要的文本元素是否被找到了list.add(matcher.group(index));//将文本匹配器获取正则第index括号里面的东西}return list;}/*作用:从网络中爬取数据,把数据拼接成字符串返回形参:网址返回值:爬取到所有的数据*/public static String webCrawler(String net) throws IOException {//1.定义StringBuilder拼接爬取到的数据StringBuilder sb = new StringBuilder();//2.创建URL对象,这个就表示网址//统一资源标识符(Uniform Resource Identifier ,URL)是采用一种特定语法标识一个资源的字符串。//所标识的资源可能是服务器上的一个文件。Java的URL网络类可以让你通过URL去练级网络服务器并获取资源URL url = new URL(net);//3.链接上这个网址//细节:必须要保证网络畅通,而且这个网址可以链接上URLConnection conn = url.openConnection();//4.读取数据,怎么读取?//一般通过IO流读取,获取输入流读到,但是InputStream是字节流,网站有中文该怎么办?//所以要转换为字符流InputStreamReaderInputStreamReader isr = new InputStreamReader(conn.getInputStream());int b;while((b=isr.read())!=-1){sb.append((char) b);//一定要强转,不然获取到的是数字}isr.close();//5.直接返回StringBuilder的字符串形式return sb.toString();}
}

在这里插入图片描述

在这里插入图片描述

6.2 利用糊涂包生成假数据

Hutool包爬取
在这里插入图片描述

public class Test1 {public static void main(String[] args) throws IOException {//1.定义变量记录网址String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";String familyNameNet = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d";//爬取利用糊涂包直接获取网址的前端代码String familyNameStr = HttpUtil.get(familyNameNet);String boyNameStr = HttpUtil.get(boyNameNet);String girlNameStr = HttpUtil.get(girlNameNet);//3.利用正则表达式获取数据,把其中符合要求的数据获取出来// ArrayList<String> familyNameTempList = getDate(familyNameStr,"(.{4})(,|。)",1);// ArrayList<String> boyNameTempList = getDate(boyNameStr,"([\\u4E00-\\u9FA5]{2})(、|。)",1);//如果是(..)(、|。),这样获取的名字里面就有数字标点等组合,而要求的是只要有汉字// ArrayList<String> girlNameTempList = getDate(girlNameStr,"((.. ){4}(..))",0);//对照着写,可以写ArrayList集合接收,只不过该方法ReUtil.findAll返回的是List集合,要进行强转成ArrayList,要么就直接用List接收List<String> familyNameTempList = ReUtil.findAll("(.{4})(,|。)", familyNameStr, 1);List<String> boyNameTempList = ReUtil.findAll("([\\u4E00-\\u9FA5]{2})(、|。)", boyNameStr, 1);List<String> girlNameTempList = ReUtil.findAll("((.. ){4}(..))", girlNameStr, 0);System.out.println(familyNameTempList);System.out.println(boyNameTempList);System.out.println(girlNameTempList);//4.处理数据和生成数据还是要自己写的ArrayList<String> familyNameList = new ArrayList<>();for (String str : familyNameTempList) {//此时str为 赵钱孙李 周吴郑王//任务就是将每个姓氏都拆开for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);familyNameList.add(c+"");//以字符串的形式放进集合}}System.out.println(familyNameList);//男生名字//处理方案:去除其中的重复元素ArrayList<String> boyNameList = new ArrayList<>();for (String str : boyNameTempList) {if(!boyNameList.contains(str)){//如果男生名字集合里面没有相同的内容才指向添加boyNameList.add(str);}}System.out.println(boyNameList);//女生的名字//处理方案:把里面读到每一个元素用空格进行切割,就可以得到ArrayList<String> girlNameList = new ArrayList<>();for (String str : girlNameTempList) {String[] arr = str.split(" ");//获取到分割后的女孩名字字符串数组后,再将器每个元素循环出来放到集合当中for (int i = 0; i < arr.length; i++) {girlNameList.add(arr[i]);}}System.out.println(girlNameList);//5.生成数据//姓名(唯一)-性别-年龄ArrayList<String> list = getInfos(familyNameList, boyNameList, girlNameList, 10, 10);Collections.shuffle(list);System.out.println(list);//6.写出数据采用hutool包//细节://糊涂包的相对路径,不是相当于当前项目而言的,而是相对class文件而言的FileUtil.writeLines(list,"names.txt","UTF-8");}/*作用:获取男生和女生的信息:比如张三-男-24参数一:装着姓氏的集合参数二:装着男生名字的集合参数三:装着女生名字的集合参数四:表示男生的个数参数五:表示女生的个数*/public static ArrayList<String> getInfos(ArrayList<String> familyNameList,ArrayList<String> boyNameList,ArrayList<String> girlNameList,int boyCount,int girlCount){//1.生成男生不重复的姓名HashSet<String> boyhs = new HashSet<>();while(true){if(boyhs.size()==boyCount){//男生名字足够了break;}//随机通过Collections.shuffle打乱集合的方式进行Collections.shuffle(familyNameList);Collections.shuffle(boyNameList);//拼接boyhs.add(familyNameList.get(0)+boyNameList.get(0));}System.out.println(boyhs);//2.生成女生不重复的姓名HashSet<String> girlhs = new HashSet<>();while(true){if(girlhs.size()==girlCount){//男生名字足够了break;}//随机通过Collections.shuffle打乱集合的方式进行Collections.shuffle(familyNameList);Collections.shuffle(girlNameList);//拼接girlhs.add(familyNameList.get(0)+girlNameList.get(0));}System.out.println(girlhs);//3.调试成名字-男-年龄 添加到集合当中ArrayList<String> list = new ArrayList<>();Random r = new Random();//想要[18~27] - 18 = 0~9//例如:尾部+1 => 9+1=10for (String boyName : boyhs) {int age = r.nextInt(10) + 18;//加上18后就到了18~27的范围选取list.add(boyName+"-男"+age);}//4.调试成名字-女-年龄 添加到集合当中for (String girlName : boyhs) {int age = r.nextInt(8) + 18;//加上18后就到了16~25的范围选取list.add(girlName+"-女"+age);}return list;}}

在这里插入图片描述

在这里插入图片描述

6.3 带权重的随机数

在这里插入图片描述
了解一下微服务:
在这里插入图片描述
用户在上网的时候不知道该访问哪台服务器,所以在中间就会有一个服务网关,它会根据算法来计算哪个服务器人多了哪个人少了,然后在调整服务器的权重,让用户到人少的地方

梳理过程:
在这里插入图片描述
那么这10%的概率怎么计算呢?
之前学的是往集合里面添加七个1、三个0,再根据1和0的占比情况来决定概率

在这里插入图片描述
但是这样做只适合数据比较少的情况(男生和女生这两个种类),一旦数据比较多,种类一旦多起来了,就不能再这样子表示了

new方案:
去求出每个数据中的权重占比
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Student类:
public class Student {private String name;private String gender;private int age;private double weight;public Student() {}public Student(String name, String gender, int age, double weight) {this.name = name;this.gender = gender;this.age = age;this.weight = weight;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return gender*/public String getGender() {return gender;}/*** 设置* @param gender*/public void setGender(String gender) {this.gender = gender;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}/*** 获取* @return weight*/public double getWeight() {return weight;}/*** 设置* @param weight*/public void setWeight(double weight) {this.weight = weight;}public String toString() {return name+"-"+gender+"-"+age+"-"+weight;}
}测试类:
public class Test1 {public static void main(String[] args) throws IOException {//1.把文件中所有的学生信息读取到内存当中,并封装一个Student对象再放到集合里,才方便统一进行管理ArrayList<Student> StudnetList = new ArrayList<>();BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\names.txt"));String line;while((line=br.readLine())!=null){String[] arr = line.split("-");Student stu = new Student(arr[0], arr[1], Integer.parseInt(arr[2]), Double.parseDouble(arr[3]));StudnetList.add(stu);}br.close();System.out.println(StudnetList);//2.计算总权重double weight = 0;for (Student stu : StudnetList) {weight = weight + stu.getWeight();}System.out.println(weight);//3.计算每个人的权重占比double[] arr = new double[StudnetList.size()];int index = 0;for (Student stu : StudnetList) {arr[index]=stu.getWeight()/weight;index++;}System.out.println(Arrays.toString(arr));//蓝色权重占比部分完成//4.计算权重占比范围for (int i = 1; i < arr.length; i++) {arr[i] = arr[i]+arr[i-1];}System.out.println(Arrays.toString(arr));//5.随机抽取//获取一个0 ~ 1.0之间的随机数double Rnumber = Math.random();//小数参与的计算是不精确的,当时不影响范围的选取System.out.println(Rnumber);//接下来判断number在arr中的位置,就不要一个一个遍历了,不够便捷//二分查找法//Arrays.binarySearch方法返回:-插入点-1 ,这个插入点表示如果在数组当中就应该是什么位置//怎么获取number这个数据在数组当中的插入点位置?//获取插入点 = -方法返回值-1int result = -Arrays.binarySearch(arr,Rnumber)-1;Student stu = StudnetList.get(result);System.out.println(stu);//6.被点到了,概率降低,修改当前学生的权重double w = stu.getWeight() / 2;stu.setWeight(w);//7.把集合中的数据再次写到文件中BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\names.txt"));for (Student student : StudnetList) {bw.write(student.toString());bw.newLine();}bw.close();}
}

在这里插入图片描述
在这里插入图片描述

6.4 登录注册

在这里插入图片描述
在这里插入图片描述

    public static void main(String[] args) throws IOException {//1.读取正确的用户名和密码BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\a.txt"));String line = br.readLine();//一行信息br.close();String[] userInfo = line.split("&");System.out.println(Arrays.toString(userInfo));String[] userList = userInfo[0].split("=");String[] passwordList = userInfo[1].split("=");System.out.println(Arrays.toString(userList));System.out.println(Arrays.toString(passwordList));String rightUsername = userList[1];String rightPassword = passwordList[1];//2.键盘录入输入Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();//3.判断if(rightUsername.equals(username)&&rightPassword.equals(password)){//不能用username == rightUsername && password==rightPassword,因为原本不是统一在栈里面的真实数据System.out.println("登录成功");}else {System.out.println("登录失败");}}

在这里插入图片描述
2.
在这里插入图片描述

在这里插入图片描述
修改以下代码:

public class Main {public static void main(String[] args) throws IOException {//1.读取正确的用户名和密码BufferedReader br = new BufferedReader(new FileReader("javaprogram1\\a.txt"));String line = br.readLine();//一行信息br.close();String[] userInfo = line.split("&");System.out.println(Arrays.toString(userInfo));String[] userList = userInfo[0].split("=");String[] passwordList = userInfo[1].split("=");String[] countList = userInfo[2].split("=");System.out.println(Arrays.toString(userList));System.out.println(Arrays.toString(passwordList));System.out.println(Arrays.toString(countList));String rightUsername = userList[1];String rightPassword = passwordList[1];int count = Integer.parseInt(countList[1]);//2.键盘录入输入Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();//3.判断if(rightUsername.equals(username)&&rightPassword.equals(password)&&count<3){//不能用username == rightUsername && password==rightPassword,因为原本不是统一在栈里面的真实数据System.out.println("登录成功");writeInfo("username"+rightUsername+"&password="+rightPassword+"&count=0");}else {count++;if(count<3){System.out.println("登录失败,还剩下"+(3-count)+"次机会");}else {System.out.println("登录失败,用户账号被锁定");}writeInfo("username"+rightUsername+"&password="+rightPassword+"&count="+count);}}public static void writeInfo(String content) throws IOException {BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\a.txt"));bw.write(content);bw.close();}
}

6.5 配置文件

在这里插入图片描述
在这里插入图片描述

6.5.1 properties配置文件

在这里插入图片描述
properties配置文件都是按照键值对的形式存储的

properties不是一个泛型类,那么在添加数据的时候就可以添加任意的数据类型,但是一般只会添加字符串类型的数据
在这里插入图片描述

properties作为map集合的基本用法:

public class Main {public static void main(String[] args) {//1.创建Properties prop = new Properties();//2.添加数据prop.put("aaa","111");prop.put("bbb","222");prop.put("ccc","333");prop.put("ddd","444");//3.遍历集合Set<Object> keys = prop.keySet();for (Object key : keys) {Object value = prop.get(key);System.out.println(key+"="+value);}System.out.println("==================");Set<Map.Entry<Object, Object>> entries = prop.entrySet();for (Map.Entry<Object, Object> entry : entries) {Object key = entry.getKey();Object value = entry.getValue();System.out.println(key+"="+value);}}
}

在这里插入图片描述

properties与IO流结合的操作:

    public static void main(String[] args) throws IOException {//1.创建Properties prop = new Properties();//2.添加数据prop.put("aaa","111");prop.put("bbb","222");prop.put("ccc","333");prop.put("ddd","444");//麻烦的代码/*BufferedWriter bw = new BufferedWriter(new FileWriter("javaprogram1\\a.txt"));Set<Map.Entry<Object, Object>> entries = prop.entrySet();for (Map.Entry<Object, Object> entry : entries) {Object key = entry.getKey();Object value = entry.getValue();bw.write(key+"="+value);bw.newLine();}bw.close();*///使用properties的特有方法FileOutputStream fos = new FileOutputStream("javaprogram1\\a.txt");prop.store(fos,"test");fos.close();//读取本地properties文件里面的数据FileInputStream fis = new FileInputStream("javaprogram1\\a.txt");prop.load(fis);fis.close();System.out.println(prop);}

在这里插入图片描述


http://www.ppmy.cn/news/70251.html

相关文章

Vue3 实现模态框组件

基于 Vue 3 实现模态框&#xff0c;并且单击遮罩层可关闭模态框 下面是一个基于 Vue 3 实现的模态框&#xff0c;并且点击遮罩层可关闭模态框的示例代码&#xff1a; <template><div class"modal-wrapper" v-show"visible" click.self"clos…

Mysql中select语句的执行流程?

Mysql中select语句的执行流程&#xff1f; 答&#xff1a; SELECT 语句的执行过程为&#xff1a;连接、查询缓存、a词法分析&#xff0c;语法分析&#xff0c;语义分析&#xff0c;构造执行树&#xff0c;生成执行计划、执行器执行计划&#xff0c;下面开始梳理一次完整的查询…

对SRC并发漏洞挖掘的思考

对SRC并发漏洞挖掘的思考 1.burpsuite Turbo插件使用2.并发点赞测试3.并发验证码测试4.某代金券逻辑测试5.有限制的并发验证码绕过6.对于并发漏洞的思考 1.burpsuite Turbo插件使用 Turbo Intruder是一个用于发送大量HTTP请求并会分析其结果的Burp Suite扩展。它旨在补充Burp …

JWT 入门

1.介绍 JSON Web Token&#xff08;JWT&#xff09;是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。该token被设计为紧凑且安全的&#xff0c;特别适用于分布式站点的单点登录&#xff08;SSO…

网络编程 lesson4 linux下的IO模型和特点

目录 阻塞式IO 工作流程 非阻塞式IO 工作流程 设置非阻塞IO方法 fcntl实例 信号驱动IO 工作流程 实例&#xff1a;在LINUX下检听自己鼠标的动作 IO多路复用&#xff08;重点&#xff0c;难点&#xff09; 工作流程 本文核心内容&#xff01;&#xff01;&#xff01…

自动化测试 —— Airtest

最近在做APP自动化过程中&#xff0c;有调研Airtest框架的使用&#xff0c;便初步介绍一下Airtest框架的使用&#xff0c;有兴趣的小伙伴&#xff0c;可以一起探讨学习~ (一&#xff09;背景 Airtest是什么&#xff1f; Airtest是一款基于Python的、跨平台的UI自动化测试框架&…

基于html+css图展示58

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

Agisoft Metashape 红外影像处理

系列文章目录 文章目录 系列文章目录前言一、加载红外影像二、对齐照片三、构建 DEM四、生成 DOM五、温度值可视化前言 Agisoft Metashape 专业版支持处理来自 AscTec(ARA 格式)、WIRIS(TIFF 格式)热成像仪和以 R-JPEG(FLIR 数据)格式保存数据的热成像数据。 在本文中,…