Хороший способ хранить данные JTable на долгое время?
В моем текущем проекте я работаю с JTable
а также DefaultTableModel
, Пока все работает, и в настоящее время для сохранения TableModel я просто сериализую объект на диск.
Поскольку это может быть разумным способом сохранения и загрузки данных, мне не нравится тот факт, что данные полностью "запутаны" / в байтовой форме. Это делает данные практически невозможными для спасения, если происходит что-то плохое. Другая проблема - UUID сериализации, который усложняет обновление моей программы и не делает данные не загружаемыми.
База данных будет заполняться годами и будет содержать важную информацию. Чтобы восстановить данные, я хотел проанализировать TableModel в XML-файл, но это не удалось, потому что XML-кодировщик не может работать с JTable / TableModel.
Каковы рекомендации по сохранению данных из JTable
в форме "открытого текста" эффективно? Является ли простой способ перебирать столбцы и строки и сохранять их в текстовом файле (с разделителями между данными столбцов) построчно? Мои опасения заключаются в том, что пользователь может использовать разделитель, такой как ":" (который я мог бы использовать), в качестве табличных данных и вызвать сбой анализатора.
Спасибо за вашу помощь.
2 ответа
Каковы рекомендации по сохранению данных из
API рекомендует XMLEncoder
Я хотел разобрать TableModel в XML-файл, но это не удалось, потому что XML-кодировщик не может работать с JTable / TableModel.
Вам необходимо создать собственный кодировщик. Ниже приведены две реализации для DefaultTableModel.
// Following code is a more complete version of:
// http://stackru.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-среды).
РЕДАКТИРОВАТЬ: Если этот проект старый или важный, и вы думаете, стоит потратить время, то, возможно, вам следует переосмыслить свой класс модели?