[英]Good way to store JTable data for longterm?
在当前项目中,我正在使用JTable
和DefaultTableModel
。 到目前为止,一切工作正常,并且当前用于保存TableModel,我只是将对象序列化到磁盘上。
因为这可能是保存和加载数据的一种合理方法,所以我不喜欢数据完全以字节形式“模糊处理”。 如果发生不良情况,这几乎使数据无法挽救。 另一个问题是序列化UUID ,这使得更新程序变得更加困难,并且不会使数据不可卸载。
多年来,该数据库将被填充,并将包含重要信息。 为了使数据可恢复,我想将TableModel解析为一个XML文件,但这失败了,因为XML Encoder无法处理JTable / TableModel。
关于以有效的“明文”形式从JTable
保存数据的建议是什么? 简单地遍历列和行并将其逐行保存到文本文件中(在列数据之间使用分隔符)是一种好方法吗? 我在这里担心的是,用户可能使用诸如“:”之类的分隔符(我可能会使用)作为表数据,并使解析器崩溃。
谢谢你的帮助。
对从
API建议使用XMLEncoder
我想将TableModel解析为XML文件,但是失败了,因为XML编码器无法处理JTable / TableModel。
您需要创建一个自定义编码器。 下面给出了DefaultTableModel的两种实现。
// Following code is a more complete version of:
// http://stackoverflow.com/q/26250939/131872
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.*;
public class DefaultTableModelPersistenceDelegateTest
{
private File file = new File("TableModel.xml");
private final JTextArea textArea = new JTextArea();
private final String[] columnNames = {"Column1", "Column2"};
private final Object[][] data =
{
{"aaa", new Integer(1)},
{"bbb\u2600", new Integer(2)}
};
private DefaultTableModel model = new DefaultTableModel(data, columnNames);
private final JTable table = new JTable(model);
public JComponent makeUI()
{
model.setColumnCount(5);
JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
sp.setResizeWeight(.3);
sp.setTopComponent(new JScrollPane(table));
sp.setBottomComponent(new JScrollPane(textArea));
JPanel p = new JPanel();
p.add(new JButton(new AbstractAction("XMLEncoder")
{
@Override
public void actionPerformed(ActionEvent e)
{
try
{
OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
XMLEncoder xe = new XMLEncoder(os);
xe.setPersistenceDelegate(DefaultTableModel.class, new DefaultTableModelPersistenceDelegate());
xe.writeObject(model);
xe.close();
Reader r = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
textArea.read(r, null);
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}));
p.add(new JButton(new AbstractAction("XMLDecoder")
{
@Override
public void actionPerformed(ActionEvent e)
{
try
{
InputStream is = new BufferedInputStream( new FileInputStream( file ));
XMLDecoder xd = new XMLDecoder(is);
model = (DefaultTableModel)xd.readObject();
table.setModel(model);
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}));
p.add(new JButton(new AbstractAction("clear")
{
@Override
public void actionPerformed(ActionEvent e)
{
model = new DefaultTableModel();
table.setModel(model);
}
}));
JPanel pnl = new JPanel(new BorderLayout());
pnl.add(sp);
pnl.add(p, BorderLayout.SOUTH);
return pnl;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
@Override public void run()
{
createAndShowGUI();
}
});
}
public static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new DefaultTableModelPersistenceDelegateTest().makeUI());
f.setSize(420, 340);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
// See following link for more information on Using XMLEncoder:
// http://www.oracle.com/technetwork/java/persistence4-140124.html
class DefaultTableModelPersistenceDelegate extends DefaultPersistenceDelegate
{
// Initially creates an empty DefaultTableModel. The columns are created
// and finally each row of data is added to the model.
@Override
protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder encoder)
{
DefaultTableModel model= (DefaultTableModel)oldInstance;
// Create XML to restore the column names
Vector<String> columnNames = new Vector<String>(model.getColumnCount());
for (int i = 0; i < model.getColumnCount(); i++)
{
columnNames.add( model.getColumnName(i) );
}
Object[] columnNamesData = new Object[] { columnNames };
encoder.writeStatement(new Statement(oldInstance, "setColumnIdentifiers", columnNamesData));
// Create XML to restore row data
Vector row = model.getDataVector();
for (int i = 0; i < model.getRowCount(); i++)
{
Object[] rowData = new Object[] { row.get(i) };
encoder.writeStatement(new Statement(oldInstance, "addRow", rowData));
}
}
}
class DefaultTableModelPersistenceDelegate2 extends DefaultPersistenceDelegate
{
// Initially creates a DefaultTableModel with rows and columns. Then the
// columns are reset and proper names are used. Finally data is set for each
// cell in the model.
@Override
protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder encoder)
{
super.initialize(type, oldInstance, newInstance, encoder);
DefaultTableModel model= (DefaultTableModel)oldInstance;
// Create XML to restore the column names
Vector<String> columnNames = new Vector<String>(model.getColumnCount());
for (int i = 0; i < model.getColumnCount(); i++)
{
columnNames.add( model.getColumnName(i) );
}
Object[] columnNamesData = new Object[] { columnNames };
encoder.writeStatement(new Statement(oldInstance, "setColumnIdentifiers", columnNamesData));
// Create XML to reset the value of every cell to its value
for (int row = 0; row < model.getRowCount(); row++)
{
for (int col = 0; col < model.getColumnCount(); col++)
{
Object[] o = new Object[] {model.getValueAt(row, col), row, col};
encoder.writeStatement(new Statement(oldInstance, "setValueAt", o));
}
}
}
}
您应该仅使用模型并对其进行序列化,而不应使用GUI对象(因为这样做的方式,也许序列化不是您的最佳选择)。 如果要为此目的存储表“标题”( JTable
列的布局),则使用其他模型(+/-表列模型-我没有Java环境)。
编辑:如果这个项目是旧的或重要的,并且您认为值得花费时间,那么也许您应该重新考虑您的Model类?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.