异常就是代表程序出现的问题
误区:不是让我们以后不出异常,而是程序出现异常之后,该如何处理
打人家玻璃是不对的
现在学习的不是让你以后不打别人家的玻璃
而是打碎别人家的玻璃之后该怎么处理
Erroe:代表的系统级别错误(属于严重问题)
系统一旦出现问题,sun公司会把这些错误封装成Error对象
Erroe是给sun公司自己用的,不是给我们程序员用的,
因此我们开发人员不管他
Exception:叫做异常,代表程序可能出现的问题
我们通常会用Exception以及他的子类来封装程序出现的问题
运行时异常:RuntimeException及其子类,编译阶段不会出现异常提醒
运行时出现的异常(如:数组索引越界异常)
编译时异常:编译阶段就会出现异常提醒的。(如:日期解析异常)
1、异常是什么?
程序中可能出现的问题
2、一场体系的最上层父类是谁?异常分几类?
父类:Exception
异常分为两类:编译时异常、运行时异常
3、编译时异常和运行时异常的区别?
编译时异常:没有继承RuntimeException的异常,直接继承于Exception。编译阶段就会错误提示
运行时异常:RuntimeException本身和子类
编译阶段没有错误提示,运行时出现的
String name = "2030年1月1日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date date = sdf.parse(time);
System.out.println(date);
parse正常情况下会报错,需要在main函数的后面加上throws ParseException
才能将报错取消
这就是编译时异常,在编译阶段,必须要手动处理,否则代码报错
int[] arr = {1,2,3,4,5};
System.out.println(arr[10]);
数组越界异常,标准的运行时异常,在编译阶段是不需要处理的,是代码运行时出现的异常
为什么分两种异常?
在编译阶段,java不会运行diamagnetic,只会检查语法是否错误,或者做一些性能的优化,更多的是提醒程序员检查本地信息
运行时异常就是代码出错而导致程序出现问题
运行时异常和编译时异常的区别?
编译时异常:除了RuntimeException和他的子类,其他都是编译时异常,编译阶段需要进行处理,作用在于提醒程序员
运行时异常:RuntimeException本身和所有子类,都是运行时异常,编译阶段不报错,是程序运行时出现的,一般是由参数传递错误带来的问题
作用一:异常是用来查询bug的关键参考信息
作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
public void setAge(int age){
if(age < 18 || age > 40){
throw new RuntimeException();
}else {
this.age=age;
}
}
学生类中的赋值年龄成员函数,如果是年龄小于18或者大于40的打印输出语句提示错误,只是在控制台打印出来,并不能直接告诉调用处(代码编写处)
这样就可以有两种解决方法,第一种自己处理掉问题,或者打印在控制台上
1、JVM虚拟机默认处理异常的方式
2、自己处理
3、抛出异常(交给调用者)
把异常的名称,异常原因及异常出现的位置等信息输出在了控制台上
程序停止运行,下面的代码不会再执行了
System.out.println("狂踹瘸子那条好腿");
System.out.println(2/0);
System.out.println("是秃子终会发光");
System.out.println("火鸡味锅巴");
格式:
下面展示一些 内联代码片
。
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
自己处理捕获异常的目的就是当代码出现问题的时候,可以让程序继续往下执行
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗");
灵魂一问:如果try中没有遇到问题,怎么执行?
会把try里面的代码全部执行完毕,不会执行catch里面的代码
注意:只有当出现了异常才会执行catch里面的代码
灵魂二问:如果try中可能会遇到多个问题,怎么执行?
要写多个catch与之对应
细节:如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
了解性:在JDK7之后,我们可以在catch中同时捕获多个异常,中间用|进行隔开
表示如果出现了A异常或者B异常的话,采取同一种处理方案
灵魂三问:如果try中遇到的问题没有被捕获,怎么执行?
相当于try…catch的代码白写了,最终还是会交给虚拟机进行处理
灵魂四问:如果try中遇到了问题,那么try下面的其他代码还会执行吗?
下面的代码就不会运行了,直接跳转到对应的catch当中,执行catch里面的语句体
但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
throws:
注意:写在方法定义出,表示声明一个异常
告诉调用者,使用本方法可能会有哪些异常
public void 方法()throws 异常类名1,异常类名2...{
...
}
编译时异常:必须要写
运行时异常:可以不写
throw:
注意:写在方法内,结束方法
手动抛出异常对象,交给调用者
方法中下面的代码不再执行了
public void 方法(){
throw new NullPointerException();
}
public static void main(String[] args) {
int[] arr = {};
try{
int max = getMax(arr);
}catch (NullPointerException e){
System.out.println("空指针异常");
}catch (ArrayIndexOutBoundsException e){
System.out.println("索引越界异常");
}
System.out.println(max);
}
public static int getMax(int[] arr){
if(arr == null){
//手动创建一个异常,并把这个异常交给方法的调用者处理
//此时方法就会结束,下面的代码不会再执行了
throw new NullPointerException();
}
if(arr.length == 0){
throw new ArratIndexOutOfBoundsException();
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]>max){
max = arr[i];
}
}
return max;
}
Throeable的成员方法
public String getMessage()//返回此Throwable的详细信息字符串
public String toString()//返回此可抛出的简短描述
public void printStackTrace()//把异常的错误信息输出在控制台,仅仅是打印红字信息,不会停止程序运行
1、虚拟机默认处理异常的方式
把异常信息以红色字体打印在控制台,并结束程序
2、捕获:try…catch
一般用在调用出,能让代码继续往下运行
3、抛出:throw throws
在方法中,出现异常了
方法就没有继续运行下去的意义了,采取抛出异常
让该方法结束运行并告诉调用者出现了问题
需求:
键盘录入自己心仪的女朋友姓名和年龄
姓名的长度在3~10之间
年龄的范围为18~40岁
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止
提示:
需要考虑用户在键盘录入时的所有情况
比如:录入年龄时超出范围,录入年龄时录入了abc等情况
Scanner sc = new Scanner(System.in);
GrilFriend gf = new GrilFriend();
while (true) {
try {
System.out.println("请输入你心仪的女朋友的名字");
String name = sc.nextLine();
gf.setName(name);
System.out.println("请输入你心仪的女朋友的年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
//如果所有的数据都是正确的,那么跳出循环
break;
} catch (NumberFormatException e) {
System.out.println("年龄的格式有误,请输入数字");
continue;
} catch (RuntimeException e){
System.out.println("姓名的长度 或者 年龄的范围有误");
continue;
}
}
System.out.println(gf);
public class GrilFriend {
private int age;
private String name;
public GrilFriend(int age, String name) {
this.age = age;
this.name = name;
}
public GrilFriend() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<18||age>40){
throw new RuntimeException();
}
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
int len = name.length();
if (len<3 || len>10){
throw new RuntimeException();
}
this.name = name;
}
}
创建自定义异常
1、定义异常类
2、写继承关系
3、空参构造
4、带参构造
自定义异常的意义就是为了让控制台的报错信息更加的见名知意
public class NameFormatException extends RuntimeException{
//技巧:
//NameFormat:当前异常的名字,表示姓名格式化问题
//Exception:表示当前类是一个异常类
//继承问题
//运行时异常:RuntimeException
//编译时异常:Exception 核心 提醒程序员检查本地信息
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
public class AgeOutOfBoundsException extends RuntimeException{
public AgeOutOfBoundsException() {
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
File对象就表示一个路径,可以是文件的路径、也可以是文件夹的路径
这个路径可以是存在的,也允许是不存在的
public File(String pathname)//根据文件路径创建文件对象
public File(String parent, String child)//根据父路径名字符串和子路径名字符串创建文件对象
public File(File parent, String child)//根据父路径对应文件对象和子路径名字符串创建文件对象
以“C:\Users\xiaoyou\Desktop\a.txt”为例
父级路径就是“C:\Users\xiaoyou\Desktop”
子级路径就是“a.txt”
1、File表示什么?
File对象表示路径,可以是文件、也可以是文件夹
这个路径可以是存在的,也可以是不存在的
2、绝对路径和相对路径是什么意思?
绝对路径是带盘符的
相对路径是不带盘符的,默认到当前项目下去找
3、File三种构造方法的作用
public File(String pathname)//根据文件路径创建文件对象
public File(String parent, String child)//根据父路径名字符串和子路径名字符串创建文件对象
public File(File parent, String child)//根据父路径对应文件对象和子路径名字符串创建文件对象
public boolean isDirectory()//判断路径名表示的File是否为文件夹
public boolean isFile()//判断此路径名表示的File是否为文件
public boolean exists()//判断此路径名表示的File是否存在
public long length()//返回文件的大小(字节数量)
public String getAbsolutePath()//返回文件的绝对路径
public String getPath()//返回定义文件时使用的路径
public String getName()//返回文件的名称,带后缀
public long lastModeidied()//返回文件的最后修改时间(时间毫秒值)
length细节:
细节1、
这个方法只能获取文件的大小,单位是字节
如果单位我们要是M,G可以不断地除以1024
细节2、
这个方法无法获取文件夹的大小,(0/4096)
如果我们要获取一个文件夹的大小,需要把这个文件夹里面所有的文件大小都累加在一起
getName细节:
细节1、
如果调用者是个文件,会返回文件名和后缀名
细节2、
如果调用者是文件夹,返回的就是文件夹的名字
String str = "C:\\Users\\xiaoyou\\Desktop\\信息.txt";
File f1 = new File(str);
Date date = new Date(f1.lastModified());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
System.out.println(sdf.format(date));
public boolean creatNewFile()//创建一个新的空的文件
public boolean mkdir()//创建单级文件夹
public boolean mkdirs()//创建多级文件夹
public boolean delete()//删除文件夹、空文件夹
delete方法默认只能删除文件和空文件夹,delete方法直接删除不走回收站
createNewFile细节:
细节1、
如果当前路径表示的文件是不存在的,则创建成功,方法返回true
如果当前路径表示的文件是存在的,则创建失败,方法返回false
细节2、
如果父级路径是不存在的,那么方法会有异常IOException
细节3、
createNewFile方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀名的文件
mkdir细节:
细节1、
Windows当中路径一定是唯一的,如果当前路径已经存在,则创建失败,返回false
细节2、
mkdir方法只能创建单级文件夹,无法创建多级文件夹
mkdirs细节:
即可以创建单级的,又可以创建多级的文件夹
delete细节
细节1、
如果删除的是文件,则直接删除,不走回收站
如果删除的是空文件夹,则直接删除,不走回收站
如果删除的是有内容的文件夹,则删除失败
public File[] listFiles()//获取当前该路径下所有内容
//1、创建File对象
File f = new File("D:\\aaa");
//2、listFiles方法
//作用:获取aaa文件夹里面的所有内容,把所有的内容放到数组中返回
File[] files = f.listFiles();
for (File file : files){
//file依次表示aaa文件夹里面的每一个文件或者文件夹
System.out.println(file);
}
listFiles细节
1、当调用者File表示的路径不存在时,返回null
2、当调用者File表示的路径是文件时,返回null
3、当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
4、当调用者File表示的路径是一个有内容的文件夹时,将里面所有的文件和文件夹的路径放在File数组中返回
5、当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路劲放在File数组中返回,包含隐藏文件
6、当调用者File表示的路径是需要权限才能访问的文件夹时,返回null
public static File[] listRoots()//列出可用的文件系统根
public String list()//获取当前该路径下所有内容
public String list(FilenameFilter filter)//利用文件名过滤器获取当前该路径下所有内容
public File[] listFiles()//获取当前该路径下所有内容
public File[] list(FileFilter filter)//利用文件名过滤器获取当前该路径下所有内容
public File[] listFiles(FilenameFilter filter)//利用文件名过滤器获取当前该路径下所有内容
list(FilenameFilter filter)
accept方法的形参,依次表示aaa文件夹李米娜每一个文件或者文件夹路径
参数一:父级路径
参数二:子级路径
返回值:如果返回值为true,就表示当前路径保留;如果返回值为false,就表示当前路径舍弃不要
IO流:存储和读取数据的解决方案
File:表示系统中文件或者文件夹的路径
获取文件信息(大小,文件名,修改时间)、判断文件类型、创建文件/文件夹、删除文件/文件夹…
File类只能对文本本身进行操作,不能读写文件里面存储的数据
IO流:用于读写文件中的数据(可以读写文件,或网络中的数据…)
IO流中,谁在读,谁在写?以谁为参照物看读写的方向呢?
以程序(内存)为参照物
按流的方向可以分为输入流和输出流
输入流:读取
输出流:写去
按操作文件类型可以分为字节流和字符流
字节流可以操作所有类型的文件
字符流只能操作纯文本文件
纯文本文件:Windows自带的记事本打开能读懂
1、什么是IO流?
存取和读取数据的解决方案
I:input
O:output
流:像水流一样传输数据
2、IO流的作用?
用于读写数据(本地文件,网络)
3、IO流按照流向可以分类哪两种流?
输出流:程序---->文件
输入流:文件---->程序
4、IO流按照操作文件的类型可以分类哪两种流?
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
5、什么是纯文本文件?
用Windows自带的记事本打开能读懂
txt文件,md文件,xml文件,lrc文件等
FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
书写步骤
1、创建字节输出流对象
2、写数据
3、释放资源
FileOutStream fos = new FileOutputStream("myio//a.txt");
fos.write(97);
fos.close();
FileOutputStream的原理
FileOutputStream就是创建了一个程序与文件之间的通道,
write就是将书写的内容通过通道传输到文件之中
close就是再将这个连接的通道“敲碎”
1、创建字节输出流对象
细节1:参数是字符串表示的路径或者是File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件
2、写数据
细节:write方法的参数是整数,但是实际上写道本地文件中的是整数在ASCII上对应的字符
3、释放资源
每次使用完流之后都要释放资源,就是将文件从内存运行中停止,这样后续就能够继续操作文件了,不然是操作不了的
void write(int b)//一次写一个字节数据
void write(byte[] b)//一次写一个字节数组数据
void write(byte[] b, int off, int len)//一次写一个字节数组的部分数据
关于wirte的第三种使用
参数一:数组
参数二:起始索引
参数三:个数
写数据的两个小问题:想要换行写以及再次写不会清空而是继续写的续写
换行写:
再次写出一个换行符就可以了
windows:\r\n
Linux:\n
Mac:\r
细节:
在Windows操作系统当中,java对回车换行进行了优化,
虽然完整的是\r\n,但是我们写其中一个\r或者\n就可以
java也可以实现换行,因为java在底层会补全
建议:不要省略,还是写全了
续写:
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true:表示打开续写,此时创建对象不会清空文件
FileOutputStream fos = new FileOutputStream("myrio\\a.txt");
Stirng str = "laozizhengshuai";
byte[] bytes = str.getBytes();
fos.write(bytes);
String wrap = "\r\n";
byte[] bytes2 = wrap.getBytes();
fos.write(bytes2);
String str2 = "666";
byte[] byte3 = str2.getBytes();
fos.write(bytes3);
fos.close();
1、FileOutputStream的作用
可以把程序中的数据写到本地文件上,是字节流的基本流
2、书写步骤
创建对象,写出数据,释放资源
3、三步操作的细节
创建对象:文件存在、文件不存在、追加写入
写出数据:写出整数、写出字节数组、换行写
释放资源:关闭通道
FileInputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来
书写步骤:
1、创建字节输入流对象
2、读数据
3、释放资源
FileInputStream fis = new FileInputStream("巴拉巴拉路径");
int b1 = fis.read();//只能读取一个字符,读不到了就返回-1
System.out.println(b1);
fis.close();
1、创建字节输入流对象
细节:如果文件不存在,就直接报错
java为什么会这么设计呢?
输出流:不存在,创建——把数据写到文件当中
输入流:不存在,而是报错?
因为创建出来的文件是没有数据的,没有任何意义。
所以java就没有设计这种无意义的逻辑,文件不存在直接报错
程序中最重要的是:数据。
2、读取数据
细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字
细节2:读到文件末尾了,read方法返回-1。
3、释放资源
细节:每一次使用完流必须要释放资源
FileInputStream fis = new FileInputStream("巴拉巴拉路径");
int b;
while((b == fis.read()) != -1){
System.out.println((char)b);
}
fis.close();
IO流:如果拷贝的文件过大,那么速度会不会有影响?
当然,会很慢
FileInputStream一次读写一个字节
弊端:一次读写一个字节,太慢了
File InputStream一次读取多个字节:
public int read()//一次读一个字节数据
public int read(byte[] buffer)//一次读一个字节数组数据
注意:一次读一个字节数组的数据,每次读取会尽可能把数组装满
数组的长度一般都是1024的整数倍
//1、创建对象
FileInputStreamfis = new FileInputStream("巴拉巴拉路径");
//2、读取数据
byte[] bytes = new byte[2];
//一次读取多个字节数据,具体读多少,跟数组的长度有关
//返回值:本次读取到了多少个字节数据
int len = fis.read(bytes);
System.out.println(len);//2
String n str = new String(bytes);
System.out.println(str);
//3、释放资源
fis.close();
注意:先选择一个比较小的文件,不要太大
//1、创建对象
FileInputStream fis = new FileInputStream("巴拉巴拉路径");
FileOutputStream fos = new FileOutputStream("巴啦啦路径");
//2、拷贝
//核心思想:边读边写
int b;
while((b = fis.read()) != -1){
fos.write(b);
}
//3、释放资源
//规则:先开的最后关闭
fos.close();
fis.close()
//1、创建对象
FileInputStream fis = new FileInputStream("巴拉巴拉路径");
FileOutputStream fos = new FileOutputStream("巴拉巴拉路径");
//2、拷贝
int len;
byte[] bytes = new byte[1024*1024*5];
while((len = fis.read(bytes)) != -1){
fos.wirte(bytes,0,len);
}
//3、释放资源
fos.close();
fis.close();
//实践代码
FileInputStream fis = new FileInputStream("C:\\Users\\xiaoyou\\Desktop\\宝的照片\\306751AF0EAB631BBBFAC17471282421.png");
FileOutputStream fos = new FileOutputStream("C:\\Users\\xiaoyou\\Desktop\\copy.png");
int len;
byte[] bytes=new byte[1024*1024*5];
while((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
老版本try…catch下面还有个finally
特点:finally里面的代码一定被执行,除非虚拟机停止,除非JVM推出
将扫尾代码放到finally之中
FileInputStream fis=null;
FileOutputStream fos=null;
try {
fis = new FileInputStream("C:\\Users\\xiaoyou\\Desktop\\宝的照片\\306751AF0EAB631BBBFAC17471282421.png");
fos = new FileOutputStream("C:\\Users\\xiaoyou\\Desktop\\copy.png");
int len;
byte[] bytes=new byte[1024*1024*5];
while((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if (fos != null){
try {
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
if (fis != null){
try {
fis.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
//jdk7的写法
//try后面的小括号中写创建对象的代码
//注意:只有实现了AutoCloseable接口的类,才能在小括号中创建对象
try(FileInputStream fis = new FileInputStream("C:\\Users\\xiaoyou\\Desktop\\宝的照片\\306751AF0EAB631BBBFAC17471282421.png");
FileOutputStream fos = new FileOutputStream("C:\\Users\\xiaoyou\\Desktop\\copy.png");){
int len;
byte[] bytes=new byte[1024*1024*5];
while((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
}catch (IOException e){
e.printStackTrace();
}
//JDK9:IO流中捕获异常的写法
FileInputStream fis = new FileInputStream("C:\\Users\\xiaoyou\\Desktop\\宝的照片\\306751AF0EAB631BBBFAC17471282421.png");
FileOutputStream fos = new FileOutputStream("C:\\Users\\xiaoyou\\Desktop\\copy.png");
try(fis,fos){
int len;
byte[] bytes=new byte[1024*1024*5];
while((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
}catch (IOException e){
e.printStackTrace();
}
计算机存储规则:在计算机中,任意数据都是以二进制的形式来存储的
GB2312,1980年发布,1981年5月1日实施的简体中文汉字编码国家标准
收录了7445个图形字符,其中包括6763个简体汉字
有趣的冷知识
BIG5字符集:台湾地区繁体中文标准字符集,共收录13053个中文字,1984年实施。
GBK字符集
2000年3月17日发布,共收录21003个汉字,包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字
windows系统默认使用的就是GBK(系统显示:ANSI)
Unicode字符集:国际标准字符集,它将世界各种语言的每一个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换
128个数据(对于西方的sucker来说足够使用了)
存储英文的时候一个字节就足以
ASCII编码规则:前面补0,补齐8位
解码直接转,前面补不补零无所谓
英文用一个字节存储,完全兼容ASCII
GBK英文编码规则:不足8位,前面补0
汉字:两个字节存储
前面的字节叫做高位字节
后面的字节叫做低位字节
高位字节二进制一定以1开头,转成十进制之后是一个负数
汉字编码规则:不需要变动
1、在计算机中,热议数据都是以二进制的形式来存储的
2、计算机中最小的存储单元是一个字节
3、ASCII字符集中,一个英文占一个字节
4、简体中文版Windows,默认使用GBK字符集
5、GBK字符集完全兼容ASCII字符集
一个英文占一个字节,二进制第一位是0
一个中文占两个字节,二进制高位字节的第一位是1
万国码
研发方:统一码联盟(也叫Unicode组织)
总部位置:美国加州
研发时间:1990年
发布时间:1994年发布1.0版本,期间不断添加新的蚊子
最新的版本是2022年9月13日发布的15.0版本
联盟组成:世界各地主要的电脑制造商、软件开发商、数据库开发商、政府部门、研究机构、国际机构及个人组织
UTF-8编码规则:用1~4个字节保存
ASCII一个字节
叙利亚文两个字节
简体中文三个字节
其他语言四个字节
1、Unicode字符集的UTF-8编码格式
一个英文占一个字节,二进制第一位是0,转成十进制是正数
一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
原因1:读取数据时未读完整个汉字
原因2:编码和解码时的方式不统一
不要用字节流读取文本文件
编码解码使用同一个码表,同一个编码方式
编码的方法
public byte[] getBytes()//使用默认方式进行编码
public byte[] getBytes(String charsetName)//使用指定方式进行编码
解码的方法
String(byte[] bytes)//使用默认方式进行解码
String(byte[] bytes, String charsetName)//使用指定方式进行解码
String str = "ai你哟";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
System.out.println(Arrays.toString(bytes));//[97, 105, -28, -67, -96, -27, -109, -97]
String str2 = new String(bytes);
System.out.println(str2);
字符流的底层其实就是字节流
字符流=字节流+字符集
特点:
输入流:一次读一个字截,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中
使用场景
对于纯文本进行读写操作
1、创建字符输入流对象
public FileReader(File file)//创建字符输入流关联本地文件
public FileReader(String pathname)//创建字符输入流关联本地文件
如果文件不存在,就直接报错
2、读取数据
public int read()//读取数据,读到末尾返回-1
public int read(char[] buffer)//读取多个数据,读到末尾返回-1
按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个整数
读到文件末尾了,read方法返回-1
3、释放资源
public int close()//释放资源/关流
FileReader fr = new FileReader("巴拉巴拉路径");
int ch;
while((ch = fr.read()) != -1){
System.out.print(ch);
}
fr.close();
读取出来的是一堆数字
read()细节
1、read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
2、在读取之后:方法的底层还会进行解码并转成十进制,最终把这个十进制作为返回值,这个十进制也表示在字符集上的数字
想看见中文汉字,还得把这些十进制数字进行强转
//空参
FileReader fr = new FileReader("");
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
fr.close();
reade(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中
//有参
FileReader fr = new FileReader("巴拉巴拉路径");
char[] chars = new char[2];
int len;
while((len = fr.read(chars)) != -1){
System.out.print(new String(chars,0,len));
}
fr.close();
FileWriter构造方法
public FileWriter(File file)//创建字符输出流关联本地文件
public FileWriter(String pathname)//创建字符输出流关联文件
public FileWriter(File file,boolean append)//创建字符输出流关联本地文件,续写
public FileWriter(String, boolean append)//创建字符输出流关联本地文件,续写
FileWriter成员方法
void write(int c)//写出一个字符
void write(String str)//写出一个字符串
void write(string str, int off, int len)//写出一个字符串的一部分
void write(char[] cbuf)//写出一个字符数组
void write(char[] cbuf, int off, int len)//写出字符数组的一部分
FileWriter书写细节
1、创建字符输出流对象
细节1:参数是字符串表示的路径或者File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件,但是不想清空可以打开续写开关
2、写数据
细节:如果write方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符
3、释放资源
细节:每次使用完流之后都要释放资源
FileWriter fw = new FileWriter("C:\\Users\\xiaoyou\\Desktop\\demo.txt");
fw.write("阿巴阿巴");
fw.close();
FileWriter fw = new FileWriter("C:\\Users\\xiaoyou\\Desktop\\demo.txt");
char[] chars ={'a','c','e','q'};
fw.write(chars);
fw.close();
底层自带了长度为8192的缓冲区提高性能
public BufferedInputStream(InuputStream is)//把基本流包装成高级流,提高读取数据的性能
public BufferedOutputStream(OutputStream os)//把基本流包装成高级流,提高写出数据的性能
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(""));
BufferedOutputStream bos = new BufferedOutputStream(FileOutputStream(""));
int b;
while((b = bis.read()) != -1){
bos.write(b);
}
bos.close();
bis.close();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(""));
BufferedOutputStream bos = new BufferedOutputStream(FileOutputStream(""));
byte[] bytes = new byte[1024];
int b;
while((b = bis.read(bytes)) != -1){
bos.write(bytes,0,b;
}
bos.close();
bis.close();
底层自带了长度为8192的缓冲区提高性能
字符缓冲流的构造方法
public BufferedReader(Reader r)//把基本流变成高级流
public BufferedWrite(Writer r)//把基本流变成高级流
public String readLine()//读取一行数据,如果没有数据可读了,会返回null
public void newLine()//跨平台的换行(不同的操作系统换行的代码不一样)
BufferedReader br = new BufferedReader(new FileReader(""));
String line = br.readLine();
System.out.println(line);
br.close();
细节:readline方法在读取的时候,一次读一整行,遇到回车换行结束,但是他不会把回车换行读到内存当中
BufferedReader br = new BufferedReader(new FileReader(""));
String line;
while(((line = br.readLine()) != null){
System.out.println(line);
}
br.close();
BufferedWriter bw = new BufferedWriter(new FileWriter(""));
bw.write("你嘴角上扬的样子,百度搜索不到");
bw.newLine();
bw.write("以后如果我结婚了,你一定要来哦,没有新娘我会很尴尬");
bw.newLine();
bw.close();
1、缓冲流有几种?
字节缓冲输入流:BufferedInputStream
字节缓冲输出流:BufferedOutputStream
字符缓冲输入流:BufferedReader
字符缓冲输出流:BufferedWrite
2、缓冲流为什么能提高性能
缓冲流自带8KB缓冲区
可以显著提高字节流的读写性能
对于字符流提升不明显,对于字符缓冲流而言关键点是两个特有的方法
3、字符缓冲流两个特有的方法是什么?
字符缓冲输入流BufferedReader:readLine()
字符缓冲输出流BufferedWriter:newLine()
作用1:指定字符集读写(已淘汰
作用二:字节流想要使用字符流中的方法
需求:利用转换流按照指定字符编码读取
InputStreamReader isr = new InputStreamReader(new FileInputStream(""),"GBK");
int ch;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
isr.close();
FileReader fr = new FileReader("",Charset.forName("GBK"));
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
fr.close();
需求:利用转换流按照指定字符编码写出
OutputSreamWriter osw = new OutputStreamWriter(new FileOutputStream(""),"GBK");
osw.write("你好你好");
osw.close();
FileWriter fw = new FileWriter("",Charset.forName("GBK"));
fw.write("你好你好");
fw.close();
需求:将本地文件中的GBK文件,转成UTF-8
InputStreamReader isr = new InputStreamReader(new FileInputStream(""),"GBK");
OutputStreamReader osr = new OutputStreamReader(new FileOutputStream(""),"UTF-8");
int b
while((b = isr.read()) != -1){
osw.write(b);
}
osw.close();
isr.close();
FileReader fe = new FileReader("",Charset.forName("GBK"));
FileWriter fw = new FIleWriter("",Charset.forName("UTF-8"));
int b;
while((b = fe.read()) != -1){
fw.write(b);
}
fw.close();
fr.close();
可以把java中的对象写到本地文件中
public ObjectOutputStream(OutputStream out)//把基本流包装成高级流
public final void writeObject(Object obj)//把对象序列化(写出)到文件中去
Student stu = new Student("zhangsan",23);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(""));
oos.writeObject(stu);
oos.close();
序列化流的小细节
使用对象输出流将对象保存到文件时会出现NotSerializableException异常
解决方案:需要让Javabean类实现Serializable接口
关于Serializable接口
它里面是没有抽象方法的,标记型接口
一旦实现了这个接口,那么就表示当前的Student类可以被序列化
(一个物品的合格证)
可以把序列化到本地文件中的对象,读取到程序中来
public ObjectInputStream(InputStream out)//把基本流变成高级流
public Object readObject()//把序列化到本地文件中的对象,读取到程序中来
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(""));
Object o = ois.readObject();
System.out.println(o);
ois.close();
当使用序列化流存储信息时会附加上一个计算出来的版本号,如是对序列化信息进行修改,版本号会进行改变,而存储的版本号不变,两者不相同,代码报错
原因:文件中的版本号,跟Javabean的版本号不匹配
解决方案:手动固定版本号
private static final long serialVersionUID = 1L;
第二种方法,在这两个打勾的地方加上勾,系统会自动为其加上固定的版本号
第三种方法,抄别人的(ctrl+n,搜索已经定义好的类,抄类的版本号,不过那个是定义好的类的,需要改一改)
transient:瞬态关键字
作用:不会把当前属性序列化到本地文件中
1、使用序列化流将对象写到文件时,需要让Javabean类实现Serializable接口
否则,会出现NotSerializableException异常
2、序列化流写到文件中的数据是不能修改的,一旦修改就无法再次读回来了
3、序列化对象后,修改了Javabean类,再次反序列化,会不会有问题?
会出现问题,会抛出InvalidClassException异常
解决方案:给Javabean类添加serialVersionUID(序列号版本号)
4、如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
解决方案:给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
打印流一般是指:PrintStream,PrintWriter两个类
特点1:打印流之操作文件目的地,不操作数据源
特点2:特有的写出方法可以实现,数据原样写出
特点3:特有的写出方法,可以实现自动刷新,自动换行
打印一次数据 = 写出+换行+刷新
//构造方法
public PeintStream(OutputStream/File/Stirng)//关联字节输出流/文件/文件路径
public PrintStream(String fileName, Charset charset)//指定字符编码
public PrintStream(OutputStream out, boolean autoFlush)//自动刷新
public PrintStream(OutputStream out, boolean autoFlush, Stirng encoding)//指定字符编码切自动刷新
字节流底层没有缓冲区,开不开自动刷新都一样
//成员方法
public void write(int b)//常规方法:规则跟之前一样,将指定的字节写出
public void println(Xxx xx)//特有方法:打印任何数据,自动刷新,自动换行
public void print(Xxx xx)//特有方法:打印任意数据,不换行
public void printf(Stirng format, Object... args)//特有方法:带有占位符的打印语句,不换行
PrintStream ps = new PrintStream(new FileOutputStream(""),true,Charset.forName("UTF-8"));
ps.println(97);//写出+自动刷新+自动换行
ps.print(true);
ps.printf("%s 爱上了%s","阿珍","阿强");
ps.close();
字符流底层有缓冲区,想要自动刷新需要开启
//成员方法
public PrintWriter(Write/File/String)//关联字节输出流/文件/文件路劲
public PrintWriter(String fileName, Charset charset)//指定字符编码
public PrintWriter(Write w, boolean autoFlush)//自动刷新
public PrintWriter(OutStream out, boolean autoFlush, Charset charset)//指定字符编码且自动刷新
//构造方法
public void write(...)//常规方法:规则跟之前
public void println(Xxx xx)//特有方法:打印任意类型的数据并且换行
public void print(Xxx xx)//特有方法:打印任意类型的数据,不换行
public void printf(String format, Object... args)//特有方法:带有占位符的打印语句
PrintWriter pw = new PrintWriter(new FileWriter("",true));
pw.println("今天你终于叫我名字了,虽然叫错了,但是没关系,我马上改");
pw.print("Hello");
pw.printf("%s 爱上了%s\",\"阿珍\",\"阿强");
pw.close();
//获取打印流的对象,此打印流在虚拟机启动的时候,由虚拟机创建,默认指向控制台
//特殊的打印流(标准输出流),系统中的标准输出流,是不能关闭的,在系统中是唯一的
PrintStream ps = System.out;
//调用打印流中的方法println
//写出苏剧,自动换行,自动刷新
ps.println("123")
1、打印流有几种?各自有什么特点?
有字节打印流和字符打印流两种
打印流不操作数据源,只能操作目的地
字节打印流:默认自动刷新,特有的println自动换行
字符打印流:自动率先你需要开,特有的println自动换行
解压的本质:把每一个ZipEntry按照层级拷贝到本地另一个文件夹中
public static void main(Stirng[] args){
//解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中
//创建一个解压缩流用来读取压缩包中的数据
File src = new File("***.zip");
//要先获取到压缩包里面的每一个zipentry对象
//表示当前在压缩包中获取到的文件或者文件夹
File dest = new File("***");
}
public static void unzip(File src,File dest) throws IOException{
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
ZipEntry entry;
while((entry = zip.getNetxtEntry()) != null){
System.out.println(entry);
if(entry.isDirectory()){
//文件夹:需要在目的地dest处创建一个同样的文件夹
Fi le file = new File(dest, entry.toStirng());
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();
}
}
}
压缩里面的每一个文件或文件夹都是一个ZipEntry对象
压缩本质:把每一个(文件/文件夹)看作ZipEntry对象放到压缩包中
把一个txt文件打包成一个压缩包
public static void main(String[] args){
//1、创建FIle对象表示要压缩的文件
File src = new File("**");
//2、创建File对象表示压缩包的文件
File dest = new File("**");
//3、调用方法用来压缩
toZip(src,dest);
}
//作用:压缩
///参数一:表示要压缩的文件
//参数二:表示压缩包的位置
Public static void toZip(File src, File dest){
//1、创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));
//2、创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
//参数:压缩包里面的路径
ZipEntry entry = new ZipEntry("a.txt");
//3、把ZipEntry对象放到压缩包当中
zos.putNextEntry(entry);
FileInputStream fis = new FileInputStream(src);
int b;
while((b = fis.read()) != -1){
zos.write(b);
}
zos.closeEntry();
zos.close();
}
public static void main(String[] args){
//1、创建File对象表示要压缩的文件
File src = new File("***");
//2、创建File对象表示压缩包放在哪里(压缩包的父级路径)
File destParent = src.getParentFile();
//3、创建File对象表示压缩包的路径
File dest = new File(destParent,src.getName()+".zip");
//4、创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
//5、获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
toZip(src,zos,src.getName);
//6、释放资源
zos.close();
}
//作用:获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
//参数一:数据源
//参数二:压缩流
//参数三:压缩包内部的路径
public static void toZip(File src, ZipOutputStream zos, String name){
//
for(File file : files){
if(file.isFile()){
ZipEntry entry - new ZipEntry(name+"\\"+file.getName());
zos.putNextEntry(entry);
FIleInputStream fis = new FileInputStream(file);
int b;
while((b = fis.read()) != -1){
zos.write(b);
}
fis.close();
zos.closeEntry();
}else{
toZip(file,zos,name+"\\"+file.getName());
}
}
Commons-io是apache开源基金组织提供的一组有关IO操作的开源工具包
作用:提高IO流的开发效率
1、在项目中创建一个文件夹:lib
2、将jar包复制粘贴到lib文件夹
3、右键点击jar包,选择Add as Library ->点击ok
4、在类中导包使用
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)//写出数据
copyDirectoryToDirectory是将目标文件拷贝到指定文件里面
public static int copy(InputStream input, OutputSream output)//复制文件
public static int copyLarge(Reader input, Writer output)//复制大文件
public static String readLines(Reader input)//读取数据
public static void write(String data, OutputStream output)//写出数据
官网:commons-io下载官网
下载完成以后需要放进代码块中并进行导入
选中commons-io包,右键点击“添加为库”,无脑确定确定确定确定,还有这个。java,准备起飞
导入成功以后,jar包前会有这个标志
File src = new File("***");
File dest = new File("***");
FileUtils.copyFile(src,dest);
GitHub国际性的代码托管平台,最大的同性交友网站(正经的)
hutool是俺们天朝大国滴,也称为糊涂包,男的糊涂
相关类:
IoUtil————————流操作工具类
FileUtil———————文件读写和操作的工具类
FileTypeUtil—————文件雷子那个判断工具类
WatchMonitor————目录、文件监听
ClassPathResource—针对ClassPath中资源的访问封装
FileReader—————封装文件读取
FileWriter——————封装文件写入
Hutool官网:Hutool官网————没什么大用
API文档:API帮助文档
中文使用文档:中文使用文档
file:根据参数创建一个file对象
touch:根据参数创建文件
writeLines:把集合中的数据写出到文件中,覆盖模式
appendLines:把集合中的数据写出到文件中,续写模式
readLines:指定字符编码,把文件中的数据,读到集合中
readUtf8Lines:按照UTF-8的形式,把文件中的和数据,读到集合中去
copy:拷贝文件或者文件夹
File file = FileUtil.file("D:\\", "aaa", "bbb", "a.txt");
System.out.println(file);//D:\aaa\bbb\a.txt
File touch = FileUtil.touch(file);
System.out.println(touch);
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa");
list.add("aaa");
File file2 = FileUtil.writeLines(list, "***", "UTF-8");
System.out.println(file2);
需求:制造假数据也是开发中的一个能力,在各个网上爬取数据,是其中的一个方法
获取姓氏:
https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0
男生名字
http://www.haoming8.cn/baobao/10881.html
女生名字
http://www.haoming8.cn/baobao/7641/html
第一部:
import cn.hutool.core.io.FileUtil;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) throws IOException {
//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);
System.out.println(familyNameTempList);
}
//作用:根据正则表达式获取字符串中的数据
//参数一:完整的字符串
//参数二:正则表达式
//参数三:获取的部分
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();
}
}
第二版
import cn.hutool.core.io.FileUtil;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) throws IOException {
//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 girlNameTempList = getData(girlNameStr,"(..){4}..",0)
//4、处理数据
ArrayList<String> familyNameList = new ArrayList<>();
for (String str : familyNameTempList){
for (int i = 0; i < str.length() ; i++) {
char c = str.charAt(i);
familyNameList.add(c+"");
}
}
//男名去重
ArrayList<String> boyNameList = new ArrayList<>();
for (String str : boyNameList){
if(boyNameList.contains(str)){
boyNameList.add(str);
}
}
//女名将每一个元素用空格进行切割,得到每一个女生的名字
ArrayList<String> girlNameList = new ArrayList<>();
for (String str : girlNameList) {
String[] arr = str.split(" ");
for (int i = 0; i < arr.length; i++) {
girlNameList.add(arr[i]);
}
}
}
//作用:根据正则表达式获取字符串中的数据
//参数一:完整的字符串
//参数二:正则表达式
//参数三:获取的部分
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();
}
}
最终版
import cn.hutool.core.io.FileUtil;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) throws IOException {
//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 girlNameTempList = getData(girlNameStr,"(..){4}..",0)
//4、处理数据
ArrayList<String> familyNameList = new ArrayList<>();
for (String str : familyNameTempList){
for (int i = 0; i < str.length() ; i++) {
char c = str.charAt(i);
familyNameList.add(c+"");
}
}
//男名去重
ArrayList<String> boyNameList = new ArrayList<>();
for (String str : boyNameList){
if(boyNameList.contains(str)){
boyNameList.add(str);
}
}
//女名将每一个元素用空格进行切割,得到每一个女生的名字
ArrayList<String> girlNameList = new ArrayList<>();
for (String str : girlNameList) {
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);
System.out.println(list);
}
//作用:获取男生和女生的信息:张三-男-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);
boyhs.add(familyNameList.get(0)+girlNameList.get(0));
}
ArrayList<String> list = new ArrayList<>();
Random r = new Random();
for (String boyName : boyhs) {
int age = r.nextInt(10) + 18;
list.add(boyName+"-男-"+age);
}
for (String girlName : girlhs) {
int age = r.nextInt(8) + 18;
list.add(girlName+"-女-"+age);
}
return list;
}
//作用:根据正则表达式获取字符串中的数据
//参数一:完整的字符串
//参数二:正则表达式
//参数三:获取的部分
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();
}
}
糊涂包爬取数据
//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})(,|。)", familyNameNet, 1);
List<String> boyNameTempList = ReUtil.findAll("[\\\\u4E00-\\\\u9FA5]{2})(、|。)", boyNameStr, 1);
List<String> girlNameTempList = ReUtil.findAll("(..){4}..", girlNameStr, 1);
需求:
txt文件中实现准备好一些学生信息,每个学生的信息独占一行
要求1:每次被点到的学生,再次被点到的概率在原先的基础上降低一半
举例:80个学生,点名5次,每次都点到小A,概率变化情况如下
第一次每人概率:1.25%
第二次小A概率:0.625%————其他学生概率:1.2579%
第三次小A概率:0.3125%———其他学生概率:1.261867%
第四次小A概率:0.15625%———其他学生概率:1.2638449%
package com.example.demo;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
public class Text {
public static void main(String[] args) throws IOException {
//1、把文件中所有的学生信息读取到内存中
ArrayList<Student> list = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader("####"));
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 += stu.getWeight();
}
//3、计算每一个人的实际占比
double[] arr = new double[list.size()];
int index = 0;
for (Student stu : list) {
arr[index++] = stu.getWeight() / weight;
}
//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);
//6、修改当前学生的权重
double w = stu.getWeight()/2;
stu.setWeight(w);
//7、把集合中的数据再次写到文件中
BufferedWriter bw = new BufferedWriter(new FileWriter("###"));
for (Student s : list) {
bw.write(s.toString());
bw.newLine();
}
bw.close();
}
}
package com.example.demo;
public class Student {
private int age;
private String name;
private String gender;
private double weight;
public Student() {
}
public Student(int age, String name, String gender, double weight) {
this.age = age;
this.name = name;
this.gender = gender;
this.weight = weight;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public String toString(){
return name+"-"+gender+"-"+age+"-"+weight;
}
}