序列化
将被序列化的对象写到文件中,可以通过解序列化重新读取这些对象,适用于Java环境,不能被其他程序引用。
将序列化程序写入文件
创建出FileOutputStream
FileOutputStream fileStream = new FileOutputStream("MyGame.ser");
这一步创建存取文件的 FileOutputStream对象,如果文件不存在会自动创建。
创建ObjectOutputStream
ObjectOutputStream os = new ObjectOutputStream(fileStream);
这一步将对象写入ObjectOutputStream,ObjectOutputStream无法直接连接文件,需要参数引导。
写入对象
os.writeObject(CharaerOne);//将变量所引用的对象序列化并写入文件 os.writeObject(CharaerTwo);//将变量所引用的对象序列化并写入文件 os.writeObject(CharaerThree);//将变量所引用的对象序列化并写入文件
关闭ObjectOutputStream
os.close();//关闭所关联的串流
数据在串流中移动
将串流(stream)连接起来代表来源与目的地的连接。串流必须连接到某处才能算是串流。
一般来说,串流要两两连接才能做出有意义的事情——其中一个表示连接,另一个则是要被调用方法的。以FileOutputStream为例,它有可以写入字节的方法。但我们通常不会直接写字节,而是以对象层次的观点来写入,所以需要高层的连接串流。
如果要让类序列化,就要实现Serializable接口
Serializable接口没有任何方法要实现,它的唯一目的就是声明有实现它的类是可以被序列化的。
序列化是全有或全无的
整个对象的主数据类型实例变量和引用到其他对象的实例变量都必须正确的序列化,不然就全部失败。
如果某实例变量不能或不应被实例化,就把它标记为transient(瞬时)的。
解序列化
创建FileInputStream
FileInputStream fileStream = new FileInputStream("MyGame.ser");//若文件不存在则抛出异常
FileInputStream知道如何连接文件
创建ObjectInputStream
ObjectInputStream os = new ObjectInputStream(fileStream);
ObjectInputStream知道如何读取对象,但是要靠链接的stream提供文件存取
读取对象
Object one = os.readObject(); //每次调用readObject()都会从stream中读出下一个对象,读取顺序与读入顺序相同,次数超过会抛出异常 Object two = os.readObject(); Object three = os.readObject();
转换对象类型
GameCharacter elf = (GameCharacte) one; GameCharacte troll = (GameCharacte) two; GameCharacte magician = (GameCharacte) three;
关闭ObjectInputStream
os.close();//FileInputStream也会关掉
存储与恢复游戏人物
import java.io.*;
public class GameSaverTest {
public static void main(String[] args) {
GameCharacter one = new GameCharacter(50, "Elf", new String[] { "bow", "sword" });
GameCharacter two = new GameCharacter(50, "Magic", new String[] { "cust", "sword" });
GameCharacter three = new GameCharacter(50, "Knight", new String[] { "horse", "sword" });
try {
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("Game.ser"));
os.writeObject(one);
os.writeObject(two);
os.writeObject(three);
os.close();
} catch (IOException ex) {
ex.printStackTrace();
}
one = null;
two = null;
three = null;
try {
ObjectInputStream is = new ObjectInputStream(new FileInputStream("Game.ser"));
GameCharacter oneRestore = (GameCharacter) is.readObject();
GameCharacter twoRestore = (GameCharacter) is.readObject();
GameCharacter threeRestore = (GameCharacter) is.readObject();
System.out.println(oneRestore.getType());
System.out.println(twoRestore.getType());
System.out.println(threeRestore.getType());
} catch (Exception ex) {
ex.getStackTrace();
}
}
}
import java.io.*;
public class GameCharacter implements Serializable {
int power;
String type;
String[] weapons;
public GameCharacter(int p, String t, String[] w) {
power = p;
type = t;
weapons = w;
}
public int getPower() {
return power;
}
public String getType() {
return type;
}
public String getWeapons() {
String weaponList = "";
for (int i = 0; i < weapons.length; i++) {
weaponList += weapons[i] + " ";
}
return weaponList;
}
}
序列化要点
- 你可以通过序列化来存储对象的状态
- 使用ObjectOutputStream来序列化对象(java.io)
- Stream是连接串流或是链接用的串流
- 连接串流用来表示源或目的地、文件、网络套接字连接
- 链接用串流用来衔接连接串流
- 用FileOutputStream链接ObjectOutputStream来将对象序列化到文件上
- 调用ObjectOutputStream的writeObject(theObject)来将对象序列化,不需要调用FileOutputStream的方法
- 对象必须实现序列化这个接口(Serializable)才能被序列化。如果父类实现序列化,则子类也就自动地实现,而不管是否有明确的声明
- 当对象被序列化时,整个对象版图都会被序列化。这代表它的实例变量所引用的对象也会被实例化
- 如果有不能被序列化的对象,执行期间就会抛出异常
- 若实例变量被标记为transient。该变量在还原的时候会被赋予null或主数据类型的默认值
- 在解序列化时,所有的类都必须能让Java虚拟机找到
- 读取对象的顺序必须与写入的顺序相同
- readObject()的返回类型是Object,因此解序列化回来的对象还需要转换成原来的类型
- 静态变量不会被序列化,因为所有对象都是共享同一份静态变量值
文件输入/输出
将字符串写入文件
使用FileWriter将文本数据(字符串)写入文件
import java.io.*;
public class WriteAFile {
public static void main(String[] args) {
try {
FileWriter writer = new FileWriter("Foo.txt");//如果没有就会创建
writer.write("Hello Foo");
writer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
文本文件范例:e-Flashcard
使用三个类来写电子版flashcard:
- QuizCardBuilder,设计并存储卡片的工具
- QuizCardPlayer,加载并播放卡片的引擎
- QuizCard,表示卡片数据的类
QuizCard
public class QuizCard {
private String question;
private String answer;
public QuizCard (String q, String a) {
question = q;
answer = a;
}
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
}
QuizCardBuilder
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
public class QuizCardBuilder {
private JTextArea question;
private JTextArea answer;
private ArrayList<QuizCard> cardList;
private JFrame frame;
public static void main(String[] args) {
QuizCardBuilder builder = new QuizCardBuilder();
builder.go();
}
public void go() {
frame = new JFrame("Quiz Card Builder");
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
Font bigFont = new Font("sanserif", Font.BOLD, 24);
question = new JTextArea(6,20);
question.setLineWrap(true);//设置在行过长的时候是否要换行
question.setWrapStyleWord(true);//设置在单词过长的时候是否要把长单词移到下一行
question.setFont(bigFont);
JScrollPane qScroller = new JScrollPane(question);
qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
answer = new JTextArea(6,20);
answer.setLineWrap(true);//设置在行过长的时候是否要换行
answer.setWrapStyleWord(true);//设置在单词过长的时候是否要把长单词移到下一行
answer.setFont(bigFont);
JScrollPane aScroller = new JScrollPane(answer);
aScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
aScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
JButton nextButton = new JButton("Next Card");
cardList = new ArrayList<QuizCard>();
JLabel qLabel = new JLabel("Question:");
qLabel.setFont(bigFont);
JLabel aLabel = new JLabel("Answer:");
aLabel.setFont(bigFont);
mainPanel.add(qLabel);
mainPanel.add(qScroller);
mainPanel.add(aLabel);
mainPanel.add(aScroller);
mainPanel.add(nextButton);
nextButton.addActionListener(new NextCardListener());
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem newMenuItem = new JMenuItem("New");
JMenuItem saveMenuItem = new JMenuItem("Save");
newMenuItem.addActionListener(new NewMenuListener());
saveMenuItem.addActionListener(new SaveMenuListener());
fileMenu.add(newMenuItem);
fileMenu.add(saveMenuItem);
menuBar.add(fileMenu);
frame.setJMenuBar(menuBar);
frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
frame.setSize(500, 600);
frame.setVisible(true);
}
public class NextCardListener implements ActionListener {
public void actionPerformed (ActionEvent ev) {
QuizCard card = new QuizCard(question.getText(), answer.getText());
cardList.add(card);
clearCard();
}
}
public class SaveMenuListener implements ActionListener {
public void actionPerformed (ActionEvent ev) {
QuizCard card = new QuizCard(question.getText(), answer.getText());
cardList.add(card);
JFileChooser fileSave = new JFileChooser();
fileSave.showSaveDialog(frame);
saveFile(fileSave.getSelectedFile());
}
}
public class NewMenuListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
cardList.clear();
clearCard();
}
}
private void clearCard() {
question.setText("");
answer.setText("");
question.requestFocus();
}
private void saveFile(File file) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
for(QuizCard card : cardList) {
writer.write(card.getQuestion() + "/");
writer.write(card.getAnswer() + "\n");
}
writer.close();
} catch (IOException ex) {
System.out.println("couldn't write the cardlist out");
ex.getStackTrace();
}
}
}
关于JmenuBar
java.io.File.class
File这个类型代表磁盘上的文件,但并不是文件中的内容。
可以对File做的事情:
创建出代表现存盘文件的File对象。
File f = new File("MyCode.txt");
建立新的目录。
File dir = new File("Chapter"); dir.mkdir();
列出目录下的内容。
if (dir.isDirectory()) { String[] dirContents = dir.list(); for (int i = 0; i < dirContents.length; i++) { System.out.println(dirContents[i]); } }
取得文件绝对路径。
System.out.println(dir.getAbsolutePath());
删除文件或目录(成功会返回true)
bool isDeleted = f.delete();
读取文本文件
import java.io.*;
public class ReadFile {
public static void main(String[] args) {
try {
File myFile = new File("MyText.txt");//找不到文件会报错
FileReader fileReader = new FileReader(myFile);//FileReader是字符连接到文本文件的串流
BufferedReader reader = new BufferedReader(fileReader); //将FileReader链接到BufferedReader以获得更高的效率。它只会在缓冲区读空的时候才会回头到磁盘读取
String line = null; //用来存储获得的结果
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
文本文件范例:e-Flashcard
QuizCardPlayer
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
public class QuizCardPlayer {
private JTextArea display;
private ArrayList<QuizCard> cardList;
private QuizCard currentCard;
private int currentCardIndex;
private JFrame frame;
private JButton nextButton;
private boolean isShowAnswer;
public static void main(String[] args) {
QuizCardPlayer reader = new QuizCardPlayer();
reader.go();
}
public void go() {
frame = new JFrame("Quiz Card Player");
JPanel mainPanel = new JPanel();
Font bigFont = new Font("sanserif", Font.BOLD, 24);
display = new JTextArea(10,20);
display.setFont(bigFont);
display.setLineWrap(true);
display.setEditable(false);
JScrollPane qScroller = new JScrollPane(display);
qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
nextButton = new JButton("Show Qusetion");
mainPanel.add(qScroller);
mainPanel.add(nextButton);
nextButton.addActionListener(new NextCardListener());
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem loadMenuItem = new JMenuItem("Load card set");
loadMenuItem.addActionListener(new OpenMenuListener());
fileMenu.add(loadMenuItem);
menuBar.add(fileMenu);
frame.setJMenuBar(menuBar);
frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
frame.setSize(640,500);
frame.setVisible(true);
}
public class NextCardListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
if (isShowAnswer) {
//显示答案
display.setText(currentCard.getAnswer());
nextButton.setText("Next Card");
isShowAnswer = false;
} else {
//显示问题
if (cardList == null){
System.out.println("first open a card");
} else if (currentCardIndex < cardList.size()) {
showNextCard();
} else {
display.setText("That was last card");
nextButton.setEnabled(false);
}
}
}
}
public class OpenMenuListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
JFileChooser fileOpen = new JFileChooser();//打开文件的对话框让用户选择文件
fileOpen.showOpenDialog(frame);
loadFile(fileOpen.getSelectedFile());
}
}
private void loadFile(File file) {
cardList = new ArrayList<QuizCard>();
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
while ((line = reader.readLine()) != null) {//读取一行
makeCard(line);//做成QuizCard加入到cardList
}
reader.close();
} catch (Exception ex) {
System.out.println("couldn't read the card file");
ex.printStackTrace();
}
}
private void makeCard(String lineToParse) {
String[] result = lineToParse.split("/");
QuizCard card = new QuizCard(result[0], result[1]);
cardList.add(card);
System.out.println("made a card");
}
private void showNextCard() {
currentCard = cardList.get(currentCardIndex);
currentCardIndex++;
display.setText(currentCard.getQuestion());
nextButton.setText("Show Answer");
isShowAnswer = true;
}
}