Java学习笔记(十八)综合练习,Properties配置文件
随机点名器
需求:设计一个随机点名器,要求从一个文件中读取学生信息数据,例如:张三-男-23-1.0,其中通用格式为:姓名-性别-年龄-抽签的权重,要求在每次该学生被抽到后,将该学生的对应抽取几率减半,在每次抽取学生之后将学生信息重新存储到文件中。
思路:先将学生的属性从文件中取出,创建相关属性的学生对象,将学生对象存入集合中进行后续操作,将各学生的权重取出,进行计算所有学生权重的总和,再分别计算各个学生权重占比,再将本学生对应的权重占比对应段数算出,再生成随机的相关范围数字,利用二分查找和相关操作得到具体的索引位置,该索引位置的学生对象就是应被抽取的学生对象,将该学生对象的权重值获取出进行除以2,再将权重值放回,最后将整个学生集合重新写入该文件。代码实现如下:
package com.itazhang;
import com.itazhang.Demo2.Student;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class Exercise5 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:\\11Codingtext\\MyIOTest\\a.txt"));
ArrayList<Student> stulist = new ArrayList<>();
String templin;
while(true){
templin = br.readLine();
if(templin == null){
break;
}
String[] arr = templin.split("-");
stulist.add(new Student(arr[0],arr[1],Integer.parseInt(arr[2]),Double.parseDouble(arr[3])));
}
br.close();
//处理权重问题
//1、求出集合中学生对象的权重总和
double sum = 0;
for (Student student : stulist) {
sum = sum+student.getWeight();
}
//用学生自己的权重值除以权重总和得到每个学生的权重占比
double[] brr = new double[stulist.size()];
int index = 0;
for (Student student : stulist) {
double v = student.getWeight() / sum;
brr[index] = v;
index++;
}
//得出每个学生权重占比的范围,例如(0-0.1)
for (int i = 1; i < brr.length; i++) {
brr[i] = brr[i]+brr[i-1];
}
//利用权重来获取学生对象
Random r =new Random();
double tempdouble = r.nextDouble(1);
//利用二分查找查找该随机到的权重对应的学生索引
//因为数组的二分查找这个方法返回的是应该-插入点索引+1,也就是结果=-插入点索引-1
//所以我们要获取插入索引的话需要 插入点索引 = -结果-1
int i = -Arrays.binarySearch(brr, tempdouble)-1;
//找到了上诉索引,就能获取到相关的学生对象
Student student = stulist.get(i);
System.out.println(student);
//找到该学生的权重,且将该权重除以2
double v = student.getWeight() / 2;
student.setWeight(v);
System.out.println(stulist);
//将集合中的数据再次写入到文件中
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\11Codingtext\\MyIOTest\\a.txt"));
for (Student student1 : stulist) {
bw.write(student1.toString());
bw.newLine();
}
bw.close();
}
}
登录锁定模拟
单个用户登录
设计一个控制台登录系统,再文件中存储正确的用户名和密码,只要用户名和对应的密码都正确才能打印登录成功,否则登录失败,且登录失败超过三次,控制台输出你的账号已被锁定,无法再继续进行登录操作,具体实现代码如下:(注意此题主要易错点为相关字符串信息的修改,每次登录之后文件中的count都需要加1,但是count是在字符串中,一个字符串的值是无法被修改的,所以在每次输入之后都得write一个新的字符串进去)
package com.itazhang.Demo3;
import java.io.*;
import java.util.Scanner;
public class LoginExercise1 {
public static void main(String[] args) throws IOException {
System.out.println("请输入用户名:");
Scanner sc = new Scanner(System.in);
String usernamein = sc.next();
System.out.println("请输入该用户的密码:");
String passwordin = sc.next();
BufferedReader br = new BufferedReader(new FileReader("D:\\11Codingtext\\MyIOTest\\Login.txt"));
String s = br.readLine();
String username = s.split("=")[1].split("&")[0];
String password = s.split("=")[2].split("&")[0];
String counttemp = s.split("=")[3];
int count = Integer.parseInt(counttemp);
if(count>=3){
System.out.println("你的账号已被锁定");
}else{
if(username.equals(usernamein)&&passwordin.equals(password)){
System.out.println("登录成功");
count = 0;
}else{
System.out.println("登录失败");
count++;
}
}
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\11Codingtext\\MyIOTest\\Login.txt"));
bw.write("username="+username+"&password="+password+"&count="+count);
bw.close();
br.close();
}
}
多个用户登录
将本地文件的用户密码以及count登录次数读入且放入一个集合文件中存储起来,在创建相关对象,调用属性值与输入的用户名和密码进行比较,如果相关账号登录失败,再将该账号的count值加1,最后写入到本地文件中(需要添加一个lock判断,如果count>3,即将该账号的lock变为true,则判断该账号被锁)代码实现如下:
package com.itazhang.Demo3;
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
public class LoginExercise2 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:\\11Codingtext\\MyIOTest\\temp.txt"));
ArrayList<User> userlist = new ArrayList<>();
//将文件里的用户和密码信息取出存储到集合中
while(true){
String templin = br.readLine();
if(templin == null){
break;
}
userlist.add(new User(templin.split("=")[1].split("&")[0],templin.split("=")[2].split("&")[0],Integer.parseInt(templin.split("=")[3])));
}
System.out.println("请输入用户名");
Scanner sc = new Scanner(System.in);
String usernameInto = sc.next();
System.out.println("请输入密码");
String passwordInto = sc.next();
boolean flag = false;
boolean lock = false;
for (User user : userlist) {
if(user.getCount() > 3){
lock = true;
}
}
for (User user : userlist) {
if(user.getPassword().equals(passwordInto) && user.getUsername().equals(usernameInto)){
System.out.println("登录成功");
user.setCount(0);
flag = true;
break; // 登录成功后无需再继续遍历
}
}
if(!flag) {
System.out.println("登录失败");
for (User user : userlist) {
if (user.getUsername().equals(usernameInto)) {
user.setCount(user.getCount() + 1);
if (user.getCount() > 3) {
System.out.println("你已登录失败超过三次,账号已被锁定");
lock = true;
}
break; // 已经找到对应用户,不需要继续遍历
}
}
}
// 如果用户被锁定,则不再写入文件
if (!lock) {
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\11Codingtext\\MyIOTest\\temp.txt"));
for (User user : userlist) {
bw.write(user.toString());
bw.newLine();
}
bw.close();
}
br.close();
}
}
配置文件
properties配置文件
properties配置文件底层是一个Map集合,他存储数据的方式也是以键值对的方式存储,,所以其也能使用Map集合里的所有方法,但是主流的还是将properties配置文件与IO相结合进行相应的操作
properties的store方法
该方法是将程序中相应的数据保存到指定路径的文件里面,底层需要一个字节或字符输出流关联,相当于也是将程序中的键值对对象存储到文件中,也就是写出操作,代码如下:
String user1 = "username=zhangsan&password=123&count=0";
String user2 = "username=lisi&password=123&count=0";
String user3 = "username=wangwu&password=123&count=0";
Properties p = new Properties();
p.put("user1",user1);
p.put("user2",user2);
p.put("user3",user3);
//创建一个输出流关联properties
FileOutputStream fos = new FileOutputStream("D:\\11Codingtext\\MyIOTest\\b.txt");
p.store(fos,"test");
fos.close();
properties的load方法
该方法也是需要关联一个字节或字符输入流,该方法的作用就是将文件中的数据从文件中读取出来,再通过键值对的方式存储到创建的properties类型的对象中(可以将properties对象理解为Map类型对象),具体实现代码如下:
//创建一个properties对象,使用load方法将数据从文件中取出
Properties p2 =new Properties();
FileInputStream fs = new FileInputStream("D:\\11Codingtext\\MyIOTest\\b.txt");
//load方法会自动将文件中的数据读取到properties对象中,用键值对的方式存储
p2.load(fs);
fs.close();
System.out.println(p2);
而在实际运用场景中,我们直接将所需要添加到程序中的数据在properties配置文件中,再通过load方法将文件里面的数据传入到程序用用集合存储,需要的时候直接通过Map的相关方法调用里面的键和值(可以将properties看作拥有特殊方法的Map集合)即可,如果我们需要改动配置文件所表示的数据,直接在配置文件中修改相应的键和值即可,省去了修改代码的不方便情况