菜鸟之路Day18一一IO流综合练习

菜鸟之路Day18一一IO流综合练习

作者:blue

时间:2025.2.21

文章目录

0.概述

文章内容学习自黑马程序员BV1yW4y1Y7Ms

1.生成假数据(网页爬虫)

实现了一个姓名生成器,主要功能是从指定网页爬取姓氏、男孩名和女孩名数据,处理后生成随机组合的姓名,并附加性别和年龄信息,最终将结果写入文件。

代码通过爬虫、正则匹配和随机化处理,生成包含姓氏、性别和年龄的模拟数据,适用于需要批量生成测试姓名的场景。

java 复制代码
package FinallyTest;

import java.io.*;
import java.net.MalformedURLException;
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 FinallyTest1 {
    public static void main(String[] args) throws IOException {
        //https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d
        //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";
        String BoyNameNet = "http://www.haoming8.cn/baobao/10881.html";
        String GirlNameNet = "http://www.haoming8.cn/baobao/7641.html";

        //2.爬取网页上的信息
        //仅仅爬取出了前端源码
        String FamilyNameInfo = webCrawler(FamilyNameNet);
        String BoyNameInfo = webCrawler(BoyNameNet);
        String GirlNameInfo = webCrawler(GirlNameNet);

        //3.获取真正想要的信息
        ArrayList<String> FamilyNameTempList = getData(FamilyNameInfo, "(.{4})(,|。)", 1);
        FamilyNameTempList.removeIf(e -> e.equals("em\">"));//去除掉造成干扰的标签

        ArrayList<String> BoyNameTempList = getData(BoyNameInfo, "([\\u4E00-\\u9FA5]{2})(、|。)", 1);

        ArrayList<String> GirlNameTempList = getData(GirlNameInfo, "(.. ){4}..", 0);

        //4.处理数据
        //FamilyNameTempList(姓氏)
        //处理方法:获取单个姓氏
        ArrayList<String> FamilyNameList = new ArrayList<>();
        for (String s : FamilyNameTempList) {
            for (int i = 0; i < s.length(); i++) {
                FamilyNameList.add(s.charAt(i) + "");
            }
        }

        //BoyNameTempList(男生名字)
        //处理方法:去重
        ArrayList<String> BoyNameList = new ArrayList<>();
        for (String s : BoyNameTempList) {
            if (!BoyNameList.contains(s)) {
                BoyNameList.add(s);
            }
        }

        //GirlNameTempList(女生名字)
        //处理方法:切割
        ArrayList<String> GirlNameList = new ArrayList<>();
        for (String s : GirlNameTempList) {
            String[] s1 = s.split(" ");
            for (String string : s1) {
                GirlNameList.add(string);
            }
        }

        //5.组合所有姓名
        //格式:姓名(唯一)-性别-年龄
        ArrayList<String> list = getInfos(FamilyNameList, BoyNameList, GirlNameList, 50, 70);
        Collections.shuffle(list);
        System.out.println(list);

        //6.将数据写到文件中
        //这里用BufferedWriter,主要是为了使用其中的newLine方法
        BufferedWriter bw = new BufferedWriter(new FileWriter("src\\FinallyTest\\name.txt"));
        for (String name : list) {
            bw.write(name);
            bw.newLine();
        }
        bw.close();
    }

    /*
     * 作用:组合姓名(唯一)-性别-年龄
     * 参数一:姓氏集合
     * 参数二:男生名字集合
     * 参数三:女生名字集合
     * 参数四:男生个数
     * 参数五:女生个数
     * */
    private static ArrayList<String> getInfos(ArrayList<String> FamilyNameList, ArrayList<String> BoyNameList, ArrayList<String> GirlNameList, int boyCount, int girlCount) {
        //用set来做一个去重操作
        //男生姓名
        HashSet<String> boyhs = new HashSet<>();
        while (true) {
            if (boyhs.size() == boyCount) {
                break;
            } else {
                //每次打乱之后再拼接
                Collections.shuffle(FamilyNameList);
                Collections.shuffle(BoyNameList);
                boyhs.add(FamilyNameList.getFirst() + BoyNameList.getFirst());//取第一个拼接
            }
        }

        //女生姓名
        HashSet<String> girlhs = new HashSet<>();
        while (true) {
            if (girlhs.size() == girlCount) {
                break;
            } else {
                //每次打乱之后再拼接
                Collections.shuffle(FamilyNameList);
                Collections.shuffle(GirlNameList);
                girlhs.add(FamilyNameList.getFirst() + GirlNameList.getFirst());//取第一个拼接
            }
        }

        ArrayList<String> list = new ArrayList<>();//存储返回值
        //[18-27岁]
        Random rd = new Random();
        for (String boyName : boyhs) {
            int age = rd.nextInt(10)+18;
            list.add(boyName+"-男-"+age);
        }

        for (String girlName : girlhs) {
            int age = rd.nextInt(10)+18;
            list.add(girlName+"-女-"+age);
        }
        return list;
    }

    /*
     * 获取真正想要的数据
     * 参数一:
     *   数据源
     * 参数二:
     *   正则表达式
     * 参数三:
     *   真正想要的数据
     * */
    private static ArrayList<String> getData(String str, String regex, int index) {
        ArrayList<String> list = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            list.add(matcher.group(index));
        }
        return list;
    }

    //爬取整个网页的信息
    private static String webCrawler(String familyNameNet) throws IOException {
        //用StringBuilder对象来获取拼接的数据
        StringBuilder sb = new StringBuilder();
        //创建url对象
        URL url = new URL(familyNameNet);
        //链接到网页
        URLConnection conn = url.openConnection();
        //获取网页中的数据,conn中有getInputStream方法可以获取字节流,但是有可能涉及到爬取中文数据
        //所以我们用转换流把其包装为字符流
        InputStreamReader isr = new InputStreamReader(conn.getInputStream());
        int ch;
        while ((ch = isr.read()) != -1) {
            sb.append((char) ch);
        }
        //释放资源
        isr.close();
        return sb.toString();
    }
}

利用hutool包中的方法来尝试实现上述功能

hutool包参考文档中的代码,与我们的源代码非常接近。

java 复制代码
//请求列表页
String listContent = HttpUtil.get("https://www.oschina.net/action/ajax/get_more_news_list?newsType=&p=2");
//使用正则获取所有标题
List<String> titles = ReUtil.findAll("<span class=\"text-ellipsis\">(.*?)</span>", listContent, 1);
for (String title : titles) {
	//打印标题
	Console.log(title);
}

代码实现:

java 复制代码
package FinallyTest;

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

import java.util.*;

public class FinallyTest2 {
    public static void main(String[] args) {
        //1.创建字符串表示网址
        String FamilyNameNet = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d";
        String BoyNameNet = "http://www.haoming8.cn/baobao/10881.html";
        String GirlNameNet = "http://www.haoming8.cn/baobao/7641.html";

        //2.爬取网页上的信息(请求列表页)
        String FamilyNameInfo = HttpUtil.get(FamilyNameNet);
        String BoyNameInfo = HttpUtil.get(BoyNameNet);
        String GirlNameInfo = HttpUtil.get(GirlNameNet);

        //3.获取真正想要的信息(使用正则获取所有标题)
        List<String> FamilyNameTempList = ReUtil.findAll("(.{4})(,|。)", FamilyNameInfo, 1);
        FamilyNameTempList.removeIf(e -> e.equals("em\">"));//去除掉造成干扰的标签

        List<String> BoyNameTempList = ReUtil.findAll("([\\u4E00-\\u9FA5]{2})(、|。)", BoyNameInfo, 1);

        List<String> GirlNameTempList = ReUtil.findAll("(.. ){4}..", GirlNameInfo, 0);

        //4.处理数据
        //FamilyNameTempList(姓氏)
        //处理方法:获取单个姓氏
        ArrayList<String> FamilyNameList = new ArrayList<>();
        for (String s : FamilyNameTempList) {
            for (int i = 0; i < s.length(); i++) {
                FamilyNameList.add(s.charAt(i) + "");
            }
        }

        //BoyNameTempList(男生名字)
        //处理方法:去重
        ArrayList<String> BoyNameList = new ArrayList<>();
        for (String s : BoyNameTempList) {
            if (!BoyNameList.contains(s)) {
                BoyNameList.add(s);
            }
        }

        //GirlNameTempList(女生名字)
        //处理方法:切割
        ArrayList<String> GirlNameList = new ArrayList<>();
        for (String s : GirlNameTempList) {
            String[] s1 = s.split(" ");
            for (String string : s1) {
                GirlNameList.add(string);
            }
        }

        //5.组合所有姓名
        //格式:姓名(唯一)-性别-年龄
        ArrayList<String> list = getInfos(FamilyNameList, BoyNameList, GirlNameList, 50, 70);
        Collections.shuffle(list);
        System.out.println(list);

        //6.将数据写到文件中
        FileUtil.writeLines(list, "FinallyTest\\namesHutool.txt", "UTF-8");
    }

    /*
     * 作用:组合姓名(唯一)-性别-年龄
     * 参数一:姓氏集合
     * 参数二:男生名字集合
     * 参数三:女生名字集合
     * 参数四:男生个数
     * 参数五:女生个数
     * */
    private static ArrayList<String> getInfos(ArrayList<String> FamilyNameList, ArrayList<String> BoyNameList, ArrayList<String> GirlNameList, int boyCount, int girlCount) {
        //用set来做一个去重操作
        //男生姓名
        HashSet<String> boyhs = new HashSet<>();
        while (true) {
            if (boyhs.size() == boyCount) {
                break;
            } else {
                //每次打乱之后再拼接
                Collections.shuffle(FamilyNameList);
                Collections.shuffle(BoyNameList);
                boyhs.add(FamilyNameList.getFirst() + BoyNameList.getFirst());//取第一个拼接
            }
        }

        //女生姓名
        HashSet<String> girlhs = new HashSet<>();
        while (true) {
            if (girlhs.size() == girlCount) {
                break;
            } else {
                //每次打乱之后再拼接
                Collections.shuffle(FamilyNameList);
                Collections.shuffle(GirlNameList);
                girlhs.add(FamilyNameList.getFirst() + GirlNameList.getFirst());//取第一个拼接
            }
        }

        ArrayList<String> list = new ArrayList<>();//存储返回值
        //[18-27岁]
        Random rd = new Random();
        for (String boyName : boyhs) {
            int age = rd.nextInt(10)+18;
            list.add(boyName+"-男-"+age);
        }

        for (String girlName : girlhs) {
            int age = rd.nextInt(10)+18;
            list.add(girlName+"-女-"+age);
        }
        return list;
    }

}

2.随机点名器

2.1随机点名器1

需求:

有一个文件里面存储了班级同学的信息,每一个信息占一行。

​ 格式为:张三-男-23

​ 要求通过程序实现随机点名器。

运行效果:

第一次运行程序:随机同学姓名1(只显示名字)

第二次运行程序:随机同学姓名2(只显示名字)

第三次运行程序:随机同学姓名3(只显示名字)

java 复制代码
public class FinallyTest4 {
    public static void main(String[] args) throws IOException {
        //1.先将文件中的数据读入到集合中
        ArrayList<String> list = getData("src\\FinallyTest\\name.txt");
        //2.打乱,根据
        Collections.shuffle(list);
        String[] arr = list.getFirst().split("-");
        System.out.println(arr[0]);
    }
    private static ArrayList<String> getData(String path) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(path));
        ArrayList<String> list = new ArrayList<>();
        String elem;
        while((elem=br.readLine())!=null){
            list.add(elem);
        }
        br.close();
        return list;
    }
}

2.2随机点名器2

需求:

一个文件里面存储了班级同学的信息,每一个学生信息占一行格式为:张三-男-23。

​ 要求通过程序实现随机点名器,

运行效果:

70%的概率随机到男生

​ 30%的概率随机到女生

​ 总共随机100万次,统计结果。

注意观察:看生成男生和女生的比例是不是接近于7:3

java 复制代码
package FinallyTest;

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

public class FinallyTest4 {
    public static void main(String[] args) throws IOException {
        //1.先将文件中的数据读入到集合中
        ArrayList<String> list = getData("src\\FinallyTest\\name.txt");
        //2.将男女集合进行分类
        ArrayList<String> BoyList = new ArrayList<>();
        ArrayList<String> GirlList = new ArrayList<>();
        for (String name : list) {
            String[] arr = name.split("-");
            if(arr[1].equals("男")){
                BoyList.add(name);
            }
            else {
                GirlList.add(name);
            }
        }
        //3.创建一个数组,10个数,7个1,3个0,1代表抽男生,0代表抽女生,模拟概率
        ArrayList<Integer> arr = new ArrayList<>();
        Collections.addAll(arr,1,1,1,1,1,1,1,0,0,0);
        //4.统计次数
        int BoyCount=0;
        int GirlCount=0;
        for(int i=1;i<=1000000;i++){
            Collections.shuffle(arr);
            //抽男生
            if(arr.getFirst()==1){
                Collections.shuffle(BoyList);
                BoyCount++;
                System.out.println(BoyList.getFirst());
            }
            else {//抽女生
                Collections.shuffle(GirlList);
                GirlCount++;
                System.out.println(GirlList.getFirst());
            }
        }
        System.out.println(BoyCount/1000000.0+"");//0.699904
        System.out.println(GirlCount/1000000.0+"");//0.300096
    }

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

}

2.3随机点名器3

需求:

一个文件里面存储了班级同学的姓名,每一个姓名占一行。

要求通过程序实现随机点名器

第三次必定是张三同学

运行效果:

第一次运行程序:随机同学姓名1

第二次运行程序:随机同学姓名2

第三次运行程序:张三

思路:新建一个Count文件来记录程序运行的次数

java 复制代码
package FinallyTest;

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

public class FinallyTest5 {
    public static void main(String[] args) throws IOException {
        //1.先将文件中的数据读入到集合中
        ArrayList<String> list = getData("src\\FinallyTest\\name.txt");
        BufferedReader br = new BufferedReader(new FileReader("src\\FinallyTest\\Count.txt"));
        int count = br.read()-'0';
        BufferedWriter bw = new BufferedWriter(new FileWriter("src\\FinallyTest\\Count.txt"));
        if(count==2) {
            System.out.println("张三");
            bw.write(count+1+"");
        }
        else {
            Collections.shuffle(list);
            String[] arr = list.getFirst().split("-");
            System.out.println(arr[0]);
            bw.write(count+1+"");
        }
        bw.close();
        br.close();
    }

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

2.4随机点名器4

需求:

一个文件里面存储了班级同学的姓名,每一个姓名占一行。

要求通过程序实现随机点名器。

运行效果:

被点到的学生不会再被点到

如果班级中所有的学生都点完了,需要自动的重新开启第二轮点名

细节1:假设班级有10个学生,每一轮中每一位学生只能被点到一次,程序运行10次,第一轮结束

细节2:第11次运行的时候,我们自己不需要手动操作本地文件,要求程序自动开始第二轮点名

思路:新建一个文件记录被点到学生的姓名,原先的文件点到一个删一个,这样就保证了不重复,删完了,就交替两个文件中的数据,代表新一轮开始

java 复制代码
public class FinallyTest6 {
    public static void main(String[] args) throws IOException, InterruptedException {
        for(int i=0;i<=120;i++){
            runMain();
            Thread.sleep(500);//暂停0.5秒查看文件效果
        }
    }
    private static ArrayList<String> getData(String path) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(path));
        ArrayList<String> list = new ArrayList<>();
        String elem;
        while((elem=br.readLine())!=null){
            list.add(elem);
        }
        br.close();
        return list;
    }

    private static void runMain() throws IOException {
        //1.获取数据
        ArrayList<String> list1 = getData("src\\FinallyTest\\name.txt");
        ArrayList<String> list2 = getData("src\\FinallyTest\\namecopy.txt");
        //2.打乱,点名,点一个删一个
        if(list1.isEmpty()){//交替
            list1.addAll(list2);
            list2.clear();
        }
        Collections.shuffle(list1);
        System.out.println(list1.getFirst());
        list2.add(list1.getFirst());
        list1.removeFirst();
        //3.写回
        BufferedWriter bw1 = new BufferedWriter(new FileWriter("src\\FinallyTest\\name.txt"));
        BufferedWriter bw2 = new BufferedWriter(new FileWriter("src\\FinallyTest\\namecopy.txt"));
        for (String name : list1) {
            bw1.write(name);
            bw1.newLine();
        }
        for (String name : list2) {
            bw2.write(name);
            bw2.newLine();
        }
        bw1.close();
        bw2.close();
    }
}

2.5随机点名器5(带权重的随机算法)

需求:txt文件中事先准备好一些学生信息,每个学生的信息独占一行

要求1:每次被点到的学生,再次被点到的概率在原先的基础上降低一半。

思路:首先,我们可以先处理数据,在数据中先给每个数据都添加上权重

复制代码
曾博月-男-26-1
赫依娜-女-26-1
杜茜燕-女-26-1
正美丽-男-25-1
蒋胜游-男-18-1
郈蔼雅-女-26-1
连雅宁-女-24-1
于淑弘-女-23-1
宗紫凡-女-23-1
闵红新-女-27-1
蒙玉涛-男-21-1
............

创建Student类来管理学生对象

java 复制代码
package FinallyTest;

public class Student {
    private String name;
    private String sex;
    private int age;
    private double weight;

    public Student() {
    }

    public Student(String name, String sex, int age, double weight) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    //改写了toString方法,方便写回到文件中
    @Override
    public String toString() {
        return name + "-" + sex + "-" + age + "-" + weight;
    }
}

带权重的随机过程

java 复制代码
package FinallyTest;

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

public class FinallyTest7 {
    public static void main(String[] args) throws IOException {
        //1.获取数据
        ArrayList<String> list = getData("src\\FinallyTest\\name_weight.txt");
        //2.处理数据
        ArrayList<Student> listStu = new ArrayList<>();
        for (String info : list) {
            //切割
            String[] arr = info.split("-");
            //存入到listStu中
            listStu.add(new Student(arr[0], arr[1], Integer.parseInt(arr[2]), Double.parseDouble(arr[3])));
        }
        //3.计算权重总和
        double weight_sum = 0;
        for (Student student : listStu) {
            weight_sum = weight_sum + student.getWeight();
        }
        //4.计算每个人在总权重中的实际占比
        double[] listRate = new double[listStu.size()];
        int index = 0;
        for (Student student : listStu) {
            listRate[index] = (student.getWeight() / weight_sum);
            index++;
        }
        //5.计算每个人权重的占比范围
        for (int i = 1; i < listRate.length; i++) {
            listRate[i] = listRate[i - 1] + listRate[i];
        }
        //6.随机抽取
        double x = Math.random(); //随机一个0-1的小数
        //binarySearch的结果 = -插入点-1
        //插入点 = -binarySearch的结果-1
        //index1即为插入点
        int index1 = -Arrays.binarySearch(listRate, x) - 1;//二分查找插入点
        System.out.println("本轮抽取到的人为:" + listStu.get(index1).getName());//被抽取到的人
        //7.修改权重
        double weight = listStu.get(index1).getWeight()/2;
        listStu.get(index1).setWeight(weight);
        //8.将listStu中的数值写回到文件中
        BufferedWriter bw = new BufferedWriter(new FileWriter("src\\FinallyTest\\name_weight.txt"));
        for (Student student : listStu) {
            bw.write(student.toString());
            bw.newLine();//换行
        }
        bw.close();
    }

    //读取文件中的数据
    private static ArrayList<String> getData(String path) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(path));
        ArrayList<String> list = new ArrayList<>();
        String elem;
        while ((elem = br.readLine()) != null) {
            list.add(elem);
        }
        br.close();
        return list;
    }
}
相关推荐
Scott9999HH4 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔4 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社5 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海5 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖6 小时前
JDK 26 新特性详解
java·开发语言
马优晨7 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区9 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大9 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai10 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说10 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json