10.1 Jar文件
Java归档文件,Jar文件,既可以包含类文件,也可以包含图像和声音这样类型的文件。Jar文件是压缩的,使用了zip压缩格式。
可以使用jar工具制作Jar文件,位于jdk/bin目录下。创建一个新的Jar文件的常见命令格式为
jar cvf JARFileName File1 File2...
10.1.1 清单文件
每个Jar文件还包含一个用于描述归档特征的清单文件,被命名为MANIFEST.MF,位于JAR文件的一个特殊META-INF子目录里面。
10.1.2 可运行Jar文件
10.1.3 资源
10.1.4 密封
10.2 Java Web Start
10.3 applet
104. 应用程序首选项存储
10.4.1 属性映射
属性映射是一种存储键/值对的数据结构,经常被用于存放配置信息。
实现属性映射的Java类被成为Properties。
Properties settings = new Properties(); settings.put("width", "200"); settings.put("title", "hello world"); FileOutputStream out = new FileOutputStream("program.properties"); settings.store(out, "Program Properties");
FileInputStream in = new FileInputStream("program.properties");
settings.load(in);
import java.awt.EventQueue; import java.awt.event.*; import java.io.*; import java.util.Properties; import javax.swing.*; public class PropertiesTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { PropertiesFrame frame = new PropertiesFrame(); frame.setVisible(true); } }); } } class PropertiesFrame extends JFrame { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; private File propertiesFile; private Properties settings; public PropertiesFrame() { // get position, size, title from properties String userDir = System.getProperty("user.home"); File propertiesDir = new File(userDir, ".corejava"); if (!propertiesDir.exists()) propertiesDir.mkdir(); propertiesFile = new File(propertiesDir, "program.properties"); Properties defaultSettings = new Properties(); defaultSettings.put("left", "0"); defaultSettings.put("top", "0"); defaultSettings.put("width", "" + DEFAULT_WIDTH); defaultSettings.put("height", "" + DEFAULT_HEIGHT); defaultSettings.put("title", ""); settings = new Properties(defaultSettings); if (propertiesFile.exists()) try { FileInputStream in = new FileInputStream(propertiesFile); settings.load(in); } catch (IOException ex) { ex.printStackTrace(); } int left = Integer.parseInt(settings.getProperty("left")); int top = Integer.parseInt(settings.getProperty("top")); int width = Integer.parseInt(settings.getProperty("width")); int height = Integer.parseInt(settings.getProperty("height")); setBounds(left, top, width, height); // if no title given, ask user String title = settings.getProperty("title"); if (title.equals("")) title = JOptionPane.showInputDialog("Please supply a frame title:"); if (title == null) title = ""; setTitle(title); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { settings.put("left", "" + getX()); settings.put("top", "" + getY()); settings.put("width", "" + getWidth()); settings.put("height", "" + getHeight()); settings.put("title", getTitle()); try { FileOutputStream out = new FileOutputStream(propertiesFile); settings.store(out, "Program Properties"); } catch (IOException ex) { ex.printStackTrace(); } System.exit(0); } }); } }
10.4.2 Preferences API
Properties类能够简化和保存配置信息的过程,但是存在下列不足:配置文件不能存放在主目录;没有标志的为配置文件命名的规则。
Preferences类提供了一个平台无关的中心知识库,具有树状结构,每个节点可以存放键/值对的独立表。
Preferences root = Preferences.userRoot(); Preferences root = Preferences.systemRoot(); Preferences node = root.node("/com/company/myapp");
import java.awt.EventQueue; import java.awt.event.*; import java.io.*; import java.util.prefs.*; import javax.swing.*; public class PreferencesTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { PreferencesFrame frame = new PreferencesFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } class PreferencesFrame extends JFrame { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; public PreferencesFrame() { // get position, size, title from preferences Preferences root = Preferences.userRoot(); final Preferences node = root.node("/com/horstmann/corejava"); int left = node.getInt("left", 0); int top = node.getInt("top", 0); int width = node.getInt("width", DEFAULT_WIDTH); int height = node.getInt("height", DEFAULT_HEIGHT); setBounds(left, top, width, height); // if no title given, ask user String title = node.get("title", ""); if (title.equals("")) title = JOptionPane.showInputDialog("Please supply a frame title:"); if (title == null) title = ""; setTitle(title); // set up file chooser that shows XML files final JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(new File(".")); // accept all files ending with .xml chooser.setFileFilter(new javax.swing.filechooser.FileFilter() { public boolean accept(File f) { return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory(); } public String getDescription() { return "XML files"; } }); // set up menus JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu menu = new JMenu("File"); menuBar.add(menu); JMenuItem exportItem = new JMenuItem("Export preferences"); menu.add(exportItem); exportItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { if (chooser.showSaveDialog(PreferencesFrame.this) == JFileChooser.APPROVE_OPTION) { try { OutputStream out = new FileOutputStream(chooser.getSelectedFile()); node.exportSubtree(out); out.close(); } catch (Exception e) { e.printStackTrace(); } } } }); JMenuItem importItem = new JMenuItem("Import preferences"); menu.add(importItem); importItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { if (chooser.showOpenDialog(PreferencesFrame.this) == JFileChooser.APPROVE_OPTION) { try { InputStream in = new FileInputStream(chooser.getSelectedFile()); Preferences.importPreferences(in); in.close(); } catch (Exception e) { e.printStackTrace(); } } } }); JMenuItem exitItem = new JMenuItem("Exit"); menu.add(exitItem); exitItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { node.putInt("left", getX()); node.putInt("top", getY()); node.putInt("width", getWidth()); node.putInt("height", getHeight()); node.put("title", getTitle()); System.exit(0); } }); } }