IO流

IO流的概述

File:表示系统中的文件或者文件夹的路径

  • 获取文件信息(大小,文件名,修改时间)
  • 判断文件的类型
  • 创建文件/文件夹
  • 删除文件/文件夹······

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

一、什么是IO流

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

  • 用于读写文件中的数据(可以读写文件,或网络中的数据···)

  • I: input

    O: output

    流:像水流一样传输数据

二、IO流的分类

1.按照流向分类:

  • 输出流:程序—>文件
  • 输入流:文件—>程序

2.按照操作文件类型分类

image-20230418102655881

纯文本文件:
  • 用Windows自带的记事本打开能读懂的文件

    txt,md,xml,lrc文件等为纯文本文件,word和excel不是

三、IO流体系

image-20230418103935713

联想截图_20230418104409

一、FileOutputStream字节输出流的基本用法

FileOutputStream

  • 操作本地文件的字节输出流,可以把程序中的数据写到本地文件中,是字节流的基本流
一、书写步骤:
1.创建字节输出流对象

​ 细节:

  • 参数是字符串表示的路径或者是File对象都是可以的

  • 如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的

    如:下列代码中的路径写成,myio\\aaa\\a.txt,父级路径中aaa文件夹不存在,就报错

  • 如果文件已经存在,则会清空文件

2.写数据

​ 细节:

  • write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符

    97 —> a

    如想书写:97,需分别write’9’,‘7’

    fos.write(57);
    fos.write(55);
    //显示为97
    
3.释放资源

​ 细节:

  • 每次使用完流之后都要释放资源

    相当于解除资源的占用,关闭通道

示例:
/*
演示:字节输出流FileOutputStream
实现需求:写一段文字到本地文件中(暂时不写中文

实现步骤:
		创建对象
		写出数据
		释放资源
IOException为下列异常的父类
**/
import java.io.FileOutputStream;
public class ByteStreamDemo1{
    public static void main(String[] args)throws IOException{
        //1.创建对象
        //写出 输出流OutputStream
        //本地文件 File
        FileOutputStream fos=new FileOutputStream("myio\\a.txt");//指定文件路径,抛出FileNotFoundException异常
        //2.写出数据
        fos.write(97);//运行后,将a写入指定路径的文件中
        //3.释放资源
        fos.close();
    }
}
二、FileOutputStream原理

插入截图p75,9.00

三、FileOutputStream写数据的3种方式
  • void write(int b)

    一次写一个字节数据

    import java.io.FileOutputStream;
    import java.io.IOException;
    public class ByteStreamDemo3 {
        public static void main(String[] args) throws IOException {
            //1.创建对象
            FileOutputStream fos=new FileOutputStream("myio\\a.txt");
            //2.写出数据
            fos.write(97);//a
            fos.write(98);//b
            //3.释放资源
            fos.close();
    
        }
    }
    
  • void write(byte[ ] b)

    一次写一个字节数组数据

    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class ByteStreamDemo3 {
        public static void main(String[] args) throws IOException {
            //1.创建对象
            FileOutputStream fos=new FileOutputStream("myio\\a.txt");
            //2.写出数据
            byte[] bytes={97,98,99,100,101};
            fos.write(bytes)//abcde
            //3.释放资源
            fos.close();
        }
    }
    
  • void write(byte[ ] b,int off,int len)

    一次写一个字节数组的部分数据

    参数一:数组

    参数二:起始索引

    参数三:个数

    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class ByteStreamDemo3 {
        public static void main(String[] args) throws IOException {
            //1.创建对象
            FileOutputStream fos=new FileOutputStream("myio\\a.txt");
            //2.写出数据
            byte[] bytes={97,98,99,100,101};
                fos.write(bytes,1,2);//bc
            //3.释放资源
            fos.close();
    
        }
    }
    
四、换行和续写
换行写:
  • 再次写出一个换行符就可以了

    windows:\r\n

    Linux:\n

    Mac:\r

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

  • 建议:不要省略,写完整

续写:
  • 如果想要续写,打开续写开关即可

  • 开关位置:创建对象的第二个参数

  • 默认false:表示关闭续写,此时创建对象会清空文件

    手动传递true:表示打开续写,此时创建对象不会清空文件

示例:
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamDemo4 {
    public static void main(String[] args) throws IOException {
        /*
            换行写:
                再次写出一个换行符就可以了
                windows:\r\n
                Linux:\n
                Mac:\r
            细节:在Windows操作系统中,Java对回车进行了优化,
                 虽然完整的是\r\n,但是我们写其中一个\r或者\n,
                 Java也可以实现换行,因为Java在底层会补全
            建议:不要省略,写完整


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

        //1.创建对象
        FileOutputStream fos=new FileOutputStream("myio\\a.txt");
        //2.写出数据
        String str="abc";
        byte[] arr=str.getBytes();
        fos.write(arr);
        
        //再次写出一个换行符
        String wrap="\r\n";
        byte[] bytes1 = wrap.getBytes();
        fos.write(bytes1);


        String str2="666";
        byte[] bytes2 = str2.getBytes();
        fos.write(bytes2);
        //3.释放资源
        fos.close();
        
        //结果:
        //abc
        //666
    }
}
//运行过一次后,a.txt中存入了上述结果,再将创建对象时的代码改为FileOutputStream fos=new FileOutputStream("myio\\a.txt",true);(即打开续写
//a.txt中内容为
//abc
//666abc
//666
//进行了续写,而非清空

二、FileInputStream字节输入流的基本用法

FileInputStream

  • 操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来
一、书写步骤
1.创建字节输入流对象

​ 细节:

  • 如果文件不存在,就直接报错

    创建出的文件没有数据,是没有意义的,故直接报错

2.读数据

​ 细节:

  • 一次读一个字节,读出来的是数据在ASCII上对应的数字

  • 读到文件末尾了,read方法返回-1

    若文件最后为-1,会先读-再读1

3.释放资源

​ 细节:

  • 每次使用完流之后都要释放资源
示例
package com.itheima.mybytestream2;

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

public class ByteStreamDemo1 {
    public static void main(String[] args) throws IOException {
        /*
            演示:字节输入流FileInputStream
            实现需求:读取文件中的数据(暂时不写中文

            实现步骤:
                    创建对象
                    读取数据
                    释放资源
         **/

        //1.创建对象
        FileInputStream fis=new FileInputStream("myio\\a.txt");//预先准备好的a.txt内容为:abc
        //2.读取数据
        int b1 = fis.read();
        System.out.println(b1);//97
        System.out.println((char)b1);//a
        int b2 = fis.read();
        System.out.println(b2);//98
        int b3 = fis.read();
        System.out.println(b3);//99
        int b4 = fis.read();
        System.out.println(b4);//打印-1:读不到数据,返回-1

        //3.释放资源
        fis.close();
    }
}

二、FileInputStream循环读取
package com.itheima.mybytestream2;

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

public class ByteStreamDemo3 {
    public static void main(String[] args) throws IOException {
        /*
            字节输入流循环读取
            预先准备的文件中为:abcde
         **/


        //1.创建对象
        FileInputStream fis=new FileInputStream("myio\\a.txt");

        //2.读取数据
        int b;
        while((b=fis.read())!=-1){
            System.out.println((char)b);
        }
        //3.释放资源
        fis.close();
    }
}


//注意:不可写成以下代码
/*
	while((fis.read())!=-1){
		System.out.println(fis.read());
	}
	打印结果为:98
			  100
			  -1
	read:表示读取数据,而且是读取一个数据就移动一次指针
	while调用一次,打印调用一次,一次循环指针移动两次,导致隔一个打印一次结果
*/
1.文件拷贝的基本代码
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ByteStreamDemo3 {
    public static void main(String[] args) throws IOException {
        /*
        	文件拷贝:
        	把D:\\itheima\\movie.mp4拷贝到当前模块下
        	小文件拷贝
        **/
        
        //1.创建对象
        FileInputStream fis=new FileInputStream("D:\\itheima\\movie.mp4");
        FileOutputStream fos=new FileOutputStream("moio\\copy.mp4");
        //2.拷贝
        //核心思想:边读边写
        int b;
        while((b=fis.read())!=-1){
            fos.write(b);
        }
        //3.释放资源
        //规则:先开的最后关闭
        fos.close();
        fis.close();
    }
}
2.FileInputStream读取的问题

一次读取一个字节,速度慢image-20230418184841985

3.FileInputStream一次读多个字节

public int read(byte[ ] buffer)

  • 一次读一个字节数组数据

    注意:一次读取一个字节数组的数据,每次读取会尽可能把数组装满

    数组长度一般用:1024的整数倍

    如:1024 * 1024 * 5(5 MB)

package com.itheima.mybytestream2;

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

public class ByteStreamDemo5 {
    public static void main(String[] args) throws IOException {
        //1.创建对象
        FileInputStream fis=new FileInputStream("myio\\a.txt");
        //2.读取数据
        byte[] bytes=new byte[2];
        //一次读取多个字节数据,具体都多少,跟数组的长度有关
        //返回值:本次读取到了多少个字节数据
        int len1 = fis.read(bytes);
        System.out.println(len1);//2
        String str1=new String(bytes);
        System.out.println(str1);//ab

        int len2 = fis.read(bytes);
        System.out.println(len2);//2
        String str2=new String(bytes);
        System.out.println(str2);//cd

        int len3 = fis.read(bytes);
        System.out.println(len3);//1
        String str3=new String(bytes);
        System.out.println(str3);//ed

        int len4 = fis.read(bytes);
        System.out.println(len4);//-1
        String str4=new String(bytes);
        System.out.println(str4);//ed

        //3.释放资源
        fis.close();
    }
}

image-20230418222512468

解决:
int len;
    byte[] bytes=new byte[2];
len=fis.read(bytes);
System.out.println(newString(bytes,0,len));//ab

len=fis.read(bytes);
System.out.println(newString(bytes,0,len));//cd

len=fis.read(bytes);
System.out.println(newString(bytes,0,len));//e
4.文件拷贝改写
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ByteStreamDemo3 {
    public static void main(String[] args) throws IOException {
        /*
        	文件拷贝:
        	把D:\\itheima\\movie.mp4拷贝到当前模块下
        	小文件拷贝
        **/
        
        //1.创建对象
        FileInputStream fis=new FileInputStream("D:\\itheima\\movie.mp4");
        FileOutputStream fos=new FileOutputStream("moio\\copy.mp4");
        //2.拷贝
        int len;
        byte[] bytes=new byte[1024*1024*5];
        while((len=fis.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }
        //3.释放资源
        fos.close;
        fis.close();
    }
}

三、IO流中不同JDK版本捕获异常的方式

try···catch异常处理

image-20230418225811388

被finally控制的语句一定会执行,除非JVM退出:

try中写入System.exit(0);或者由于其他原因导致虚拟机都停止了,就无法执行finallly中的代码

快捷键:Ctrl Alt+T,选择tay/catch/ginally,回车

jdk7时,Java推出接口:AutoCloseable

特点特定的情况下,可以自动释放资源

image-20230418230835020

image-20230418231120076

image-20230418231220476

四、字符集详解

字节流读取文件的时候,文件中不要有中文

计算机的存储规则

在计算机中,任意数据都是以二进制的来存储的

计算机中最小的存储单元是一个字节

存储英文,一个字节就足以

一、ASCII字符集(编码表

ASCII编码规则:前面补0,补齐8位

如:存储a—查询ASCII—>97->110 0001—编码—>0110 0001

ASCII解码规则:直接转成十进制

如:读取:0110 0001—解码—>97—查询ASCII—>a(读取到的英文)

二、GBK字符集

image-20230419095634477

1.计算机存储规则(英文(GBK

GBK英文编码规则:前面补0,补齐8位

要求英文用一个字节存储,完全兼容ASCII

如:存储a—查询GBK—>97->110 0001—编码—>0110 0001

2.计算机存储规则(汉字(GBK

GBK汉字编码规则:不需要变动

规则1:汉字两个字节存储

规则2:高位字节二进制一定以1开头,转成十进制之后是一个负数(为了与英文做区分

如:存储:汉 —查询GBK—>47802->10111010 10111010—编码—>10111010 10111010(-70 -70)

如:读取:10111010 10111010 —解码—>47802—查询GBK—>汉(读取到的汉字)

三、Unicode字符集(万国码)

image-20230419095747948

image-20230419101622415

UTF-8编码规则:
  • 用1~4个字节保存

  • ASCII:1个字节

    一个英文占一个字节,二进制第一位是0,转成十进制是正数

  • 简体中文:3个字节

    一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数

    存储:汉 —查询Unicode—>27721->01101100 01001001—UTF-8编码—>11100110 10110001 10001001

image-20230419101943007

五、为什么有乱码

1.读取数据时未读完整个汉字

字节流一次只读一个字节

2.编码和解码时的方式不统一

解决:

  • 不用字节流读取文本文件
  • 编码解码时使用同一个码表,同一个编码方式

扩展:

image-20230419103259710

数据未缺失,记事本采用的编码方式与数据源相同

六、Java中编码和解码的代码实现

image-20230419103543876

package com.itheima.mycharset;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.util.Arrays;

public class CharSetDemo3 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        /*
        java中编码的方法
            public byte[] getBytes()                            使用默认方式进行编码
            public byte[] getBytes(String charsetName)          使用指定方式进行编码
        java中解码的方法
            String(byte[] bytes)                                使用默认方式进行解码
            String(byte[] bytes,String charsetName)             使用指定方式进行解码
     **/

        //1.编码
        String str="ai你哟";
        byte[] bytes1 = str.getBytes();//utf-8
        System.out.println(Arrays.toString(bytes1));//[97, 105, -28, -67, -96, -27, -109, -97]

        byte[] bytes2 = str.getBytes("GBK");
        System.out.println(Arrays.toString(bytes2));//[97, 105, -60, -29, -45, -76]


        //2.解码
        String str2=new String(bytes1);
        System.out.println(str2);//ai你哟

        String str3=new String(bytes1,"GBK");
        System.out.println(str3);//ai浣犲摕,编码方式不同,产生乱码
        //浣(-27  -67)····
        
    }

}

七、字符流

字符流的底层其实就是字节流

字符流=字节流+字符集

使用场景:对于纯文本文件进行读写操作

特点

  • 输入流:

    一次读一个字节,遇到中文时,一次读多个字节

  • 输出流:

    底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中

image-20230419105853945

1.FileReader

1.创建字节输入流对象
构造方法
  • public FileReader(File file)

    创建字符输入流关联本地文件

  • public FileReader(String pathname)

    创建字符输入流关联本地文件

细节
  • 如果文件不存在,就直接报错
2.读取数据
成员方法
  • public int read()

    读取数据,读到末尾返回-1

  • public int read(char[] buffer)

    读取多个数据,读到末尾返回-1

细节
  • 按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个整数

    • 在读取后,方法的底层还会进行解码并转成十进制,最终把这个十进制作为返回值

      这个十进制的数据也表示在字符集上的数字

    • 英文:文件里面二进制数据0110 0001

      ​ read方法进行读取,解码并转成十进制97

      中文:文件里面二进制数据11100110 10110001 10001001

      ​ read方法进行读取,解码并转成27721

      若想看见中文,需将这些十进制数据再次进行强转

  • 读到文件末尾了,read方法返回-1

3.释放资源
成员方法
  • public int close()

    释放资源/关流

示例:

空参的read方法

package com.itheima.mycharstream1;

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

public class CharStreamDemo1 {
    public static void main(String[] args) throws IOException {
        /*
        第一步:创建对象
        - public FileReader(File file)          创建字符输入流关联本地文件

        - public FileReader(String pathname)    创建字符输入流关联本地文件

        第二步:读取数据
        - public int read()                      读取数据,读到末尾返回-1
        - public int read(char[] buffer)         读取多个数据,读到末尾返回-1
        第三步:释放资源
        - public int close()                     释放资源/关流
     **/
        //1.创建对象并关联本地文件
        FileReader fr=new FileReader("myio\\a.txt");
        //2.读取数据read()
        //字符流的底层也是字节流,默认也是一个字节一个字节的读取的
        //如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节
        int ch;
        while((ch=fr.read())!=-1){
            System.out.print((char)ch);//char强转,能看见中文汉字,不强转则看见十进制数据
        }
        //3.释放资源
        fr.close();

    }
}

package com.itheima.mycharstream1;

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

public class CharStreamDemo2 {
    public static void main(String[] args) throws IOException {
         /*
        第一步:创建对象
        - public FileReader(File file)          创建字符输入流关联本地文件

        - public FileReader(String pathname)    创建字符输入流关联本地文件

        第二步:读取数据
        - public int read()                      读取数据,读到末尾返回-1
        - public int read(char[] buffer)         读取多个数据,读到末尾返回-1
        第三步:释放资源
        - public int close()                     释放资源/关流
     **/

        //1.创建对象
        FileReader fr=new FileReader("myio\\a.txt");
        //2.读取数据
        char[] chars=new char[2];
        int len;
        while((len=fr.read(chars))!=-1){
            //把数组中的数据变成字符串再进行打印
            System.out.print(new String(chars,0,len));
        }
        //3.释放资源
        fr.close();
    }
}

2.FileWriter

1.创建字节输出流对象

细节:

  • 参数是字符串表示的路径或者File对象都是可以的
  • 如果文件不存在会创建一个新的文件,但要保证父级路径是存在的
  • 如果文件已经存在,则会清空文件,如果不想清空可以打开续写开关
构造方法

image-20230419205016631

2.写数据

细节:

  • 如果write方法的参数是整数,但是实际上写到本地文件的是整数在字符集上对应的字符

成员方法

image-20230419210819757

3.释放资源

细节:

  • 每次使用完流之后都要释放资源
示例:
package com.itheima.mycharstream1;

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

public class CharStreamDemo3 {
    public static void main(String[] args) throws IOException {
        /*
            第一步:创建对象
                public FileWriter(File file)                            创建字符输出流关联本地文件
                public FileWriter(String pathname)                      创建字符输出流关联本地文件
                public FileWriter(File file,boolean append)             创建字符输出流关联本地文件
                public FileWriter(String pathname,boolean append)       创建字符输出流关联本地文件

            第二步:读取数据
                void write(int c)                           写出一个字符
                void write(String str)                      写出一个字符
                void write(String str,int off,int len)      写出一个字符中的一部分
                void write(char[] chuf)                     写出一个字符数组
                void write(char[] chuf,int off,int len)     写出一个字符数组的一部分

            第三步:释放资源
                public void close()                 释放资源/关流

         **/

        FileWriter fw=new FileWriter("myio\\a.txt");
        //fw.write(25105);
        //fw.write("你好啊");
        char[] chars={'a','b','c','我'};
        fw.write(chars);
        fw.close();
    }
}

3.字符流原理解析

image-20230419225601999

image-20230419225949405

image-20230419225910508

八、字节流和字符流的使用场景

字节流:拷贝任意类型的文件

字符流:读取纯文本文件中的数据

​ 往纯文本文件中写出数据

练习1

拷贝一个文件夹,考虑子文件夹
package com.itheima.mytest;

import java.io.*;

public class Test01 {
    public static void main(String[] args) throws IOException {
        //拷贝一个文件夹,考虑子文件夹

        //1.创建对象表示数据源
        File src=new File("");
        //2.创建对象标表示目的地
        File dest=new File("");

        //3.调用方法开始拷贝
        copydir(src,dest);
    }
/*
    作用:拷贝文件夹
    参数一:数据源
    参数二:目的地

 **/
    private static void copydir(File src,File dest) throws IOException {
        dest.mkdirs();//如果不存在,就创建
        //递归
        //1.进入数据源
        File[] files=src.listFiles();
        //2.遍历数组
        for (File file:files){
            if(file.isFile()){
                //3.判断文件,拷贝
                FileInputStream fis=new FileInputStream(file);
                FileOutputStream fos=new FileOutputStream(new File(dest,file.getName()));
                byte[] bytes=new byte[1024];
                int len;
                while((len=fis.read(bytes))!=-1){
                    fos.write(bytes,0,len);
                }
                fos.close();
                fis.close();
            }else {
                //4.判断文件夹,递归
                copydir(file,new File(dest,file.getName()));
            }
        }
    }
}


练习2

文件加密

为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理。

加密原理:对原始文件中的每一个字节数据进行更改,然后将更改后的数据存储到新的文件中。

解密原理:读取加密之后的文件,按照加密的规则反向操作,变成原始文件

package com.itheima.mytest;

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

public class Test02 {
    public static void main(String[] args) throws IOException {
        /*
            为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理。
            加密原理:
                    对原始文件中的每一个字节数据进行更改,然后将更改后的数据存储到新的文件中。
            解密原理:
                    读取加密之后的文件,按照加密的规则反向操作,变成原始文件.
            ^:异或
                两边相同:false
                两边不同:true
         **/
        //1.创建对象,关联原始文件
        FileInputStream fis=new FileInputStream("myio\\girl.jpg");
        //2.创建对象关联加密文件
        FileOutputStream fos=new FileOutputStream("myio\\ency.jpg");
        //3.加密处理
        int b;
        while((b=fis.read())!=-1){
            fos.write(b^2);
        }
        //4.释放资源
        fos.close();
        fis.close();
    }
}
解密文件仅需将12的文件路径交换即可

练习3

修改文件中的数据

文件中有以下数据;

​ 2-1-9-4-7-8

将文件中的数据进行排序,变成以下的数据:

​ 1-2-4-7-8-9

细节:

  • 文件中的数据不要换行(/r/n
  • bom头(占3个字节

写法1:

package com.itheima.mytest;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;

public class Test03 {
    public static void main(String[] args) throws IOException {
        /*
            文件中有以下数据;

				2-1-9-4-7-8

            将文件中的数据进行排序,变成以下的数据:

				1-2-4-7-8-9
         **/

        //1.读取数据
        FileReader fr=new FileReader("myio\\a.txt");
        StringBuilder sb=new StringBuilder();
        int ch;
        while((ch=fr.read())!=-1){
            sb.append((char)ch);
        }
        fr.close();
        System.out.println(sb);
        //2.排序
        String str=sb.toString();
        String[] arrStr=str.split("-");//2-1-9-4-7-8

        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("myio\\a.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:

package com.itheima.mytest;

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

public class Test04 {
    public static void main(String[] args) throws IOException {
        /*
            文件中有以下数据;

				2-1-9-4-7-8

            将文件中的数据进行排序,变成以下的数据:

				1-2-4-7-8-9
         **/

        //1.读取数据
        FileReader fr = new FileReader("myio\\a.txt");
        StringBuilder sb = new StringBuilder();
        int ch;
        while ((ch = fr.read()) != -1) {
            sb.append((char) ch);
        }
        fr.close();
        System.out.println(sb);

        //2.排序

        Integer[] arr= Arrays.stream(sb.toString()
                .split("-"))
                .map(Integer::parseInt)
                .sorted()
                .toArray(Integer[]::new);
        //3.写出
        FileWriter fw=new FileWriter("myio\\a.txt");
        String s=Arrays.toString(arr).replace(",","-");
        String result = s.substring(1, s.length() - 1);
        fw.write(result);
        fw.close();

    }
}

九、高级流

1.缓冲流

可以显著提高字节流的读写性能

对于字符流提升不明显,对于字符缓冲流而言关键点是两个特洋浦的方法

image-20230420170439330

(1)字节缓冲流

原理:底层自带了长度为8192的缓冲区提高性能

image-20230420170620291

·练习:拷贝文件

利用字节缓冲流拷贝文件

·一次读取一个字节
package com.itheima.mybufferedstream1;

import java.io.*;

public class BufferedStreamDemo1 {
    public static void main(String[] args) throws IOException {
        /*
            需求:
                利用字节缓冲流拷贝文件

            字节缓冲输入流的构造方法:
                   public BufferedInputStream(InputStream is)

            字节缓冲输出流的构造方法:
                   public BufferedOutputStream(OutputStream os)

         **/
        //1.创建缓冲流的对象
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("myio\\a.txt"));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("myio\\copy.txt"));
        //2.循环读取并写到目的地
        int b;
        while((b=bis.read())!=-1){
            bos.write(b);
        }
        //3.释放资源
        bos.close();
        bis.close();
    }
}

·一次读取多个字节
package com.itheima.mybufferedstream1;

import java.io.*;

public class BufferedStreamDemo2 {
    public static void main(String[] args) throws IOException {
        /*
            需求:
                利用字节缓冲流拷贝文件

            字节缓冲输入流的构造方法:
                   public BufferedInputStream(InputStream is)

            字节缓冲输出流的构造方法:
                   public BufferedOutputStream(OutputStream os)

         **/
        //1.创建缓冲流的对象
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("myio\\a.txt"));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("myio\\copy2.txt"));
        //2.拷贝(一次读写多个字节)
        byte[] bytes=new byte[1024];
        int len;
        while((len= bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        //3.释放资源
        bos.close();
        bis.close();
    }
}

·字节缓冲流提高效率的原理:

image-20230420190000304

数组一次倒手多个数据(更快

(2)字符缓冲流

image-20230420190344056

字符缓冲流特有方法:

image-20230420190503919

字符缓冲输入流:
package com.itheima.mybufferedstream1;

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

public class BufferedStreamDemo3 {
    public static void main(String[] args) throws IOException {
        /*
            字符缓冲输入流:
                构造方法:
                    public BufferedReader(Reader r)
                特有方法:
                    public String readLine()    读一整行
         **/
        //1.创建字符缓冲输入流的对象
        BufferedReader br=new BufferedReader(new FileReader("myio\\a.txt"));
        //2.读取数据
        //细节:
        //readLine方法在读取的时候,一次读一整行,遇到回车换行结束
        //          但是他不会把回车换行读到内存当中
        /*String line = br.readLine();
        System.out.println(line);*/
        String line;
        while((line=br.readLine())!=null){
            System.out.println(line);
        }
        //3.释放资源
        br.close();
    }
}

字节缓冲输出流:
package com.itheima.mybufferedstream1;

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

public class BufferedStreamDemo04 {
    public static void main(String[] args) throws IOException {
        /*
            字符缓冲输出流:
                构造方法:
                    public BufferedWriter(Writer r)
                特有方法:
                    public void newLine()    跨平台的换行
         **/
        //1.创建字符缓冲输出流的对象
        BufferedWriter bw=new BufferedWriter(new FileWriter("b.txt",true));//BufferedWriter没有续写功能,该功能在FileWriter中,所以开关需写在其中
        //2.写出数据
        bw.write("你嘴角上扬的样子,百度搜索不到");
        bw.newLine();
        bw.write("以后如果我结婚了,你一定要来哦,没有新娘我会很尴尬");
        bw.newLine();
        //3.释放资源
        bw.close();
    }
}

综合练习01

1.拷贝文件

四种方式拷贝文件,并统计各自用时

  • 字节流的基本流:一次读写一个字节
  • 字节流的基本流:一次读写一个字节数组
  • 字节缓冲流:一次读写一个字节
  • 字节缓冲流:一次读写一个字节数组

2.修改文本顺序

需求:把《出师表》的文章顺序进行恢复到一个新文件中。

写法1:
package com.itheima.mytest;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Test06 {
    public static void main(String[] args) throws IOException {
        /*
            需求:把《出师表》的文章顺序进行恢复到一个新文件中。
         */
        //1.
        BufferedReader br=new BufferedReader(new FileReader("myio\\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>() {
            @Override
            public int compare(String o1, String o2) {
                //获取o1和o2的序号
                int i1 = Integer.parseInt(o1.split("\\.")[0]);
                int i2 = Integer.parseInt(o2.split("\\.")[0]);
                return i1-i2;//按照序号1 2 3 4···进行排列
            }
        });
        //3.写出
        BufferedWriter bw=new BufferedWriter(new FileWriter("myio\\result.txt"));
        for (String str:list) {
            bw.write(str);
            bw.newLine();
        }
        bw.close();
    }
}

写法2:
package com.itheima.mytest;

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

public class Test06Case02 {
    public static void main(String[] args) throws IOException {
        /*
            需求:把《出师表》的文章顺序进行恢复到一个新文件中。
         */
        //1.
        BufferedReader br=new BufferedReader(new FileReader("myio\\a.txt"));
        String line;
        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能够看见序号
        }
        br.close();

        //2.写出数据
        BufferedWriter bw=new BufferedWriter(new FileWriter("myio\\result2.txt"));
        Set<Map.Entry<Integer, String>> entries = tm.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            String value = entry.getValue();
            bw.write(value);
            bw.newLine();
        }
        bw.close();
    }
}

3.软件运行次数

实现一个验证程序运行次数的小程序,要求如下:
1.当程序运行超过3次时给出提示:本软件只能免费使用3次,欢迎您注册会员后继续使用~
2.程序运行演示如下:
第一次运行控制台输出:欢迎使用本软件,第1次使用免费第二次运行控制台输出:欢迎使用本软件,第2次使用免费第三次运行控制台输出:欢迎使用本软件,第3次使用免费~
第四次及之后运行控制台输出:本软件只能免费使用3次,欢迎您注册会员后继续使用~

package com.itheima.mytest;

import java.io.*;

public class Test07 {
    public static void main(String[] args) throws IOException {
        /*
            实现一个验证程序运行次数的小程序,要求如下:
            1.当程序运行超过3次时给出提示:本软件只能免费使用3次,欢迎您注册会员后继续使用~
            2.程序运行演示如下:
                第一次运行控制台输出:欢迎使用本软件,第1次使用免费~
                第二次运行控制台输出:欢迎使用本软件,第2次使用免费~
                第三次运行控制台输出:欢迎使用本软件,第3次使用免费~
                第四次及之后运行控制台输出:本软件只能免费使用3次,欢迎您注册会员后继续使用~
         */

        //1.把文件中的数字读取到内存中
        //原则:
        //IO:随用随创建
        //  什么时候不用什么时候关闭
        BufferedReader br=new BufferedReader(new FileReader("myio\\count.txt"));
        String line=br.readLine();
        br.close();
        int count = Integer.parseInt(line);
        //表示当前软件又运行了一次
        count++;

        //2.判断
        //<=3正常运行
        //>3不能运行
        if(count<=3){
            System.out.println("欢迎使用本软件,第"+count+"次使用免费~");
        }else{
            System.out.println("本软件只能免费使用3次,欢迎您注册会员后继续使用~");
        }
        //3.把当前自增后的count写出到文件当中
        BufferedWriter bw=new BufferedWriter(new FileWriter("myio\\count.txt"));
        bw.write(count+"");//变成字符串,原样写出
        bw.close();
    }
}

2.转换流

image-20230420203754839

image-20230420204052645

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

  • 指定字符集读写(淘汰了
  • 字节流想要使用字符流中的方法
转换文件编码

​ 需求1:手动创建一个GBK的文件,把文件中的中文读取到内存中,不能出现乱码

​ 需求2:把一段中文按照GBK的方式写到本地文件

​ 需求3:将本地文件中的GBK文件,转成UTF-8

package com.itheima.myconvertDemo1;

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

public class ConvertStreamDemo1 {
    public static void main(String[] args) throws IOException {
        /*
            利用转换流按照指定的字符编码读取数据(了解)

            因为JDK11:这种方法被淘汰了,需要掌握替代方案

         */

//        //1.创建对象并指定字符编码
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\develop\\Y\\gbkfile.txt"),"GBK");
//        //2.读取数据
//        //转换流本身就是字符流,所以可以按照字符流的方式读取数据
//        int ch;
//        while((ch = isr.read()) != -1) {
//            System.out.print((char)ch);
//        }
//        //3.释放资源
//        isr.close();

        /**
         * 替代方案
         */
        FileReader fr = new FileReader("D:\\develop\\Y\\gbkfile.txt",Charset.forName("GBK"));
        //2.读取数据
        //转换流本身就是字符流,所以可以按照字符流的方式读取数据
        int ch;
        while((ch = fr.read()) != -1) {
            System.out.print((char)ch);
        }
        //3.释放资源
        fr.close();
    }
}
package com.itheima.myconvertDemo1;

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

public class ConvertStreamDemo2 {
    public static void main(String[] args) throws IOException {
        /*
            利用转换流按照指定的字符编码写出数据(淘汰)
         */

//        //1.创建转换流的对象
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myio\\b.txt"),"GBK");
//        //2.写出数据
//        osw.write("你好你好");
//        //3.释放资源
//        osw.close();

        //替代方案(掌握)
        FileWriter fw = new FileWriter("myio\\c.txt", Charset.forName("GBK"));
        fw.write("你好你好");
        fw.close();
    }
}
读取文件中的数据

利用字节流读取文件中的数据,每次读一整行,而且不能出现乱码

package com.itheima.mycovertstream;

import java.io.*;

public class CovertStreamDemo4 {
    public static void main(String[] args) throws IOException {
        /*
            利用字节流读取文件中的数据,每次读一整行,而且不能出现乱码

            //1.字节流在读取中文的时候,是会出现乱码的
            //2.字节流里面是没有读一整行的方法的,只有字符缓冲流才能搞定
         */

        /*FileInputStream fis=new FileInputStream("myio\\a.txt");
        InputStreamReader isr=new InputStreamReader(fis);
        BufferedReader br=new BufferedReader(isr);
        String str = br.readLine();
        System.out.println(str);
        br.close();*/

        BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("myio\\a.txt")));
        String line;
        while ((line=br.readLine())!=null){
            System.out.println(line);
        }
        br.close();
    }
}

3.序列化流/对象操作输出流

序列化流:可以把Java中的对象写到本地文件中

image-20230420212111935

image-20230420212416961

序列化流细节:

  • 使用对象输出流对象保存到文件时会出现NotSerializableException异常
  • 序列化流写到文件中的数据是不能修改的,一旦修改就无法再次读回来了

解决方案:需要Javabean类实现Serializable接口

package com.itheima.myobjectstream;

import java.io.Serializable;
/*
    Serializable接口里面是没有抽象方法的,标记型接口
    一旦实现了这个接口,那么就表示当前的Student类可以被序列化
    理解:
        一个物品的合格证
 */

public class Student implements Serializable {
    private String name;
    private int age;

    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;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

package com.itheima.myobjectstream;

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

public class ObjectStreamDemo1 {
    public static void main(String[] args) throws IOException {
        /*
            需求:
                利用序列化流/对象操作输出流,把一个对象写到本地文件中
            构造方法:
                public ObjectOutputStream(OutputStream out)     把基本流变成高级流
            成员方法:
                public final void writeObject(Object obj)       把对象序列化(写出)到文件中去


           */
        //1.创建对象
        Student stu=new Student("zhangsan",23);

        //2.创建序列化流的对象/对象操作输出流
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("myio\\a.txt"));

        //3.写出数据
        oos.writeObject(stu);

        //4.释放资源
        oos.close();
    }
}

4.反序列化流/对象操作输入流

可以把序列化到本地文件中的对象,读取到程序中来

image-20230421135842842

package com.itheima.myobjectstream;

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

public class ObjectStreamDemo2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        /*
           需求:
                利用反序列化流/对象操作输入流,把文件中中的对象读到程序当中
           构造方法:
                public ObjectInputStream(InputStream out)         把基本流变成高级流
           成员方法:
                public Object readObject()                        把序列化到本地文件中的对象,读取到程序中来
        */



        //1.创建反序列化流的对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myio\\a.txt"));

        //2.读取数据
        Student o = (Student) ois.readObject();//Object o=ois.readObject();为object。student强转

        //3.打印对象
        System.out.println(o);

        //4.释放资源
        ois.close();//Student{name = zhangsan, age = 23, address = null}



    }
}

细节:

序列化对象后,修改了Javabean类,再次反序列化,会抛出InvalidclassException异常

image-20230421140917491

处理方案:固定版本号

image-20230421141039373

transient:瞬态关键字

作用:不会把当前属性序列化到本地文件当中(还需将javabean中涉及的代码删去

综合练习

用对象流读取多个对象

需求:将多个自定义对象序列化到文件中,但是由于对象的个数不确定,反序列化流该如何读取呢?

package com.itheima.mytest;

import java.io.Serializable;

public class Student implements Serializable {

    private static final long serialVersionUID = -4953542782786788850L;
    private String name;
    private int age;
    private 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 + "}";
    }
}

package com.itheima.mytest;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

public class Test08 {
    public static void main(String[] args) throws IOException {
        /*需求:
            将多个自定义对象序列化到文件中,但是对象的个数不确定,该如何操作呢?
        */


        //1.序列化多个对象
        Student s1 = new Student("zhangsan",23,"南京");
        Student s2 = new Student("lisi",24,"重庆");
        Student s3 = new Student("wangwu",25,"北京");


        ArrayList<Student> list = new ArrayList<>();
        list.add(s1);
        list.add(s2);
        list.add(s3);

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myio\\a.txt"));
        oos.writeObject(list);


        oos.close();

    }
}

package com.itheima.mytest;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;

public class Test09 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {


        //1.创建反序列化流的对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myio\\a.txt"));

        //2.读取数据
        ArrayList<Student> list = (ArrayList<Student>) ois.readObject();

        for (Student student : list) {
            System.out.println(student);
        }


        //3.释放资源
        ois.close();

    }
}

5.打印流

image-20230421145132121

分类:

打印流一般是指:PrintStream,PrintWriter两个类

特点:
  • 打印流只操作文件目的地,不操作数据源

  • 特有的写出方法可以实现,数据原样写出

    例如:打印97 文件中97

    ​ 打印true 文件中true

  • 特有的写出方法,可以实现自动刷新,特有的println自动换行

    打印一次数据=写出+换行+刷新

(1)字节打印流

image-20230421145639516

字节流底层没有缓冲区,开不开自动刷新都一样(默认自动刷新

image-20230421145813133

package com.itheima.myprintstream;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

public class PrintStreamDemo1 {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
    /*
        字节打印流:
            构造方法
                public PrintStream(OutputStream/File/String)            关联字节输出流/文件/文件路径
                public PrintStream(String fileName, Charset charset)    指定字符编码
                public PrintStream(OutputStreamout, boolean autoFlush)  自动刷新
                public PrintStream(OutputStream out, boolean autoFlush, String encoding)    指定字符编码且自动刷新
            成员方法:
                public void write(int b)            常规方法:规则跟之前一样,将指定的字节写出
                public void println(Xxx xx)         特有方法:打印任意数据,自动刷新,自动换行
                public void print(Xxx xx)           特有方法:打印任意数据,不换行
                public void printf(String format, Object... args)   特有方法:带有占位符的打印语句,不换行
    */

        //1.创建字节打印流的对象
        PrintStream ps = new PrintStream(new FileOutputStream("myio\\a.txt"), true,"UTF-8");
        //2.写出数据
        ps.println(97);//写出 + 自动刷新 + 自动换行
        ps.print(true);
        ps.println();
        ps.printf("%s爱上了%s","阿珍","阿强");
        //3.释放资源
        ps.close();


    }
}
package com.itheima.myprintstream;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Date;

public class PrintStreamDemo2 {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps = new PrintStream("a.txt");

        //% n表示换行
        ps.printf("我叫%s %n", "阿玮");
        ps.printf("%s喜欢%s %n", "阿珍", "阿强");
        ps.printf("字母H的大写:%c %n", 'H');
        ps.printf("8>3的结果是:%b %n", 8 > 3);
        ps.printf("100的一半是:%d %n", 100 / 2);
        ps.printf("100的16进制数是:%x %n", 100);
        ps.printf("100的8进制数是:%o %n", 100);
        ps.printf("50元的书打8.5折扣是:%f元%n", 50 * 0.85);
        ps.printf("计算的结果转16进制:%a %n", 50 * 0.85);
        ps.printf("计算的结果转科学计数法表示:%e %n", 50 * 0.85);
        ps.printf("计算的结果转成指数和浮点数,结果的长度较短的是:%g %n", 50 * 0.85);
        ps.printf("带有百分号的符号表示法,以百分之85为例:%d%% %n", 85);
        ps.println("---------------------");

        double num1 = 1.0;
        ps.printf("num: %.4g %n", num1);
        ps.printf("num: %.5g %n", num1);
        ps.printf("num: %.6g %n", num1);

        float num2 = 1.0F;
        ps.printf("num: %.4f %n", num2);
        ps.printf("num: %.5f %n", num2);
        ps.printf("num: %.6f %n", num2);
        ps.println("---------------------");

        ps.printf("数字前面带有0的表示方式:%03d %n", 7);
        ps.printf("数字前面带有0的表示方式:%04d %n", 7);
        ps.printf("数字前面带有空格的表示方式:% 8d %n", 7);
        ps.printf("整数分组的效果是:%,d %n", 9989997);
        ps.println("---------------------");

        //最终结果是10位,小数点后面是5位,不够在前面补空格,补满10位
        //如果实际数字小数点后面过长,但是只规定两位,会四舍五入
        //如果整数部分过长,超出规定的总长度,会以实际为准
        ps.printf("一本书的价格是:%2.5f元%n", 49.8);
        ps.printf("%(f%n", -76.04);

        //%f,默认小数点后面7位,
        //<,表示采取跟前面一样的内容
        ps.printf("%f和%3.2f %n", 86.04, 1.789651);
        ps.printf("%f和%<3.2f %n", 86.04, 1.789651);
        ps.println("---------------------");

        Date date = new Date();
        // %t 表示时间,但是不能单独出现,要指定时间的格式
        // %tc 周二 12月 06 22:08:40 CST 2022
        // %tD 斜线隔开
        // %tF 冒号隔开(12小时制)
        // %tr 冒号隔开(24小时制)
        // %tT 冒号隔开(24小时制,带时分秒)
        ps.printf("全部日期和时间信息:%tc %n", date);
        ps.printf("月/日/年格式:%tD %n", date);
        ps.printf("年-月-日格式:%tF %n", date);
        ps.printf("HH:MM:SS PM格式(12时制):%tr %n", date);
        ps.printf("HH:MM格式(24时制):%tR %n", date);
        ps.printf("HH:MM:SS格式(24时制):%tT %n", date);

        System.out.println("---------------------");
        ps.printf("星期的简称:%ta %n", date);
        ps.printf("星期的全称:%tA %n", date);
        ps.printf("英文月份简称:%tb %n", date);
        ps.printf("英文月份全称:%tB %n", date);
        ps.printf("年的前两位数字(不足两位前面补0):%tC %n", date);
        ps.printf("年的后两位数字(不足两位前面补0):%ty %n", date);
        ps.printf("一年中的第几天:%tj %n", date);
        ps.printf("两位数字的月份(不足两位前面补0):%tm %n", date);
        ps.printf("两位数字的日(不足两位前面补0):%td %n", date);
        ps.printf("月份的日(前面不补0):%te  %n", date);

        System.out.println("---------------------");
        ps.printf("两位数字24时制的小时(不足2位前面补0):%tH %n", date);
        ps.printf("两位数字12时制的小时(不足2位前面补0):%tI %n", date);
        ps.printf("两位数字24时制的小时(前面不补0):%tk %n", date);
        ps.printf("两位数字12时制的小时(前面不补0):%tl %n", date);
        ps.printf("两位数字的分钟(不足2位前面补0):%tM %n", date);
        ps.printf("两位数字的秒(不足2位前面补0):%tS %n", date);
        ps.printf("三位数字的毫秒(不足3位前面补0):%tL %n", date);
        ps.printf("九位数字的毫秒数(不足9位前面补0):%tN %n", date);
        ps.printf("小写字母的上午或下午标记(英):%tp %n", date);
        ps.printf("小写字母的上午或下午标记(中):%tp %n", date);
        ps.printf("相对于GMT的偏移量:%tz %n", date);
        ps.printf("时区缩写字符串:%tZ%n", date);
        ps.printf("1970-1-1 00:00:00 到现在所经过的秒数:%ts %n", date);
        ps.printf("1970-1-1 00:00:00 到现在所经过的毫秒数:%tQ %n", date);

        ps.close();
    }
}
(2)字符打印流

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

image-20230421155326390

image-20230421155358677

package com.itheima.myprintstream;


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

public class PrintStreamDemo3 {
    public static void main(String[] args) throws IOException {
/*
        字符打印流:
            构造方法
                public PrintWriter(Write/File/String)            关联字节输出流/文件/文件路径
                public PrintWriter(String fileName, Charset charset)    指定字符编码
                public PrintWriter(Write, boolean autoFlush)  自动刷新
                public PrintWriter(Write out, boolean autoFlush, String encoding)    指定字符编码且自动刷新
            成员方法:
                public void write(int b)            常规方法:规则跟之前一样,将指定的字节写出
                public void println(Xxx xx)         特有方法:打印任意数据,自动刷新,自动换行
                public void print(Xxx xx)           特有方法:打印任意数据,不换行
                public void printf(String format, Object... args)   特有方法:带有占位符的打印语句,不换行
    */


      //1.创建字符打印流的对象
        PrintWriter pw = new PrintWriter(new FileWriter("myio\\a.txt"),true);

        //2.写出数据
        pw.println("今天你终于叫我名字了,虽然叫错了,但是没关系,我马上改");
        pw.print("你好你好");
        pw.printf("%s爱上了%s","阿珍","阿强");
        //3.释放资源
        pw.close();

    }
}

package com.itheima.myprintstream;

import java.io.PrintStream;

public class PrintStreamDemo4 {
    public static void main(String[] args) {
        /*
        *       打印流的应用场景
        * */

        //获取打印流的对象,此打印流在虚拟机启动的时候,由虚拟机创建,默认指向控制台
        //特殊的打印流,系统中的标准输出流,是不能关闭,在系统中是唯一的。
        PrintStream ps = System.out;

        //调用打印流中的方法println
        //写出数据,自动换行,自动刷新
        ps.println("123");

        //ps.close();关闭后无法再次启动,下列打印流无法执行


        ps.println("你好你好");


        System.out.println("456");

    }
}

6.解压缩流/压缩流

image-20230421161338333

(1)解压缩流

压缩包里面的每一个文件都是ZipEntry对象

解压本质:把每一个ZipEntry按照层级拷贝到本地另一个文件夹中

package com.itheima.myzipstream;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/*
*   解压缩流
*
* */
public class ZipStreamDemo1 {
    public static void main(String[] args) throws IOException {

        //1.创建一个File表示要解压的压缩包
        File src = new File("D:\\aaa.zip");
        //2.创建一个File表示解压的目的地
        File dest = new File("D:\\");

        //调用方法
        unzip(src,dest);

    }

    //定义一个方法用来解压
    public static void unzip(File src,File dest) throws IOException {
        //解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中
        //创建一个解压缩流用来读取压缩包中的数据
        ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
        //要先获取到压缩包里面的每一个zipentry对象
        //表示当前在压缩包中获取到的文件或者文件夹
        ZipEntry entry;
        while((entry = zip.getNextEntry()) != null){
            System.out.println(entry);
            if(entry.isDirectory()){
                //文件夹:需要在目的地dest处创建一个同样的文件夹
                File file = new File(dest,entry.toString());
                file.mkdirs();
            }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();


    }
}

(2)压缩流

压缩本质:把每一个(文件/文件夹)看成ZipEntry对象放到压缩包中

压缩单独的文件
package com.itheima.myzipstream;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipStreamDemo2 {
    public static void main(String[] args) throws IOException {
        /*
         *   压缩流
         *      需求:
         *          把D:\\a.txt打包成一个压缩包
         * */
        //1.创建File对象表示要压缩的文件
        File src = new File("D:\\a.txt");
        //2.创建File对象表示压缩包的位置
        File dest = new File("D:\\");
        //3.调用方法用来压缩
        toZip(src,dest);
    }

    /*
    *   作用:压缩
    *   参数一:表示要压缩的文件
    *   参数二:表示压缩包的位置
    * */
    public static void toZip(File src,File dest) throws IOException {
        //1.创建压缩流关联压缩包
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));
        //2.创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
        //参数:压缩包里面的路径
        ZipEntry entry = new ZipEntry("aaa\\bbb\\a.txt");
        //3.把ZipEntry对象放到压缩包当中
        zos.putNextEntry(entry);
        //4.把src文件中的数据写到压缩包当中
        FileInputStream fis = new FileInputStream(src);
        int b;
        while((b = fis.read()) != -1){
            zos.write(b);
        }
        zos.closeEntry();
        zos.close();

    }
}

压缩文件夹
package com.itheima.myzipstream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipStreamDemo3 {
    public static void main(String[] args) throws IOException {
        /*
         *   压缩流
         *      需求:
         *          把D:\\aaa文件夹压缩成一个压缩包
         * */


        //1.创建File对象表示要压缩的文件夹
        File src = new File("D:\\aaa");
        //2.创建File对象表示压缩包放在哪里(压缩包的父级路径)
        File destParent = src.getParentFile();//D:\\
        //3.创建File对象表示压缩包的路径
        File dest = new File(destParent,src.getName() + ".zip");//D:\aaa.zip
        //4.创建压缩流关联压缩包
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
        //5.获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
        toZip(src,zos,src.getName());//aaa
        //6.释放资源
        zos.close();
    }

    /*
    *   作用:获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
    *   参数一:数据源
    *   参数二:压缩流
    *   参数三:压缩包内部的路径
    * */
    public static void toZip(File src,ZipOutputStream zos,String name) throws IOException {
        //1.进入src文件夹
        File[] files = src.listFiles();
        //2.遍历数组
        for (File file : files) {
            if(file.isFile()){
                //3.判断-文件,变成ZipEntry对象,放入到压缩包当中
                //ZipEntry(),括号内为压缩包内部的路径,不可写为ZipEntry(file.toString),会先出现D盘再出现想要的文件
                ZipEntry entry = new ZipEntry(name + "\\" + file.getName());//aaa\\no1\\a.txt
                zos.putNextEntry(entry);
                //读取文件中的数据,写到压缩包
                FileInputStream fis = new FileInputStream(file);
                int b;
                while((b = fis.read()) != -1){
                    zos.write(b);
                }
                fis.close();
                zos.closeEntry();//表示当前文件书写完毕,不可写为zos.close(关闭内存和压缩包的通道
            }else{
                //4.判断-文件夹,递归
                toZip(file,zos,name + "\\" + file.getName());
                //     no1            aaa   \\   no1
            }
        }
    }
}

7.工具包

Commons-io

Commons-io时Apache开源基金组织提供的一组有关IO操作的开源工具包

作用:提高IO流的开发效率

image-20230421165427079

使用步骤:
  1. 在项目中创建一个文件夹:lib
  2. 将jar包复制粘贴到lib文件夹
  3. 右键点击jar包,选择Add as Library->点击OK
  4. 在类中导包使用
Commons-io常见方法

image-20230421165750242

image-20230421165846129

package com.itheima.mycommonsio;

import java.io.IOException;

public class CommonsIODemo1 {
    public static void main(String[] args) throws IOException {
        /*
          FileUtils类
                static void copyFile(File srcFile, File destFile)                   复制文件
                static void copyDirectory(File srcDir, File destDir)                复制文件夹
                static void copyDirectoryToDirectory(File srcDir, File destDir)     复制文件夹
                static void deleteDirectory(File directory)                         删除文件夹
                static void cleanDirectory(File directory)                          清空文件夹
                static String readFileToString(File file, Charset encoding)         读取文件中的数据变成成字符串
                static void write(File file, CharSequence data, String encoding)    写出数据

            IOUtils类
                public static int copy(InputStream input, OutputStream output)      复制文件
                public static int copyLarge(Reader input, Writer output)            复制大文件
                public static String readLines(Reader input)                        读取数据
                public static void write(String data, OutputStream output)          写出数据
         */


       /*
        复制文件:
        File src = new File("myio\\a.txt");
        File dest = new File("myio\\copy.txt");
        FileUtils.copyFile(src,dest);*/


        /*
        复制文件夹:
        File src = new File("D:\\aaa");
        File dest = new File("D:\\bbb");
        FileUtils.copyDirectory(src,dest);//直接拷贝文件夹里面的内容
        FileUtils.copyDirectoryToDirectory(src,dest);//将数据源的文件夹原封不动的拷贝到目的地文件夹里面
        */


        /*
        删除文件夹:
        File src = new File("D:\\bbb");
        FileUtils.deleteDirectory(src);//将文件夹全部删除
         */

        
        /*
        清空文件夹
        File src = new File("D:\\bbb");
        FileUtils.cleanDirectory(src);//将文件夹内容删除,但其本身留存
        */

    }
}

Hutool工具包

image-20230421171202310

image-20230421171228500

package com.itheima.myhutool;

import cn.hutool.core.io.FileUtil;

import java.util.List;

public class Test1 {
    public static void main(String[] args) {
    /*
        FileUtil类:
                file:根据参数创建一个file对象
                touch:根据参数创建文件

                writeLines:把集合中的数据写出到文件中,覆盖模式。
                appendLines:把集合中的数据写出到文件中,续写模式。
                readLines:指定字符编码,把文件中的数据,读到集合中。
                readUtf8Lines:按照UTF-8的形式,把文件中的数据,读到集合中

                copy:拷贝文件或者文件夹
    */


       /* File file1 = FileUtil.file("D:\\", "aaa", "bbb", "a.txt");
        System.out.println(file1);//D:\aaa\bbb\a.txt

        File touch = FileUtil.touch(file1);//如果父级路径不存在,不会报错,会将父级路径一同创建
        System.out.println(touch);


        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("aaa");
        list.add("aaa");

        File file2 = FileUtil.writeLines(list, "D:\\a.txt", "UTF-8");//写true表示开启追加
        System.out.println(file2);*/

      /*  ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("aaa");
        list.add("aaa");
        File file3 = FileUtil.appendLines(list, "D:\\a.txt", "UTF-8");
        System.out.println(file3);*/


        List<String> list = FileUtil.readLines("D:\\a.txt", "UTF-8");//该方法在底层帮我们创建一个集合,一行数据认作集合里的一个元素
        System.out.println(list);


    }
}

十、综合练习

制造假数据

需求:制造假数据也是开发中的一个能力,在各个往上爬取数据,是其中一个方法

爬取:
package com.itheima.myiotest1;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test1 {
    public static void main(String[] args) throws IOException {
        /*
         制造假数据:
             获取姓氏:https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0
             获取男生名字:http://www.haoming8.cn/baobao/10881.html
             获取女生名字:http://www.haoming8.cn/baobao/7641.html
        */

        //1.定义变量记录网址
        String familyNameNet = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0";
        String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";
        String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";

        //2.爬取数据,把网址上所有的数据拼接成一个字符串
        String familyNameStr = webCrawler(familyNameNet);
        String boyNameStr = webCrawler(boyNameNet);
        String girlNameStr = webCrawler(girlNameNet);

        //3.通过正则表达式,把其中符合要求的数据获取出来
        ArrayList<String> familyNameTempList = getData(familyNameStr,"(.{4})(,|。)",1);
        ArrayList<String> boyNameTempList = getData(boyNameStr,"([\\u4E00-\\u9FA5]{2})(、|。)",1);
        ArrayList<String> girlNameTempList = getData(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 + "");
            }
        }
        //boyNameTempList(男生的名字)
        //处理方案:去除其中的重复元素
        ArrayList<String> boyNameList = new ArrayList<>();
        for (String str : boyNameTempList) {
            //不存在,再添加入集合
            if(!boyNameList.contains(str)){
                boyNameList.add(str);
            }
        }
        //girlNameTempList(女生的名字)
        //处理方案:把里面的每一个元素用空格进行切割,得到每一个女生的名字
        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]);
            }
        }

        //5.生成数据
        //姓名(唯一)-性别-年龄
        ArrayList<String> list = getInfos(familyNameList, boyNameList, girlNameList, 70, 50);
        Collections.shuffle(list);


        //6.写出数据
        BufferedWriter bw = new BufferedWriter(new FileWriter("myiotest\\names.txt"));
        for (String str : list) {
            bw.write(str);
            bw.newLine();
        }
        bw.close();


    }

    /*
    * 作用:
    *      获取男生和女生的信息:张三-男-23
    *
    * 形参:
    *      参数一:装着姓氏的集合
    *      参数二:装着男生名字的集合
    *      参数三:装着女生名字的集合
    *      参数四:男生的个数
    *      参数五:女生的个数
    * */
    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(familyNameList);
            Collections.shuffle(boyNameList);
            boyhs.add(familyNameList.get(0) + boyNameList.get(0));
        }
        //2.生成女生不重复的名字
        HashSet<String> girlhs = new HashSet<>();
        while (true){
            if(girlhs.size() == girlCount){
                break;
            }
            //随机
            Collections.shuffle(familyNameList);
            Collections.shuffle(girlNameList);
            girlhs.add(familyNameList.get(0) + girlNameList.get(0));
        }
        //3.生成男生的信息并添加到集合当中
        ArrayList<String> list = new ArrayList<>();
        Random r = new Random();
        //【18 ~ 27】
        for (String boyName : boyhs) {
            //boyName依次表示每一个男生的名字
            int age = r.nextInt(10) + 18;
            list.add(boyName + "-男-" + age);
        }
        //4.生成女生的信息并添加到集合当中
        //【18 ~ 25】
        for (String girlName : girlhs) {
            //girlName依次表示每一个女生的名字
            int age = r.nextInt(8) + 18;
            list.add(girlName + "-女-" + age);
        }
        return list;
    }



    /*
    * 作用:根据正则表达式获取字符串中的数据
    * 参数一:
    *       完整的字符串
    * 参数二:
    *       正则表达式
    * 参数三:
    *      获取数据
    *       0:获取符合正则表达式所有的内容
    *       1:获取正则表达式中第一组数据
    *       2:获取正则表达式中第二组数据
    *       ...以此类推
    *
    * 返回值:
    *       真正想要的数据
    *
    * */
    private static ArrayList<String> getData(String str, String regex,int index) {
        //1.创建集合存放数据
        ArrayList<String> list = new ArrayList<>();
        //2.按照正则表达式的规则,去获取数据
        Pattern pattern = Pattern.compile(regex);
        //按照pattern的规则,到str当中获取数据
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()){
            list.add(matcher.group(index));
        }
        return list;

    }


    /*
    * 作用:
    *   从网络中爬取数据,把数据拼接成字符串返回
    * 形参:
    *   网址
    * 返回值:
    *   爬取到的所有数据
    * */
    public static String webCrawler(String net) throws IOException {
        //1.定义StringBuilder拼接爬取到的数据
        StringBuilder sb = new StringBuilder();
        //2.创建一个URL对象
        URL url = new URL(net);
        //3.链接上这个网址
        //细节:保证网络是畅通的,而且这个网址是可以链接上的。
        URLConnection conn = url.openConnection();
        //4.读取数据
        InputStreamReader isr = new InputStreamReader(conn.getInputStream());
        int ch;
        while ((ch = isr.read()) != -1){
            sb.append((char)ch);
        }
        //5.释放资源
        isr.close();
        //6.把读取到的数据返回
        return sb.toString();
    }
}
利用糊涂包生成假数据
package com.itheima.myiotest1;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HttpUtil;

import java.util.*;

public class Test2 {
    public static void main(String[] args){
        //利用糊涂包生成假数据,并写到文件当中

        //1. 定义网址
        String familyNameNet = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0";
        String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";
        String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";

        //2.爬取数据
        String familyNameStr = HttpUtil.get(familyNameNet);
        String boyNameStr = HttpUtil.get(boyNameNet);
        String girlNameStr = HttpUtil.get(girlNameNet);

        //3.利用正则表达式获取数据
        //通过正则表达式,把其中符合要求的数据获取出来
        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.处理数据
        //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 + "");
            }
        }
        //boyNameTempList(男生的名字)
        //处理方案:去除其中的重复元素
        ArrayList<String> boyNameList = new ArrayList<>();
        for (String str : boyNameTempList) {
            if(!boyNameList.contains(str)){
                boyNameList.add(str);
            }
        }
        //girlNameTempList(女生的名字)
        //处理方案:把里面的每一个元素用空格进行切割,得到每一个女生的名字
        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]);
            }
        }

        //5.生成数据
        //姓名(唯一)-性别-年龄
        ArrayList<String> list = getInfos(familyNameList, boyNameList, girlNameList, 70, 50);
        Collections.shuffle(list);

        //6.写出数据
        //细节:
        //糊涂包的相对路径,不是相对于当前项目而言的,而是相对class文件而言的
        FileUtil.writeLines(list,"D:\\names.txt","UTF-8");

    }

    /*
     * 作用:
     *      获取男生和女生的信息:张三-男-23
     *
     * 形参:
     *      参数一:装着姓氏的集合
     *      参数二:装着男生名字的集合
     *      参数三:装着女生名字的集合
     *      参数四:男生的个数
     *      参数五:女生的个数
     * */
    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(familyNameList);
            Collections.shuffle(boyNameList);
            boyhs.add(familyNameList.get(0) + boyNameList.get(0));
        }
        //2.生成女生不重复的名字
        HashSet<String> girlhs = new HashSet<>();
        while (true){
            if(girlhs.size() == girlCount){
                break;
            }
            //随机
            Collections.shuffle(familyNameList);
            Collections.shuffle(girlNameList);
            girlhs.add(familyNameList.get(0) + girlNameList.get(0));
        }
        //3.生成男生的信息并添加到集合当中
        ArrayList<String> list = new ArrayList<>();
        Random r = new Random();
        //【18 ~ 27】
        for (String boyName : boyhs) {
            //boyName依次表示每一个男生的名字
            int age = r.nextInt(10) + 18;
            list.add(boyName + "-男-" + age);
        }
        //4.生成女生的信息并添加到集合当中
        //【18 ~ 25】
        for (String girlName : girlhs) {
            //girlName依次表示每一个女生的名字
            int age = r.nextInt(8) + 18;
            list.add(girlName + "-女-" + age);
        }
        return list;
    }
}

1.随机点名器

(1)
package com.itheima.myiotest2;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Test {
    public static void main(String[] args) throws IOException {
        /*需求:
            需求:
                有一个文件里面存储了班级同学的信息,每一个信息占一行。
                格式为:张三-男-23
                要求通过程序实现随机点名器。

            运行效果:
                第一次运行程序:随机同学姓名1(只显示名字)
                第二次运行程序:随机同学姓名2(只显示名字)
                第三次运行程序:随机同学姓名3(只显示名字)
                …
         */

        //1.读取文件中学生的姓名
        ArrayList<String> list = new ArrayList<>();
        BufferedReader br = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest2\\names.txt"));
        String line;
        while ((line = br.readLine()) != null){
            list.add(line);
        }
        br.close();

        //2.随机抽取(解法一)
        Random r = new Random();
        int index = r.nextInt(list.size());
        String randomName1 = list.get(index);
        String[] arr1 = randomName1.split("-");
        System.out.println(arr1[0]);


        //2.随机抽取(解法二)
        Collections.shuffle(list);
        String randomName2 = list.get(0);
        String[] arr2 = randomName2.split("-");
        System.out.println(arr2[0]);


    }
}

(2)
package com.itheima.myiotest3;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Test {
    public static void main(String[] args) throws IOException {
        /*需求:
            一个文件里面存储了班级同学的信息,格式为:张三-男-23
            每一个学生信息占一行。
            要求通过程序实现随机点名器。
            70%的概率随机到男生
            30%的概率随机到女生
            随机100万次,统计结果。看生成男生和女生的比例是不是接近于7:3
        */

        //1.读取数据,并把男生和女生的信息添加到不同的集合当中
        ArrayList<String> boyNameList = new ArrayList<>();
        ArrayList<String> girlNameList = new ArrayList<>();
        BufferedReader br = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest3\\names.txt"));
        String line;
        while ((line = br.readLine()) != null){
            String[] arr = line.split("-");
            if(arr[1].equals("男")){
                boyNameList.add(line);
            }else{
                girlNameList.add(line);
            }
        }
        br.close();

        //2.定义权重集合,男女比例:7:3
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,1,1,1,1,1,1,0,0,0);

        //3.定义变量,统计被点到的次数
        int boyCount = 0;
        int girlCount = 0;

        Random r = new Random();

        //4.循环100万次
        for (int i = 0; i < 1000000; i++) {
           //5.从权重集合中获取随机数据
            int index = r.nextInt(list.size());
            int weight = list.get(index);
            //6.判断获取的随机数据是1还是0
            if(weight == 1){
                //1就随机男生
                Collections.shuffle(boyNameList);
                String boyInfo = boyNameList.get(0);
                System.out.println(boyInfo);
                boyCount++;
            }else{
                //0就随机女生
                Collections.shuffle(girlNameList);
                String girlInfo = girlNameList.get(0);
                System.out.println(girlInfo);
                girlCount++;
            }
        }

        System.out.println("随机抽取100万次,其中男生被抽到了" + boyCount);
        System.out.println("随机抽取100万次,其中女生被抽到了" + girlCount);

    }
}

(3)
package com.itheima.myiotest4;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;

public class Test {
    public static void main(String[] args) throws IOException {
        /*需求:
            一个文件里面存储了班级同学的姓名,每一个姓名占一行。
            要求通过程序实现随机点名器。
            第三次必定是张三同学

          运行效果:
            第一次运行程序:随机同学姓名1
            第二次运行程序:随机同学姓名2
            第三次运行程序:张三
            …
        */

        //1.读取数据,并把学生信息添加到集合当中
        ArrayList<String> list = new ArrayList<>();
        BufferedReader br1 = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest4\\names.txt"));
        String line;
        while ((line = br1.readLine()) != null){
            list.add(line);
        }
        br1.close();
        //2.读取当前程序已经运行的次数
        BufferedReader br2 = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest4\\count.txt"));
        String countStr = br2.readLine();
        int count = Integer.parseInt(countStr);
        br2.close();
        //4.表示程序再次运行了一次
        count++;
        //3.判断,如果当前已经是第三次,直接打印,不是第三次才随机
        if(count == 3){
            System.out.println("张三");
        }else {
            Collections.shuffle(list);
            String stuInfo = list.get(0);
            System.out.println(stuInfo);
        }

        //4.将程序已经运行的次数写会本地文件
        BufferedWriter bw = new BufferedWriter(new FileWriter("myiotest\\src\\com\\itheima\\myiotest4\\count.txt"));
        bw.write(count + "");
        bw.close();



    }
}

(4)
package com.itheima.myiotest5;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;

public class Test {
    public static void main(String[] args) throws IOException {
        /*需求:
            一个文件里面存储了班级同学的姓名,每一个姓名占一行。
            要求通过程序实现随机点名器。

          运行结果要求:
            被点到的学生不会再被点到。
            但是如果班级中所有的学生都点完了, 需要重新开启第二轮点名。

          核心思想:
               点一个删一个,把删除的备份,全部点完时还原数据。

        */

        //1.定义变量,表示初始文件路径,文件中存储所有的学生信息
        String src = "myiotest\\src\\com\\itheima\\myiotest5\\names.txt";
        //2.定义变量,表示备份文件,一开始文件为空
        String backups = "myiotest\\src\\com\\itheima\\myiotest5\\backups.txt";
        //3.读取初始文件中的数据,并把学生信息添加到集合当中
        ArrayList<String> list = readFile(src);
        //4.判断集合中是否有数据
        if (list.size() == 0) {
            //5.如果没有数据,表示所有学生已经点完,从backups.txt中还原数据即可
            //还原数据需要以下步骤:
            //5.1 读取备份文件中所有的数据
            list = readFile(backups);
            //5.2 把所有的数据写到初始文件中
            writeFile(src, list, false);
            //5.3 删除备份文件
            new File(backups).delete();
        }
        //5.集合中有数据,表示还没有点完,点一个删一个,把删除的备份到backups.txt当中
        //打乱集合
        Collections.shuffle(list);
        //获取0索引的学生信息并删除
        String stuInfo = list.remove(0);
        //打印随机到的学生信息
        System.out.println("当前被点到的学生为:" + stuInfo);
        //把删除之后的所有学生信息,写到初始文件中
        writeFile(src, list, false);
        //把删除的学生信息备份(追加写入)
        writeFile(backups, stuInfo, true);


    }

    private static void writeFile(String pathFile, ArrayList<String> list, boolean isAppend) throws IOException {
        BufferedWriter bw = new BufferedWriter(new FileWriter(pathFile, isAppend));
        for (String str : list) {
            bw.write(str);
            bw.newLine();
        }
        bw.close();
    }

    private static void writeFile(String pathFile, String str, boolean isAppend) throws IOException {
        BufferedWriter bw = new BufferedWriter(new FileWriter(pathFile, isAppend));
        bw.write(str);
        bw.newLine();
        bw.close();
    }


    private static ArrayList<String> readFile(String pathFile) throws IOException {
        ArrayList<String> list = new ArrayList<>();
        BufferedReader br = new BufferedReader(new FileReader(pathFile));
        String line;
        while ((line = br.readLine()) != null) {
            list.add(line);
        }
        br.close();
        return list;
    }
}

(5)
package com.itheima.myiotest6;

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;
    }
}

package com.itheima.myiotest6;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;

public class Test {
    public static void main(String[] args) throws IOException {
        //1.把文件中所有的学生信息读取到内存中
        ArrayList<Student> list = new ArrayList<>();
        BufferedReader br = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest6\\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]));
            list.add(stu);
        }
        br.close();

        //2.计算权重的总和
        double weight = 0;
        for (Student stu : list) {
            weight = weight + stu.getWeight();
        }

        //3.计算每一个人的实际占比
        //[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
        double[] arr = new double[list.size()];
        int index = 0;
        for (Student stu : list) {
            arr[index] = stu.getWeight() / weight;
            index++;
        }

        //4.计算每一个人的权重占比范围
        for (int i = 1; i < arr.length; i++) {
            arr[i] = arr[i] + arr[i - 1];
        }

        //5.随机抽取
        //获取一个0.0~1.0之间的随机数
        double number = Math.random();
        //判断number在arr中的位置
        //二分查找法
        //方法回返回: - 插入点 - 1
        //获取number这个数据在数组当中的插入点位置
        int result = -Arrays.binarySearch(arr, number) - 1;
        Student stu = list.get(result);
        System.out.println(stu);

        //6.修改当前学生的权重
        double w = stu.getWeight() / 2;
        stu.setWeight(w);

       //7.把集合中的数据再次写到文件中
        BufferedWriter bw = new BufferedWriter(new FileWriter("myiotest\\src\\com\\itheima\\myiotest6\\names.txt"));
        for (Student s : list) {
            bw.write(s.toString());
            bw.newLine();
        }
        bw.close();


    }
}

2.登陆注册

(1)
package com.itheima.myiotest7;


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) throws IOException {
       /*
        需求:写一个登陆小案例。

        步骤:
            将正确的用户名和密码手动保存在本地的userinfo.txt文件中。
            保存格式为:username=zhangsan&password=123
            让用户键盘录入用户名和密码
                    比较用户录入的和正确的用户名密码是否一致
            如果一致则打印登陆成功
                    如果不一致则打印登陆失败
        */

        //1.读取正确的用户名和密码
        BufferedReader br = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest7\\userinfo.txt"));
        String line = br.readLine();//username=zhangsan&password=123
        br.close();
        String[] userInfo = line.split("&");
        String[] arr1 = userInfo[0].split("=");
        String[] arr2 = userInfo[1].split("=");

        String rightUsername = arr1[1];
        String rightPassword = arr2[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)){
            System.out.println("登陆成功");
        }else{
            System.out.println("登陆失败");
        }


    }
}
(2)
package com.itheima.myiotest8;


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

public class Test {
    public static void main(String[] args) throws IOException {
       /*
        需求:写一个登陆小案例(添加锁定账号功能)

        步骤:
        	将正确的用户名和密码手动保存在本地的userinfo.txt文件中。
        	保存格式为:username=zhangsan&password=123&count=0
        	让用户键盘录入用户名和密码
        	比较用户录入的和正确的用户名密码是否一致
        	如果一致则打印登陆成功
        	如果不一致则打印登陆失败,连续输错三次被锁定

        */

        //1.读取正确的用户名和密码
        BufferedReader br = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest8\\userinfo.txt"));
        String line = br.readLine();//username=zhangsan&password=123&count=0
        br.close();
        String[] userInfo = line.split("&");
        String[] arr1 = userInfo[0].split("=");
        String[] arr2 = userInfo[1].split("=");
        String[] arr3 = userInfo[2].split("=");

        String rightUsername = arr1[1];
        String rightPassword = arr2[1];
        //count:表示用户连续输错的次数
        int count = Integer.parseInt(arr3[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) {
            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("myiotest\\src\\com\\itheima\\myiotest8\\userinfo.txt"));
        bw.write(content);
        bw.close();
    }
}
(3)

image-20230421183843845


  •   需求:写一个登陆小案例。
    
      步骤:
          将正确的用户名和密码手动保存在本地的userinfo.txt文件中。
          保存格式为:username=zhangsan&password=123
          让用户键盘录入用户名和密码
                  比较用户录入的和正确的用户名密码是否一致
          如果一致则打印登陆成功
                  如果不一致则打印登陆失败
      */
    
      //1.读取正确的用户名和密码
      BufferedReader br = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest7\\userinfo.txt"));
      String line = br.readLine();//username=zhangsan&password=123
      br.close();
      String[] userInfo = line.split("&");
      String[] arr1 = userInfo[0].split("=");
      String[] arr2 = userInfo[1].split("=");
    
      String rightUsername = arr1[1];
      String rightPassword = arr2[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)){
          System.out.println("登陆成功");
      }else{
          System.out.println("登陆失败");
      }
    

    }
    }




#### (2)

```java
package com.itheima.myiotest8;


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

public class Test {
    public static void main(String[] args) throws IOException {
       /*
        需求:写一个登陆小案例(添加锁定账号功能)

        步骤:
        	将正确的用户名和密码手动保存在本地的userinfo.txt文件中。
        	保存格式为:username=zhangsan&password=123&count=0
        	让用户键盘录入用户名和密码
        	比较用户录入的和正确的用户名密码是否一致
        	如果一致则打印登陆成功
        	如果不一致则打印登陆失败,连续输错三次被锁定

        */

        //1.读取正确的用户名和密码
        BufferedReader br = new BufferedReader(new FileReader("myiotest\\src\\com\\itheima\\myiotest8\\userinfo.txt"));
        String line = br.readLine();//username=zhangsan&password=123&count=0
        br.close();
        String[] userInfo = line.split("&");
        String[] arr1 = userInfo[0].split("=");
        String[] arr2 = userInfo[1].split("=");
        String[] arr3 = userInfo[2].split("=");

        String rightUsername = arr1[1];
        String rightPassword = arr2[1];
        //count:表示用户连续输错的次数
        int count = Integer.parseInt(arr3[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) {
            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("myiotest\\src\\com\\itheima\\myiotest8\\userinfo.txt"));
        bw.write(content);
        bw.close();
    }
}
(3)

[外链图片转存中…(img-YDuL5vjF-1682159273607)]


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值