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

发布于:2025-02-25 ⋅ 阅读:(12) ⋅ 点赞:(0)

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

作者:blue

时间:2025.2.21

0.概述

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

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

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

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

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包参考文档中的代码,与我们的源代码非常接近。

//请求列表页
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);
}

代码实现:

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(只显示名字)

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

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文件来记录程序运行的次数

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次运行的时候,我们自己不需要手动操作本地文件,要求程序自动开始第二轮点名

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

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类来管理学生对象

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

带权重的随机过程

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

网站公告

今日签到

点亮在社区的每一天
去签到