JavaSE程序设计训练4:以文件模拟数据库完成管理系统
一、项目需求:
需要写一个学生管理系统,这个管理系统不能用数据库,要用文件IO完成数据库的所有功能。功能如下:
1.1、功能1:描述
每次系统启动的时候,完成一次从外存到内存的读取,说白了就是完成数据库的启动,把外存(长期保持)的数据读取到可以进行逻辑操作的内存上!
1.2、功能1:实现(只展示核心代码)
public void getDataFromFileToMem() throws Exception {
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream(new File("StudentOfFiles\\StudentInfo.txt")),
"UTF-8"
)
);
String strLine = null;
while((strLine = br.readLine()) != null){
strLine = strLine.replaceAll(" {2,}", " ");
String[] splitArray = strLine.split("\\ |\\t");
if(splitArray.length != 4){
throw new Exception("读取信息有误!");
}
else{
myStudents.add(new Student(splitArray[0], splitArray[1],
Integer.parseInt(splitArray[2]), Integer.parseInt(splitArray[3])));
}
}
br.close();
}
1.3、功能2:描述
完成系统的增删改查,所谓增删改,都必须同步内外存,既要在内存数据结构上处理,也要在外存上处理,要达到同步!所谓查询,就要输入一个学号,在控制台输出该学生的信息。
1.4、功能2:实现(只展示核心代码)
增加学生:
public void insertStudent(Student s) throws IOException {
myStudents.add(s);
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(file, true),
"UTF-8"
)
);
String strLine = new String(s.getName() + "\t" + s.getId() + "\t" + s.getAge() + "\t" + s.getScore());
bw.write(strLine + "\t\n");
bw.flush();
bw.close();
}
删除学生:
private static void cmdOfRemoveStudent(StudentDatabaseOperate sdo, Scanner sc){
System.out.println("----------------请输入您要删除的学生的学号:----------------");
String id = "";
while(true) {
id = sc.next();
if(!"".equals(id)){
break;
}
}
int len = sdo.getSize(), pos = -1;
for(int i = 0;i < len;++i){
if(id.equals(sdo.getMyStudents().get(i).getId())){
pos = i;
break;
}
}
try {
if(-1 != pos){
sdo.getMyStudents().remove(pos);
}
else{
throw new IOException("error");
}
exit(sdo, true);
sdo.filterByScore(true);
} catch (IOException e) {
System.out.println("文件内容删除有误!");
}
}
查询学生:
public Student findStudent(String id) throws Exception {
if("".equals(id)){
throw new Exception("id is null");
}
int len = myStudents.size();
for(int i = 0;i < len;++i){
Student s = myStudents.get(i);
if(id.equals(s.getId())) {
return s;
}
}
return null;
}
1.5、功能3:描述
完成数据库的多表归类,这里我设计的是按照成绩划分 A 、 B 、 C 三个档次,分别记为:
(90-100)—— 完美
(60-90) —— 合格
(0-60) —— 糟糕
其实实现上很简单,就是从外存文件上,把总的学生信息文件(也就是数据库的表),按照成绩划分的约定,分成三个子表即可!
这里有个点需要注意:
要避免在用户不合理操作下的处理,比如说用户多此指令要求按照成绩分表,切记不能够累积处理,否则分出来的表的内容会内存冗余,造成很多重复数据嗷!
1.6、功能3:实现(只展示核心代码)
filterByScore() 方法
public void filterByScore(boolean book) throws IOException {
int len = myStudents.size();
for(int i = 0;i < len;++i){
Student s = myStudents.get(i);
if(null == s){
continue;
}
if(book){
insertStudent(s);
}
switch (s.getScore() / 30)
{
case 3:
addIntoLevelFiles('A', s);
break;
case 2:
addIntoLevelFiles('B', s);
break;
default:
addIntoLevelFiles('C', s);
}
}
}
addIntoLevelFiles() 方法
private void addIntoLevelFiles(char level, Student s) throws IOException {
BufferedWriter bw = null;
switch (level)
{
case 'A':
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-perfect.txt"), true),
"UTF-8"
)
);
break;
case 'B':
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-pass.txt"), true),
"UTF-8"
)
);
break;
default:
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-bad.txt"), true),
"UTF-8"
)
);
}
String strLine = new String(s.getName() + "\t" + s.getId() + "\t" + s.getAge() + "\t" + s.getScore());
bw.write(strLine + "\t\n");
bw.flush();
bw.close();
}
1.7、功能4:描述
完成学生排序,按照的排序约定是:
① 如若成绩不一致,则成绩降序排序
② 如若成绩一致,则按照姓名的字典序排序
这里有个点需要注意:
这里的排序我采用的是内排序,这个也是比较合理的,毕竟数据库的图形页面对用户而言只是一个映射,不必做外排序。
1.8、功能4:实现(只展示核心代码)
public void sortStudentList(){
Collections.sort(myStudents, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
if(s1.getScore() != s2.getScore()){
return s2.getScore() - s1.getScore();
}
else{
return s1.getName().compareTo(s2.getName());
}
}
});
}
1.9、功能5:描述
清空数据库的功能,这个很简单,只需要给每个文件的开头(FileInputStream 的第二个参数改成true)写入一个空字符串即可!
1.10、功能5:实现(只展示核心代码)
public void exitDatabase(boolean book) throws IOException {
BufferedWriter bw;
if(book) {
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\StudentInfo.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
}
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-perfect.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-pass.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-bad.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
bw.close();
}
二、系统设计
本系统我按照MVC设计模式进行设计,设计如下:
Models :
设计了 Student 类,相当于给数据库建表
Views:
设计了 Main 类,给用户提供了人机交互性相对较号的交互界面
Controller:
设计了 StudentDatabaseOperate 类,完成了所有从 Models(数据库) 到 Views 的所有功能的实现,在 Views 里面仅仅是对功能进行了 二次 封装和调用。
三、文件结构:
这个文件结构如上,一会方便大家调试和复盘。
四、完整项目代码
Models 层:
import java.util.Comparator;
/**
* 功能:操作对象:学生类
* @author jiangzl
*/
class Student {
private String name, id;
private int age, score;
public Student(String name, String id, int age, int score){
this.name = name;
this.id = id;
this.age = age;
this.score = score;
}
public String getName(){
return name;
}
public int getScore(){
return score;
}
public String getId(){
return id;
}
public int getAge(){
return age;
}
@Override
public String toString(){
return new String("姓名:" + name + " 年龄:" + age + " 分数:" + score);
}
}
Controller 层
import java.io.*;
import java.util.*;
/**
* 功能:文本数据库操作类
* @author jiangzl
*/
class StudentDatabaseOperate {
private List<Student> myStudents;
private File file;
public StudentDatabaseOperate(String filename){
this.file = new File(filename);
this.myStudents = new ArrayList<>();
}
public void sortStudentList(){
Collections.sort(myStudents, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
if(s1.getScore() != s2.getScore()){
return s2.getScore() - s1.getScore();
}
else{
return s1.getName().compareTo(s2.getName());
}
}
});
}
public Student findStudent(String id) throws Exception {
if("".equals(id)){
throw new Exception("id is null");
}
int len = myStudents.size();
for(int i = 0;i < len;++i){
Student s = myStudents.get(i);
if(id.equals(s.getId())) {
return s;
}
}
return null;
}
public int getSize(){
return myStudents.size();
}
public List<Student> getMyStudents(){
return myStudents;
}
public void insertStudent(Student s) throws IOException {
myStudents.add(s);
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(file, true),
"UTF-8"
)
);
String strLine = new String(s.getName() + "\t" + s.getId() + "\t" + s.getAge() + "\t" + s.getScore());
bw.write(strLine + "\t\n");
bw.flush();
bw.close();
}
private void addIntoLevelFiles(char level, Student s) throws IOException {
BufferedWriter bw = null;
switch (level)
{
case 'A':
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-perfect.txt"), true),
"UTF-8"
)
);
break;
case 'B':
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-pass.txt"), true),
"UTF-8"
)
);
break;
default:
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-bad.txt"), true),
"UTF-8"
)
);
}
String strLine = new String(s.getName() + "\t" + s.getId() + "\t" + s.getAge() + "\t" + s.getScore());
bw.write(strLine + "\t\n");
bw.flush();
bw.close();
}
public void filterByScore(boolean book) throws IOException {
int len = myStudents.size();
for(int i = 0;i < len;++i){
Student s = myStudents.get(i);
if(null == s){
continue;
}
if(book){
insertStudent(s);
}
switch (s.getScore() / 30)
{
case 3:
addIntoLevelFiles('A', s);
break;
case 2:
addIntoLevelFiles('B', s);
break;
default:
addIntoLevelFiles('C', s);
}
}
}
public void exitDatabase(boolean book) throws IOException {
BufferedWriter bw;
if(book) {
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\StudentInfo.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
}
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-perfect.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-pass.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(new File("StudentOfFiles\\Score-bad.txt")),
"UTF-8"
)
);
bw.write("");
bw.flush();
bw.close();
}
public void getDataFromFileToMem() throws Exception {
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream(new File("StudentOfFiles\\StudentInfo.txt")),
"UTF-8"
)
);
String strLine = null;
while((strLine = br.readLine()) != null){
strLine = strLine.replaceAll(" {2,}", " ");
String[] splitArray = strLine.split("\\ |\\t");
if(splitArray.length != 4){
throw new Exception("读取信息有误!");
}
else{
myStudents.add(new Student(splitArray[0], splitArray[1],
Integer.parseInt(splitArray[2]), Integer.parseInt(splitArray[3])));
}
}
br.close();
}
}
Views 层
import java.io.*;
import java.util.Scanner;
/**
* 功能:测试类
* @author 江政良
*/
public class Main {
private static void cmdOfInsert(StudentDatabaseOperate sdo, Scanner sc){
System.out.println("----------------请问您一次需要插入多少名同学:----------------");
int num = sc.nextInt();
System.out.println("----------------请依次输入:姓名、学号、年龄、分数----------------");
for(int i = 0;i < num;++i){
String name = sc.next();
String id = sc.next();
int age = sc.nextInt();
int score = sc.nextInt();
Student s = new Student(name, id, age, score);
try {
sdo.insertStudent(s);
}
catch (Exception inertE){
System.out.println("存在输入异常的同学!!");
}
}
}
private static void cmdOfFind(StudentDatabaseOperate sdo, Scanner sc){
System.out.println("----------------请输入需要查找的同学的学号:----------------");
Student ret = null;
while(true) {
String id = sc.nextLine();
if("".equals(id)){
continue;
}
try {
ret = sdo.findStudent(id);
break;
} catch (Exception findE) {
System.out.println("查找失败,重新输入id,检查id格式!");
}
}
if(null != ret){
System.out.println(ret);
}
else{
System.out.println("查找到的学生不存在!");
}
}
private static void cmdOfStudentSort(StudentDatabaseOperate sdo){
sdo.sortStudentList();
int len = sdo.getMyStudents().size();
for(int i = 0;i < len;++i){
System.out.println(sdo.getMyStudents().get(i));
}
}
private static void cmdOfFilterToFile(StudentDatabaseOperate sdo){
try {
sdo.exitDatabase(false);
sdo.filterByScore(false);
}
catch (Exception fileE){
System.out.println("文件操作有误!");
}
}
private static void cmdOfRemoveStudent(StudentDatabaseOperate sdo, Scanner sc){
System.out.println("----------------请输入您要删除的学生的学号:----------------");
String id = "";
while(true) {
id = sc.next();
if(!"".equals(id)){
break;
}
}
int len = sdo.getSize(), pos = -1;
for(int i = 0;i < len;++i){
if(id.equals(sdo.getMyStudents().get(i).getId())){
pos = i;
break;
}
}
try {
if(-1 != pos){
sdo.getMyStudents().remove(pos);
}
else{
throw new IOException("error");
}
exit(sdo, true);
sdo.filterByScore(true);
} catch (IOException e) {
System.out.println("文件内容删除有误!");
}
}
private static void exit(StudentDatabaseOperate sdo, boolean book){
try {
sdo.exitDatabase(book);
}
catch (Exception exitE) {
System.out.println("关闭系统错误!");
}
}
private static void cmdOfResumeDataFromFile(StudentDatabaseOperate sdo){
try {
sdo.getDataFromFileToMem();
} catch (Exception getDataE) {
System.out.println("从数据库恢复数据到内存失败");
System.exit(0);
}
}
public static void main(String[] args){
System.out.println("----------------欢迎使用学生管理后台----------------");
String src = "StudentOfFiles\\StudentInfo.txt";
StudentDatabaseOperate sdo = new StudentDatabaseOperate(src);
cmdOfResumeDataFromFile(sdo);
System.out.println("----------------请根据如下提示进行操作----------------");
System.out.println("----------------输入0:清空数据库----------------");
System.out.println("----------------输入1:加入学生----------------");
System.out.println("----------------输入2:查找学生----------------");
System.out.println("----------------输入3:学生等第排序----------------");
System.out.println("----------------输入4:学生按成绩分类到文件----------------");
System.out.println("----------------输入5:按照学号删除某同学的记录----------------");
System.out.println("----------------输入“结束”:结束本系统----------------");
Scanner sc = new Scanner(System.in);
while(true) {
int cmd = -1;
String cmdStr = sc.next();
if("结束".equals(cmdStr)){
break;
}
try {
cmd = Integer.parseInt(cmdStr);
}
catch (Exception cmdE){
System.out.println("亲,这边不晓得你说什么哦,请重新输入!");
continue;
}
switch (cmd) {
case 0:
exit(sdo, true);
sdo.getMyStudents().clear();
break;
case 1:
cmdOfInsert(sdo, sc);
break;
case 2:
cmdOfFind(sdo, sc);
break;
case 3:
cmdOfStudentSort(sdo);
break;
case 4:
cmdOfFilterToFile(sdo);
break;
case 5:
cmdOfRemoveStudent(sdo, sc);
break;
default:
System.out.println("输入失败,请重新输入");
}
System.out.println("----------------请根据如下提示进行操作----------------");
System.out.println("----------------输入0:清空数据库----------------");
System.out.println("----------------输入1:加入学生----------------");
System.out.println("----------------输入2:查找学生----------------");
System.out.println("----------------输入3:学生等第排序----------------");
System.out.println("----------------输入4:学生按成绩分类到文件----------------");
System.out.println("----------------输入5:按照学号删除某同学的记录----------------");
System.out.println("----------------输入“结束”:结束本系统----------------");
}
sc.close();
}
}
五、写在后面的话
由于本人能力有限,写的、设计的不合理的地方还请各位提出!有好的建议或者意见也最好能够留言、私信给我,谢谢~~
对了,这里是我的GitHub上,关于这个项目的地址,欢迎多多Star!谢谢!