序列化 - 为什么 readObject 不读取整个文件?
Serialization - Why readObject doesn't reads whole file?
我是 Java 的初学者,我遇到 read/write 到文本文件的问题。
过程:
- 读取并显示文本文件:System.out.println(车库);
- 添加第一辆车:garage.addVoiture(lag1);
- 添加第二辆车:garage.addVoiture(A300B_2);
这里是 main.java :
import fr.ocr.vehicule2.*;
public class Main {
public static void main(String[] args) {
Garage garage = new Garage();
System.out.println(garage);
Vehicule lag1 = new Lagouna();
lag1.setMoteur(new MoteurEssence("150 Chevaux", 10256d));
lag1.addOption(new GPS());
lag1.addOption(new SiegeChauffant());
lag1.addOption(new VitreElectrique());
garage.addVoiture(lag1);
Vehicule A300B_2 = new A300B();
A300B_2.setMoteur(new MoteurElectrique("1500 W", 1234d));
A300B_2.addOption(new Climatisation());
A300B_2.addOption(new BarreDeToit());
A300B_2.addOption(new SiegeChauffant());
garage.addVoiture(A300B_2);
}
这里是garage.java
package fr.ocr.vehicule2;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class Garage {
private List<Vehicule> voitures = new ArrayList<Vehicule>();;
ObjectInputStream ois;
ObjectOutputStream oos;
public Garage(){
}
public String toString() {
System.out.println("DEBUG start toString");
String str = "";
// Vérification de l'existence du fichier de sauvegarde
if(Files.notExists(Paths.get("garage.txt"))) str += "Aucune voiture sauvegardée !\n";
str += "*************************\n"
+ "* Garage OpenClassrooms *\n"
+ "*************************\n";
// Lecture du fichier texte
if(Files.exists(Paths.get("garage.txt"))) {
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
str += ((Vehicule)ois.readObject()).toString();
ois.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("DEBUG end toString");
return str;
}
public void addVoiture(Vehicule voit) {
System.out.println("DEBUG start addVoiture" + voit);
voitures.add(voit);
// écriture du fichier texte
try {
oos = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File("garage.txt"))));
// for(Vehicule V:voitures){
// oos.writeObject(V);
// }
oos.writeObject(voit);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("DEBUG end addVoiture");
}
}
第一次执行 main.java,(文本文件不存在)我进入控制台:
- Aucune voiture sauvegardée !
- 车库开放课堂 *
- 开始添加Voiture
- 结束添加
- 开始添加Voiture
- 结束添加
这就是我想在首次启动时在控制台中显示的内容。
但是第二次执行 main.java,(文本文件存在),我进入控制台:
- DEBUG 开始 toString
- DEBUG 结束 toString
- 车库开放课堂 *
- Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€
- 调试开始 addVoiture+ Voiture RENO : Lagouna Moteur ESSENCE 150 Chevaux (10256.0) [GPS (113.5€), Siège chauffant (562.9€), Vitres electrique (212.35€)] d'une valeur totale de 11144.75€
- DEBUG结束addVoiture
- DEBUG start addVoiture+ Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€
- DEBUG结束addVoiture
控制台中仅显示第二辆车(+ Voiture PIGEOT)。
我想要的结果是他们两个,按照我添加它们的方式排序:
_ * 车库开放课堂 *
_ *************************
- Voiture RENO : Lagouna Moteur ESSENCE 150 Chevaux (10256.0) [GPS (113.5€), Siège chauffant (562.9€), Vitres electrique (212.35€)] d'une valeur totale de 11144.75€
- Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€
我找不到这个问题的解决方案,
是因为我没有正确写两辆车:oos.writeObject(voit);
或者因为我没有正确阅读它:str += ((Vehicule)ois.readObject()).toString(); ?
我什至在 Whosebug 上搜索了很多,但代码似乎是正确的。所以这可能是我写入然后读取文件的方式有问题?
如果有人能提供帮助,非常感谢,我花了很多时间但转过身来。
在@Kevin Anderson 信息之后添加:
再次感谢您的帮助!
我用你的脚本更改了 readObject,但我仍然只添加了最后一辆车。
我也看到了这个 post (java.io.StreamCorruptedException: invalid type code: AC) 但没能解决。所以我改变了我写对象的方式(停止将对象附加到 ObjectOutputStream)并获得了几乎不错的结果。
现在我的最终问题是 "Type safety: Unchecked cast from Object to List" on readObject()。
我认为(不确定?)这只是一个 IDE 信息,所以我想最好以正确的方式进行操作,所以我想避免使用 (@SuppressWarnings("unchecked")) over (public String toString() {) 并以最好的方式做到这一点,但我无法应用我在 Whosebug 上找到的所有解决方案。
如果你有想法,那就太完美了!
这是新的 garage.java :
public class Garage {
private List<Vehicule> voitures = new ArrayList<Vehicule>();
private ObjectInputStream ois;
protected static ObjectOutputStream oos;
public Garage(){}
public String toString() {
String str = "";
// Vérification de l'existence du fichier de sauvegarde
if(Files.notExists(Paths.get("garage.txt"))) {
str += "Aucune voiture sauvegardée !\n";
}
str += "*************************\n"
+ "* Garage OpenClassrooms *\n"
+ "*************************\n";
// Lecture du fichier texte
if(Files.exists(Paths.get("garage.txt"))) {
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
// garage loading during instanciation :
// Information Eclipse :
// Type safety: Unchecked cast from Object to List<Vehicule>
this.voitures = (List<Vehicule>)ois.readObject();
// Affichage des voitures enregistrées dans le fichier texte
for(Vehicule V : this.voitures){
str += V;
}
// To avoid "Type safety: Unchecked cast from Object to List<Vehicule>" :
// those 2 solutions show identical information "Type safety: Unchecked cast from Object to List<Vehicule>"
// First tried solution :
// this.voitures = new new ArrayList<Vehicule>((List<Vehicule>)ois.readObject());
// Second tried solution :
// if(ois.readObject() instanceof List<?>){
// List<?> list = (ArrayList<?>)ois.readObject();
// for(Object e : list){
// if(e instanceof Vehicule){
// this.voitures = (List<Vehicule>)e;
// }
// }
// }
ois.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return str;
}
public void addVoiture(Vehicule voit) {
voitures.add(voit);
// écriture du fichier texte
try {
oos = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File("garage.txt"))));
// Enregistrement detoutes les voitures dans le fichier texte
oos.writeObject(voitures);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
添加了类型安全的解决方案:未检查的从对象到列表的转换
多亏了这个 post : Type safety: Unchecked cast
文本文件包含一个列表对象
当我启动 Garage() 时,我需要将这个 List 对象添加到现有的 List 对象中。
Eclipse 显示:
类型安全:未经检查的从对象到列表的转换
我可以在我的方法中使用:@SuppressWarnings("unchecked"),但这样做看起来更好,所以我不会忽略任何警告:
List<?> list = (List<?>) ois.readObject();
for(int i = 0; i < list.size(); i++) {
this.voitures.add((Vehicule) list.get(i)); // instanciation
str += (Vehicule) list.get(i);// Added to console message
}
希望对您有所帮助,对于我初学者的错误感到抱歉^^,感谢大家的帮助!
名称告诉您需要做什么:读取一个对象。
未命名 read File.
换句话说:当您使用对象流时,您的代码定义了以何种顺序写入哪些对象。然后,在另一边,类似的代码必须以完全相同的顺序读取这些对象。
这就是全部。
并且您当前的代码覆盖现有文件。当你想要 "preserve" 文件内容时 - 那么你首先必须读入先前存储的对象。
每次调用 addVoiture
时,都会覆盖数据文件,而不是向其添加内容。将您的文件打开代码更改为
oos = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File("garage.txt"), true)));
new FileOutputStream
上的额外参数 true
打开一个现有文件进行追加,而不是每次都创建一个新的空文件。请参阅文档 here
此外,由于您正在将多个 Vehicule
对象写入文件,因此您必须执行多个 readObject
调用才能再次读取所有对象。您只看到一辆车的原因是因为您只调用 readObject
一次。您需要在循环中继续调用 readObject
直到获得 EOFException
:
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
for(;;){
try {
str += ((Vehicule)ois.readObject()).toString();
} catch (EOFException eofe) {
break;
}
}
ois.close();
}
} catch ....
通过此更改,您不再需要使用外部 try
块捕获 EOFException
,因为内部 try
现在可以处理它。
我是 Java 的初学者,我遇到 read/write 到文本文件的问题。
过程:
- 读取并显示文本文件:System.out.println(车库);
- 添加第一辆车:garage.addVoiture(lag1);
- 添加第二辆车:garage.addVoiture(A300B_2);
这里是 main.java :
import fr.ocr.vehicule2.*;
public class Main {
public static void main(String[] args) {
Garage garage = new Garage();
System.out.println(garage);
Vehicule lag1 = new Lagouna();
lag1.setMoteur(new MoteurEssence("150 Chevaux", 10256d));
lag1.addOption(new GPS());
lag1.addOption(new SiegeChauffant());
lag1.addOption(new VitreElectrique());
garage.addVoiture(lag1);
Vehicule A300B_2 = new A300B();
A300B_2.setMoteur(new MoteurElectrique("1500 W", 1234d));
A300B_2.addOption(new Climatisation());
A300B_2.addOption(new BarreDeToit());
A300B_2.addOption(new SiegeChauffant());
garage.addVoiture(A300B_2);
}
这里是garage.java
package fr.ocr.vehicule2;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class Garage {
private List<Vehicule> voitures = new ArrayList<Vehicule>();;
ObjectInputStream ois;
ObjectOutputStream oos;
public Garage(){
}
public String toString() {
System.out.println("DEBUG start toString");
String str = "";
// Vérification de l'existence du fichier de sauvegarde
if(Files.notExists(Paths.get("garage.txt"))) str += "Aucune voiture sauvegardée !\n";
str += "*************************\n"
+ "* Garage OpenClassrooms *\n"
+ "*************************\n";
// Lecture du fichier texte
if(Files.exists(Paths.get("garage.txt"))) {
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
str += ((Vehicule)ois.readObject()).toString();
ois.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("DEBUG end toString");
return str;
}
public void addVoiture(Vehicule voit) {
System.out.println("DEBUG start addVoiture" + voit);
voitures.add(voit);
// écriture du fichier texte
try {
oos = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File("garage.txt"))));
// for(Vehicule V:voitures){
// oos.writeObject(V);
// }
oos.writeObject(voit);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("DEBUG end addVoiture");
}
}
第一次执行 main.java,(文本文件不存在)我进入控制台:
- Aucune voiture sauvegardée !
- 车库开放课堂 *
- 开始添加Voiture
- 结束添加
- 开始添加Voiture
- 结束添加
这就是我想在首次启动时在控制台中显示的内容。
但是第二次执行 main.java,(文本文件存在),我进入控制台:
- DEBUG 开始 toString
- DEBUG 结束 toString
- 车库开放课堂 *
- Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€
- 调试开始 addVoiture+ Voiture RENO : Lagouna Moteur ESSENCE 150 Chevaux (10256.0) [GPS (113.5€), Siège chauffant (562.9€), Vitres electrique (212.35€)] d'une valeur totale de 11144.75€
- DEBUG结束addVoiture
- DEBUG start addVoiture+ Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€
- DEBUG结束addVoiture 控制台中仅显示第二辆车(+ Voiture PIGEOT)。
我想要的结果是他们两个,按照我添加它们的方式排序:
_ * 车库开放课堂 * _ *************************- Voiture RENO : Lagouna Moteur ESSENCE 150 Chevaux (10256.0) [GPS (113.5€), Siège chauffant (562.9€), Vitres electrique (212.35€)] d'une valeur totale de 11144.75€
- Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€
我找不到这个问题的解决方案, 是因为我没有正确写两辆车:oos.writeObject(voit); 或者因为我没有正确阅读它:str += ((Vehicule)ois.readObject()).toString(); ?
我什至在 Whosebug 上搜索了很多,但代码似乎是正确的。所以这可能是我写入然后读取文件的方式有问题?
如果有人能提供帮助,非常感谢,我花了很多时间但转过身来。
在@Kevin Anderson 信息之后添加:
再次感谢您的帮助!
我用你的脚本更改了 readObject,但我仍然只添加了最后一辆车。
我也看到了这个 post (java.io.StreamCorruptedException: invalid type code: AC) 但没能解决。所以我改变了我写对象的方式(停止将对象附加到 ObjectOutputStream)并获得了几乎不错的结果。
现在我的最终问题是 "Type safety: Unchecked cast from Object to List" on readObject()。
我认为(不确定?)这只是一个 IDE 信息,所以我想最好以正确的方式进行操作,所以我想避免使用 (@SuppressWarnings("unchecked")) over (public String toString() {) 并以最好的方式做到这一点,但我无法应用我在 Whosebug 上找到的所有解决方案。
如果你有想法,那就太完美了!
这是新的 garage.java :
public class Garage {
private List<Vehicule> voitures = new ArrayList<Vehicule>();
private ObjectInputStream ois;
protected static ObjectOutputStream oos;
public Garage(){}
public String toString() {
String str = "";
// Vérification de l'existence du fichier de sauvegarde
if(Files.notExists(Paths.get("garage.txt"))) {
str += "Aucune voiture sauvegardée !\n";
}
str += "*************************\n"
+ "* Garage OpenClassrooms *\n"
+ "*************************\n";
// Lecture du fichier texte
if(Files.exists(Paths.get("garage.txt"))) {
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
// garage loading during instanciation :
// Information Eclipse :
// Type safety: Unchecked cast from Object to List<Vehicule>
this.voitures = (List<Vehicule>)ois.readObject();
// Affichage des voitures enregistrées dans le fichier texte
for(Vehicule V : this.voitures){
str += V;
}
// To avoid "Type safety: Unchecked cast from Object to List<Vehicule>" :
// those 2 solutions show identical information "Type safety: Unchecked cast from Object to List<Vehicule>"
// First tried solution :
// this.voitures = new new ArrayList<Vehicule>((List<Vehicule>)ois.readObject());
// Second tried solution :
// if(ois.readObject() instanceof List<?>){
// List<?> list = (ArrayList<?>)ois.readObject();
// for(Object e : list){
// if(e instanceof Vehicule){
// this.voitures = (List<Vehicule>)e;
// }
// }
// }
ois.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return str;
}
public void addVoiture(Vehicule voit) {
voitures.add(voit);
// écriture du fichier texte
try {
oos = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File("garage.txt"))));
// Enregistrement detoutes les voitures dans le fichier texte
oos.writeObject(voitures);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
添加了类型安全的解决方案:未检查的从对象到列表的转换
多亏了这个 post : Type safety: Unchecked cast
文本文件包含一个列表对象 当我启动 Garage() 时,我需要将这个 List 对象添加到现有的 List 对象中。
Eclipse 显示: 类型安全:未经检查的从对象到列表的转换
我可以在我的方法中使用:@SuppressWarnings("unchecked"),但这样做看起来更好,所以我不会忽略任何警告:
List<?> list = (List<?>) ois.readObject();
for(int i = 0; i < list.size(); i++) {
this.voitures.add((Vehicule) list.get(i)); // instanciation
str += (Vehicule) list.get(i);// Added to console message
}
希望对您有所帮助,对于我初学者的错误感到抱歉^^,感谢大家的帮助!
名称告诉您需要做什么:读取一个对象。
未命名 read File.
换句话说:当您使用对象流时,您的代码定义了以何种顺序写入哪些对象。然后,在另一边,类似的代码必须以完全相同的顺序读取这些对象。
这就是全部。
并且您当前的代码覆盖现有文件。当你想要 "preserve" 文件内容时 - 那么你首先必须读入先前存储的对象。
每次调用 addVoiture
时,都会覆盖数据文件,而不是向其添加内容。将您的文件打开代码更改为
oos = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File("garage.txt"), true)));
new FileOutputStream
上的额外参数 true
打开一个现有文件进行追加,而不是每次都创建一个新的空文件。请参阅文档 here
此外,由于您正在将多个 Vehicule
对象写入文件,因此您必须执行多个 readObject
调用才能再次读取所有对象。您只看到一辆车的原因是因为您只调用 readObject
一次。您需要在循环中继续调用 readObject
直到获得 EOFException
:
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
for(;;){
try {
str += ((Vehicule)ois.readObject()).toString();
} catch (EOFException eofe) {
break;
}
}
ois.close();
}
} catch ....
通过此更改,您不再需要使用外部 try
块捕获 EOFException
,因为内部 try
现在可以处理它。