我正在做关于java I / O数据的功课,问题是我不允许使用对象序列化从二进制文件加载数据。
以下是作业要求:
持久性,将对象写入文件并从文件中读取对象(文本格式)
• All objects should be written to a single file in a text format • All objects should be read form the same file • You should use JFileChooser
我有3个课程:Unit
,Assessment
和Task
。
Assessment
类是抽象的IndividualAssessment
& GroupAssessment
是具体的子类。
Unit
有Assessment
的集合,Assessment
有Task
的集合。
我可以使用FileWriter
将所有数据保存到一个文本文件中,但我不知道如何将文本文件的每一行读入正确的Assessment
类。
我的意思是,您如何识别IndividualAssessment
或GroupAssessment
类的哪一行。
这是我尝试的代码,但它不起作用:
BufferedReader bf = new BufferedReader(file);
While (bf.readLine != null){
Unit u = new Unit(bf);
diary.add(u);
try{
Assessment a = new IndividualAssessment(bf);
} catch (IOException ex){
Assessment a = new GroupAssessment(bf);
}
u.add(a);
Task t = new Task(bf);
a.add(t);
答案 0 :(得分:1)
您应该从存储在String对象中读取的行的内容开始。所以它看起来像这样:
String line = bf.readLine();
while(line != null) {
// Add code to look at your line to figure out what kind of object it
// represents. For example you could add a one character prefix to each
// line when you write it to specify which object it is ('U', 'A' or 'T').
// Based on that, you can call a constructor of the appropriate object that
// takes a String as input. Then let the constructor deal with parsing the
// line for the object it represents. This way you don't end up with some
// massive parsing routine.
char code = line.charAt(0);
if(code == 'T') {
Task task = new Task();
task.initFromString(line.sustring(1));
... Do something with your task
}
else if(code == ...) {
}
line = bf.readLine(); // Read the next line
}
定义您的所有对象应实现的一些接口:
public interface TextExportable {
public char getClassIdentifier();
public void initFromString(String s);
}
我不确定你的物品是什么样子但是比如说:
public class Task implements TextExportable {
private String name;
public Task() {} // For the pseudo-serialization
public Task(String name) { // For creating the object by hand
this.name = name;
}
public char getClassIdentifier() {
return 'T';
}
public String toString() {
return getClassIdentifier()+name;
}
public void initFromString(String line) {
this.name = line;
// Here, you would need extra parsing if you have more than one attribute
// and dissect the line
}
}
答案 1 :(得分:0)
在构造函数中使用BufferedReader
作为参数是一种非常规的方法来解决这个问题。您实例中的BufferedReader
是交付模型数据的工具。并且您的模型数据应该与您的用例有关,而不是关于如何将其存储在磁盘上,因此它应该足够抽象。所以相反,我会在每个模型类上都有一个默认构造函数,然后可能是一个构造函数,可用于对模型类的所有/某些字段进行初始化。
接近文件界面的一种方法是创建文件读取器/写入器工具,可以从/向文件加载/保存数据。如果类层次结构的顶部是Unit
,那么我会这样:
Unit loadFromFile(String filename) {
// read unit, assessments etc in a format you choose, build the model and return it
...
}
void saveToFile(String filename) {
// write you model to a file
...
}
如果我是你,我会使用JSON作为我的数据格式。它可读,易于调试。
我希望这会有所帮助。
答案 2 :(得分:0)
除了接受的答案之外,我想补充一点,一种干净的解析方法是遵循interpreter pattern
所以假设bnf的语法如下:
<Unit> ::= <Name>[<Assessments>]
<Assessments> ::= <Assessment> | <Assessment> <Assessments>
<Assessment> ::= <Name>:<Type>[<Tasks>]
<Tasks> ::= <Task> | <Task>,<Tasks>
<Name> ::= <String>
<Type> ::= Group | Ind
你可能会写这样的东西来解析它 - 我把它留作练习来编写所使用的Expression
类。
try {
BufferedReader br = new BufferedReader(new FileReader("File.txt"));
try {
String unit;
while ((unit = br.readLine()) != null) {
String unitName = unit.substring(0, unit.indexOf('['));
String assessments = unit.substring(unit.indexOf('[') + 1,
unit.lastIndexOf(']'));
List<AssessmentExpression> aes = new ArrayList<AssessmentExpression>();
while (!assessments.equals("")) {
String assessmentName = assessments.substring(0,
assessments.indexOf(':'));
String assessmentType = assessments.substring(
assessments.indexOf(':') + 1,
assessments.indexOf('['));
String tasks = assessments.substring(
assessments.indexOf('[') + 1,
assessments.indexOf(']'));
List<String> taskList = Arrays.asList(tasks.split(","));
aes.add(new AssessmentExpression(assessmentName,
assessmentType, taskList));
assessments = assessments.substring(assessments.indexOf(']')+1);
}
Unit u = new UnitExpression(unitName, aes).interpret();
}
} finally {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}