当前位置: 首页 > news >正文

Java 黑马程序员学习笔记(进阶篇26)

一、Commons-io 工具包

1. FileUtils - 文件操作工具类
(1) 作用

简化文件 / 目录的创建、复制、移动、删除、读取等操作。

方法功能示例
readFileToString(File file, String encoding)读取文件内容为字符串(指定编码)String content = FileUtils.readFileToString(new File("test.txt"), "UTF-8");
writeStringToFile(File file, String data, String encoding)写入字符串到文件(覆盖 / 追加)FileUtils.writeStringToFile(new File("test.txt"), "Hello", "UTF-8");
copyFile(File src, File dest)复制文件FileUtils.copyFile(new File("a.txt"), new File("b.txt"));
copyDirectory(File srcDir, File destDir)复制目录(含子目录和文件)FileUtils.copyDirectory(new File("dir1"), new File("dir2"));
deleteDirectory(File dir)删除目录(含所有内容)FileUtils.deleteDirectory(new File("dir"));
listFiles(File dir, String[] extensions, boolean recursive)按后缀过滤文件(递归 / 非递归)File[] files = FileUtils.listFiles(new File("dir"), new String[]{"txt"}, true);
(2) 示例:文件复制与内容读取
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;public class CommonsIoDemo {public static void main(String[] args) {File srcFile = new File("D:\\test\\source.txt");File destFile = new File("D:\\test\\dest.txt");try {// 1. 复制文件FileUtils.copyFile(srcFile, destFile);System.out.println("文件复制成功");// 2. 读取文件内容(UTF-8编码)String content = FileUtils.readFileToString(destFile, "UTF-8");System.out.println("文件内容:" + content);// 3. 追加内容到文件FileUtils.writeStringToFile(destFile, "\n追加的内容", "UTF-8", true);System.out.println("内容追加成功");} catch (IOException e) {e.printStackTrace();}}
}

二、综合练习

1. 百家姓网页数据爬取与正则分组提取
题目描述:

在名字数据处理场景中,常需要从网页提取特定格式的文本(如百家姓的四字一组格式)。本题要求你基于提供的代码框架,实现一个程序,从指定的百家姓网页中爬取内容,并通过正则表达式的分组功能提取目标数据。

具体需求:

(1) 爬取目标:从百家姓网页(https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0)爬取网页源码,同时预留对男生名字网页(http://www.haoming8.cn/baobao/10881.html)和女生名字网页(http://www.haoming8.cn/baobao/7641.html)的爬取接口。

(2) 核心功能

  • 完善 webCrawler 方法:通过 URL 和 URLConnection 建立网络连接,使用 InputStreamReader 将网页字节流转换为字符流,读取并返回网页的文本内容。
  • 完善 getData 方法:接收网页源码、正则表达式和分组索引,使用 Pattern 和 Matcher 进行正则匹配,提取匹配结果中指定分组的内容,存入 ArrayList<String> 并返回。
  • 在 main 方法中,调用上述方法从百家姓网页提取 “四字一组” 的内容(如 “赵钱孙李”“周吴郑王”),正则表达式已指定为 (\\W{4})(,|。),需提取第一个分组(索引为 1)的内容,并打印结果。

技术要求

  • 必须使用 java.net 包中的 URL 和 URLConnection 类实现网络通信。
  • 使用 InputStreamReader 处理字符流读取,确保网页文本正确解析。
  • 理解正则表达式的分组机制:(\\W{4}) 为第一个分组(目标提取内容),(,|。) 为第二个分组,分组索引从 1 开始。
  • 正确处理 IO 异常,确保流资源关闭;集合需准确存储提取的目标数据。
提示:
  • URL url = new URL(net) 用于将 URL 字符串转换为可操作的 URL 对象,是网络连接的入口。
  • InputStreamReader isr = new InputStreamReader(conn.getInputStream()) 负责将网络字节流转换为字符流,支持文本内容的直接读取。
  • matcher.group(index) 用于获取正则匹配中第index个分组的内容,本题需提取第一个分组(四字部分)。
输出要求:

程序运行后,需打印从百家姓网页中提取的所有 “四字一组” 内容(如[赵钱孙李, 周吴郑王, ...])。

package demo3;import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class test1 {public static void main(String[] args) throws IOException {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";String familyNameStr = webCrawler(familyNameNet);String boyNameStr = webCrawler(boyNameNet);String girlNameStr = webCrawler(girlNameNet);ArrayList<String> familyNameTempList = getData(familyNameStr,"(\\W{4})(,|。)",1);  // 不太理解System.out.println(familyNameTempList);}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;}public static String webCrawler(String net) throws IOException {StringBuilder sb = new StringBuilder();URL url = new URL(net);  // 不太理解URLConnection conn = url.openConnection();InputStreamReader isr = new InputStreamReader(conn.getInputStream());  // 不太理解int ch;while ((ch = isr.read()) != -1) {sb.append((char) ch);}isr.close();return sb.toString();}
}
关键逻辑 1:正则表达式 (\\W{4})(,|。) 是什么意思?

① (\\W{4})

  • \\W 是正则表达式的元字符,表示 “非单词字符”(在中文场景下可匹配汉字,因为汉字不属于字母 / 数字 / 下划线)。
  • {4} 表示匹配前面的字符(这里是\\W)4 次。
  • 括号 () 表示 “分组”,这部分是第一个分组(分组索引从 1 开始),目标是匹配 “4 个汉字”(比如 “赵钱孙李”“周吴郑王”)。

② (,|。)

  • | 表示 “或”,匹配 “,”(中文逗号)或 “。”(中文句号)。
  • 括号 () 是第二个分组,匹配的是四字后面的标点符号。
关键逻辑 2:index=1 为什么要传 1?

getData 方法中用 matcher.group(index) 获取匹配结果,这里的 index 对应正则表达式中的 “分组索引”:

  • 分组索引从 1 开始,group(1) 对应第一个分组 (\\W{4})(4 个汉字);
  • group(2) 对应第二个分组 (,|。)(标点符号);
  • group(0) 对应整个匹配的完整字符串(比如 “赵钱孙李,”)。
关键逻辑 3:URL url = new URL(net);

这行代码是将字符串格式的网页地址转换为可操作的 URL 对象,是网络爬虫的 “入口”。

  • net 是传入的网页地址字符串(比如"https://hanyu.baidu.com/..."),但字符串本身无法直接用于网络连接,需要转换为 Java 能识别的URL对象。
  • URL 类是 Java 提供的用于处理 “统一资源定位符”(即网页地址)的工具类,它封装了 URL 的解析、协议(http/https)、主机名、端口等信息,后续可以通过这个对象建立网络连接。
关键逻辑 4:InputStreamReader isr = new InputStreamReader(conn.getInputStream());

这行代码是将网络字节流转换为字符流,方便读取网页的文本内容(源码)。

  • 先看 conn.getInputStream()conn 是通过 url.openConnection() 建立的网络连接对象,getInputStream() 会从这个连接中获取 “字节输入流”(网页内容在网络中传输时是以字节形式存在的)。

  • 再看 InputStreamReader:字节流(InputStream)只能按字节读取数据,而网页源码是文本(比如 HTML 标签、中文文字),需要按 “字符” 处理(比如一个汉字可能占 2 个字节)。InputStreamReader 是 “字节流→字符流” 的转换桥梁,它会根据默认编码(或指定编码)把字节转换为字符,方便后续用 read() 方法按字符读取。

2. 题目:学生体重加权随机抽样与数据更新
题目描述:

在学生数据处理场景中,常需要根据特定权重(如体重)进行随机抽样,并对抽样结果进行数据修改。本题要求你基于提供的代码框架,实现一个程序,从指定文件中读取学生信息,通过加权随机抽样算法选中目标学生,修改其体重后将数据写回文件。

具体需求:

(1) 数据读取目标:从 names.txt 文件中读取学生信息,文件中每行格式为 姓名-性别-年龄-体重(例如:张三-男-20-50.0),预留对男生名字文件(如 boys.txt)和女生名字文件(如 girls.txt)的读取接口。

(2) 核心功能:

  • 完善 readStudentData 方法:通过 BufferedReader 和 FileReader 建立文件连接,读取文件内容并解析为 Student 对象,存入 ArrayList<Student> 并返回。
  • 完善 weightedRandomSelect 方法:接收学生列表,计算所有学生的体重总和,构建体重占比的概率区间数组,生成随机数并通过 Arrays.binarySearch 确定选中学生的索引,返回该索引。
  • 完善 updateAndWriteBack 方法:接收学生列表和选中索引,将对应学生的体重减半,使用 BufferedWriter 将更新后的所有学生信息写回原文件。
  • 在 main 方法中,调用上述方法从 names.txt 提取学生数据,通过加权随机抽样选中学生,打印选中结果,修改体重并写回文件。
技术要求:
  • 必须使用 java.io 包中的 BufferedReader 和 BufferedWriter 类实现文件读写。
  • 使用 ArrayList 存储 Student 对象,确保数据的动态管理。
  • 理解加权随机抽样的核心逻辑:体重总和计算、概率区间构建、Arrays.binarySearch 的返回值处理。
  • 正确处理 IO 异常,确保流资源关闭;数据解析时需处理字符串分割和类型转换。
提示:
  • BufferedReader br = new BufferedReader(new FileReader("names.txt")) 用于建立文件读取连接,是文件数据读取的入口。
  • String[] arr = line.split("-") 负责将每行文件内容按 - 分割为学生信息数组,需注意数组长度校验。
  • Arrays.binarySearch(arr, number) 的返回值处理:未找到时返回 -插入点-1,通过公式 -返回值-1 可获取正确索引。
package demo4;import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;public class test2 {public static void main(String[] args) throws IOException {ArrayList<Student> list = new ArrayList<>();BufferedReader br = new BufferedReader(new FileReader("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();double weight = 0;for (Student stu : list) {weight = weight + stu.getWeight();}double[] arr = new double[list.size()];  // 不太理解int index = 0;for (Student stu : list) {arr[index] = stu.getWeight() / weight;index++;}for (int i = 1; i < arr.length; i++) {arr[i] = arr[i] + arr[i - 1];  // 不太理解}double number = Math.random();int result = -Arrays.binarySearch(arr, number) - 1;  // 不太理解Student stu = list.get(result);System.out.println(stu);double w = stu.getWeight() / 2;stu.setWeight(w);BufferedWriter bw = new BufferedWriter(new FileWriter("names.txt"));for (Student s : list) {bw.write(s.toString());bw.newLine();}bw.close();}
}
关键逻辑 1:double[] arr = new double[list.size()];
  • 作用:创建一个和学生列表 list 长度相同的 double 类型数组。
  • 用途:这个数组是一个临时容器,用来存储每个学生的 “相对权重” 或者说 “概率密度”。
关键逻辑 2:for (int i = 1; i < arr.length; i++) { arr[i] = arr[i] + arr[i - 1]; }

(1) 作用:将这个数组从一个概率数组转换成一个前缀和数组(也叫累积分布函数 CDF)。

(2) 这是最关键的一步,我们来举例说明:

假设我们有 3 个学生,他们的体重分别是:

  • 学生 A:体重 = 100.0
  • 学生 B:体重 = 200.0
  • 学生 C:体重 = 300.0
  • 总重量 weight = 600.0

第一步:在这个循环执行之前arr 数组存储的是每个学生体重占总重量的比例(概率):

  • arr[0] (学生 A 的概率) = 100.0 / 600.0 ≈ 0.1667 (16.67%)
  • arr[1] (学生 B 的概率) = 200.0 / 600.0 ≈ 0.3333 (33.33%)
  • arr[2] (学生 C 的概率) = 300.0 / 600.0 ≈ 0.5 (50%)
  • 此时数组是:[0.1667, 0.3333, 0.5]

第二步:执行这个 for 循环:

① 当 i=1 时:

  • arr[1] = arr[1] + arr[0]
  • arr[1] = 0.3333 + 0.1667 = 0.5

② 当 i=2 时:

  • arr[2] = arr[2] + arr[1]
  • arr[2] = 0.5 + 0.5 = 1.0

③ 循环执行之后arr 数组变成了前缀和数组:

  • arr[0] ≈ 0.1667
  • arr[1] ≈ 0.5
  • arr[2] = 1.0
  • 此时数组是:[0.1667, 0.5, 1.0]

(3) 为什么要这么做?

  • [0, 0.1667) 这个区间对应学生 A。
  • [0.1667, 0.5) 这个区间对应学生 B。
  • [0.5, 1.0] 这个区间对应学生 C。
http://www.dtcms.com/a/611667.html

相关文章:

  • 网站开发的进度怎么写网站开发里程碑
  • Xshell终端连接Ubuntu/Debian无颜色的解决方案
  • 国外推广网站有哪些网页设计介绍北京网站
  • 贵港网站建设兼职企业做网站需要什么
  • 怎样在网站做转向连接网站建设素材模板下载
  • 音乐网站建站如何做视频网站
  • 广东宇晟建设工程有限公司网站注册公司取名推荐
  • 网站开发遵循的标准或规范陕西政务服务网
  • 平板电脑可以做网站不张家港网站网络公司
  • docker中安装conda环境
  • 网站模块顺序调整云服务器服务安全
  • 网站开发和网页上传的说法用vscode做网站
  • Bootstrap Wells
  • 网站设计中下拉列表怎么做网费一年多少钱
  • 网站主页和子页风格如何统一提升网站权重的策略
  • 却持网站招聘网站代做
  • 做代理的网站wordpress系统是什么意思
  • 网站怎么开发设计怎么在免费空间里面做网站
  • 2025甘肃省第二届数据挖掘挑战赛——融合石榴果实时序图像数据和传感监测数据的智能化果实图像病害阶段识别与病害发展演变预测
  • JAVA EE初阶 2: 多线程-初阶
  • 共享ip服务器做网站设计类专业哪个好
  • 中国建设银行官网站额度申请胶州网站建设
  • Java语言的编译和运行过程 | 深入解析Java编译、执行及常见问题
  • 如何在网上建立网站网站建设和运行遇到的问题
  • 石家庄做家教网站wordpress怎么设置发布时间
  • 自微网站首页国内最好的效果图公司
  • C++ BuilderXE 用imageENView的图片进行批量的调整对比度,亮度,锐化,美化图片
  • 个人对设计模式的一些体会
  • 站长工具问答网站 天堂资源最新版中文资源
  • 网站站外链接建立公司微信平台 网站平台