最近想做一个功能,就是把我们编译后的字节码及其资源文件打包成一个可执行的jar包,在装有jre的机器上双击就能运行。

  首先是我们需要选择哪些字节码和文件需要打包到文件中,这个我们用JFileChooser来做,让用户选择,我做了一个窗体来让用户选择。

  效果如下:

  

  我们让浏览文件系统,并选择需要打包的文件夹,然后计算出可以作为启动类的文件,通过下方的下拉让用户选择。

  生成文件路径在确认按钮点击后弹出文件保存框让用户选择就好(也可以弹出输入框)。

  代码如下:

  Main

  1. package org.coderecord.commons.ejarmaker;
  2.  
  3. import java.awt.EventQueue;
  4.  
  5. import javax.swing.UIManager;
  6. import javax.swing.UnsupportedLookAndFeelException;
  7.  
  8. public class Main {
  9.  
  10. public static void main(String[] args) {
  11. try {
  12. UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
  13. } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
  14. e.printStackTrace();
  15. }
  16. EventQueue.invokeLater(new Runnable() {
  17.  
  18. @Override
  19. public void run() {
  20. new FrmMain().setVisible(true);
  21. }
  22. });
  23. }
  24.  
  25. }

Main

  FrmMain(只是界面代码,业务代码最后贴出)

  1. package org.coderecord.commons.ejarmaker;
  2.  
  3. import java.awt.Toolkit;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.io.File;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9.  
  10. import javax.swing.JButton;
  11. import javax.swing.JComboBox;
  12. import javax.swing.JFileChooser;
  13. import javax.swing.JFrame;
  14. import javax.swing.JLabel;
  15. import javax.swing.JScrollPane;
  16. import javax.swing.JTextArea;
  17. import javax.swing.filechooser.FileFilter;
  18.  
  19. public class FrmMain extends JFrame implements ActionListener {
  20.  
  21. private static final long serialVersionUID = 2016913328739206536L;
  22. // 选择的文件(用户在文件选择器中选择的)
  23. private List<File> userSelectedFiles = new ArrayList<>();
  24. // 我们经过分析得到的最终会被打包的文件
  25. private List<File> finalFiles = new ArrayList<>();
  26.  
  27. public FrmMain() {
  28. setSize(480, 320);
  29. setResizable(false);
  30. setLocationRelativeTo(null);
  31. setTitle("通用可执行Jar包生成工具");
  32. setDefaultCloseOperation(EXIT_ON_CLOSE);
  33. setLayout(null);
  34. // 在运行时获取资源文件的方式,一定是使用Class.getResource方式
  35. // 在jar包中这种方式也行得通
  36. // ‘/’代表根路径
  37. setIconImage(Toolkit.getDefaultToolkit().getImage(FrmMain.class.getResource("/resources/icon.png")));
  38. initComponents();
  39. }
  40.  
  41. // 初始化组件
  42. private void initComponents() {
  43. // 提示
  44. lblTip = new JLabel("选择需要打包的文件并设置启动类");
  45. lblTip.setLocation(20, 10);
  46. lblTip.setSize(350, 20);
  47. add(lblTip);
  48.  
  49. // 浏览按钮
  50. btnBrowser = new JButton("浏 览");
  51. btnBrowser.setLocation(380, 10);
  52. btnBrowser.setSize(80, 24);
  53. btnBrowser.addActionListener(this);
  54. add(btnBrowser);
  55.  
  56. // 展示已选择文件
  57. JScrollPane jspFiles = new JScrollPane();
  58. txtFiles = new JTextArea();
  59. txtFiles.setEditable(false);
  60. jspFiles.setSize(440, 160);
  61. jspFiles.setLocation(20, 40);
  62. txtFiles.setSize(440, 201600);
  63. txtFiles.setLocation(20, 40);
  64. txtFiles.setFocusable(false);
  65. jspFiles.setViewportView(txtFiles);
  66. add(jspFiles);
  67.  
  68. // 选择启动类
  69. cobMainClass = new JComboBox<>();
  70. cobMainClass.setSize(440, 30);
  71. cobMainClass.setLocation(20, 210);
  72. add(cobMainClass);
  73.  
  74. // 清除已选
  75. btnCls = new JButton("重 选");
  76. btnCls.setLocation(20, 250);
  77. btnCls.setSize(80, 24);
  78. btnCls.addActionListener(this);
  79. add(btnCls);
  80.  
  81. // 确认按钮
  82. btnConfirm = new JButton("确认");
  83. btnConfirm.setSize(80, 24);
  84. btnConfirm.setLocation(380, 250);
  85. btnConfirm.addActionListener(this);
  86. add(btnConfirm);
  87.  
  88. // 文件选择器
  89. jfcSelect = new JFileChooser();
  90. // 可以选择文件和文件夹
  91. jfcSelect.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
  92. // 可以多选
  93. jfcSelect.setMultiSelectionEnabled(true);
  94.  
  95. // 文件保存
  96. jfcSave = new JFileChooser();
  97. // 设置只接受以“.jar”结尾的文件
  98. jfcSave.setAcceptAllFileFilterUsed(false);
  99. jfcSave.setFileFilter(new FileFilter() {
  100.  
  101. @Override
  102. public String getDescription() {
  103. return "可执行Jar";
  104. }
  105.  
  106. @Override
  107. public boolean accept(File f) {
  108. return f.getName().endsWith(".jar");
  109. }
  110. });
  111. }
  112.  
  113. @Override
  114. public void actionPerformed(ActionEvent e) {
  115.  
  116. }
  117.  
  118. private JLabel lblTip;
  119. private JButton btnBrowser;
  120. private JFileChooser jfcSelect;
  121. private JTextArea txtFiles;
  122. private JComboBox<String> cobMainClass;
  123. private JButton btnCls;
  124. private JButton btnConfirm;
  125. private JFileChooser jfcSave;
  126. }

FrmMain_UI

  然后开始业务部分,首先是选择文件,我们允许用户选择多个文件和文件夹(甚至可以通过多次选择来选择不同盘符、路径下的文件和文件夹),在选择后可能有重复的地方或两次选择后有包含的项目,我们要去除。

  我们为“浏览”按钮事件添加处理,让用户选择文件并处理选中文件:

  1. @Override
  2. public void actionPerformed(ActionEvent e) {
  3. if(e.getSource() == btnBrowser) {
  4. // 浏览
  5. int result = jfcSelect.showOpenDialog(this);
  6.  
  7. // 选择了文件
  8. if(result == JFileChooser.APPROVE_OPTION) {
  9. for(File file : jfcSelect.getSelectedFiles())
  10. userSelectedFiles.add(file);
  11.  
  12. // 整理选择的文件,去除重复项
  13. removeDuplicateItems(userSelectedFiles);
  14.  
  15. // 重新计算选中文件
  16. finalFiles.clear();
  17. for(File file : userSelectedFiles)
  18. addFileToList(file, finalFiles);
  19.  
  20. // 计算文件展示打包路径及展示路径
  21. // 计算可启动类路径
  22. // 展示到文本框中
  23. cobMainClass.removeAllItems();
  24. txtFiles.setText("");
  25. File file,direc;
  26. String filePath,direcPath;
  27. Iterator<File> itd,itf;
  28. for(itd = userSelectedFiles.iterator(); itd.hasNext();) {
  29. direc = itd.next();
  30. direcPath = direc.getAbsolutePath();
  31. for(itf = finalFiles.iterator(); itf.hasNext();) {
  32. file = itf.next();
  33. filePath = file.getAbsolutePath();
  34. if(filePath.equalsIgnoreCase(direcPath)) {
  35. txtFiles.append(file.getName() + "\n");
  36. filePaths.put(file.getName(), file);
  37. //fileNames.put(file.getName(), file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
  38. if(file.getName().endsWith(".class"))
  39. cobMainClass.addItem(file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
  40. itf.remove();
  41. } else if(filePath.startsWith(direcPath)) {
  42. String nameTmp = filePath.substring(direcPath.lastIndexOf(File.separator) + 1).replace(File.separatorChar, '/');
  43. filePaths.put(nameTmp, file);
  44. txtFiles.append(nameTmp + "\n");
  45. //fileNames.put(nameTmp, nameTmp.endsWith(".class")?nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'):nameTmp);
  46. if(nameTmp.endsWith(".class") && nameTmp.indexOf('$') == -1)
  47. cobMainClass.addItem(nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'));
  48. itf.remove();
  49. }
  50. }
  51. }
  52. }
  53. }
  54. }
  55.  
  56. // 添加文件(非文件夹)到集合
  57. private void addFileToList(File file, List<File> fileArr) {
  58. if(file.isDirectory())
  59. for(File child : file.listFiles())
  60. addFileToList(child, fileArr);
  61. else
  62. fileArr.add(file);
  63. }
  64.  
  65. // 去除重复项
  66. private void removeDuplicateItems(List<File> fileArr) {
  67. // 去重复项
  68. Set<String> directories = new HashSet<>();
  69. Set<String> files = new HashSet<>();
  70. for(File file : fileArr)
  71. if(file.isDirectory())
  72. directories.add(file.getAbsolutePath());
  73. else
  74. files.add(file.getAbsolutePath());
  75. //去包含项(先去文件夹再去文件应该更好)
  76. String fpath,dpath;
  77. for(Iterator<String> itf = files.iterator(); itf.hasNext();) {
  78. fpath = itf.next();
  79. for(Iterator<String> itd = directories.iterator(); itd.hasNext();) {
  80. dpath = itd.next();
  81. if(fpath.startsWith(dpath))
  82. itf.remove();
  83. }
  84. }
  85. String dpath1,dpath2;
  86. Set<String> directories1 = new HashSet<>(directories);
  87. for(Iterator<String> itd1 = directories.iterator(); itd1.hasNext();) {
  88. dpath1 = itd1.next();
  89. for(Iterator<String> itd2 = directories1.iterator(); itd2.hasNext();) {
  90. dpath2 = itd2.next();
  91. if(dpath1.equals(dpath2))
  92. continue;
  93. else if(dpath2.startsWith(dpath1))
  94. itd2.remove();
  95. else if(dpath1.startsWith(dpath2))
  96. itd1.remove();
  97. }
  98. }
  99. directories.addAll(directories1);
  100.  
  101. fileArr.clear();
  102. for(String file : files)
  103. fileArr.add(new File(file));
  104. for(String directory : directories)
  105. fileArr.add(new File(directory));
  106. }

btnBrowser_event_handler

  “重选”按钮点击后清除已选项,逻辑就先不详细介绍了。

  然后是“确定”按钮,我们弹出文件保存框让用户选择保存位置,然后生成可执行的jar包:

  1. @Override
  2. public void actionPerformed(ActionEvent e) {
  3. if(e.getSource() == btnBrowser) {
  4. } else if(e.getSource() == btnCls) {
  5. if(userSelectedFiles.size() == 0) return;
  6. else if(JOptionPane.showConfirmDialog(this, "确定重选吗?将清除所有已选项!") == JOptionPane.OK_OPTION) {
  7. userSelectedFiles.clear();
  8. finalFiles.clear();
  9. filePaths.clear();
  10. cobMainClass.removeAllItems();
  11. }
  12. } else if(e.getSource() == btnConfirm) {
  13. if(filePaths.size() == 0) {
  14. JOptionPane.showMessageDialog(this, "未选择文件", "错误", JOptionPane.ERROR_MESSAGE);
  15. return;
  16. } else if(cobMainClass.getSelectedItem() == null) {
  17. JOptionPane.showMessageDialog(this, "未选择启动类", "错误", JOptionPane.ERROR_MESSAGE);
  18. return;
  19. }
  20. // 打包
  21. int result = jfcSave.showSaveDialog(this);
  22. if(result == JFileChooser.APPROVE_OPTION) {
  23. try {
  24. // 清单文件
  25. Manifest man = new Manifest();
  26. // 版本和启动类路径必要
  27. man.getMainAttributes().putValue(Name.MANIFEST_VERSION.toString(), "1.0");
  28. man.getMainAttributes().putValue(Name.MAIN_CLASS.toString(), cobMainClass.getSelectedItem().toString());
  29. // Class-Path一定不要,除非能保证将引用类(即import的类)都联合打包了
  30. JarOutputStream jos = new JarOutputStream(new FileOutputStream(jfcSave.getSelectedFile()), man);
  31. jos.setLevel(Deflater.BEST_COMPRESSION);
  32. BufferedInputStream bis = null;
  33. byte[] cache = new byte[1024];
  34. StringBuffer config = new StringBuffer();
  35. for(String name : filePaths.keySet()) {
  36. bis = new BufferedInputStream(new FileInputStream(filePaths.get(name)), 1024);
  37. config.append(name).append('=').append(bis.available()).append('\n');
  38. jos.putNextEntry(new JarEntry(name));
  39. int count;
  40. while((count = bis.read(cache, 0, 1024)) != -1)
  41. jos.write(cache, 0, count);
  42. jos.closeEntry();
  43. bis.close();
  44. }
  45. jos.flush();
  46. jos.close();
  47. JOptionPane.showMessageDialog(this, "导出成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
  48. System.exit(0);
  49. } catch(Exception ex) {
  50. JOptionPane.showMessageDialog(this, ex.getMessage(), "异常", JOptionPane.ERROR_MESSAGE);
  51. System.exit(1);
  52. }
  53. }
  54. }
  55.  
  56. }

btnConfirm_event_handler

  当然,这里还有一个小问题:选择文件(自己写的文件名就算不加后缀也能保存成功-_-)。

  先展示一下结果:

  

  在文件系统中选择:

  

  导出到桌面:

  

  

  运行一下:

  

  我最后再将完整的源码贴出一份:

  1. package org.coderecord.commons.ejarmaker;
  2.  
  3. import java.awt.Toolkit;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.io.BufferedInputStream;
  7. import java.io.File;
  8. import java.io.FileInputStream;
  9. import java.io.FileOutputStream;
  10. import java.util.ArrayList;
  11. import java.util.HashSet;
  12. import java.util.Hashtable;
  13. import java.util.Iterator;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Set;
  17. import java.util.jar.JarEntry;
  18. import java.util.jar.JarOutputStream;
  19. import java.util.jar.Manifest;
  20. import java.util.jar.Attributes.Name;
  21. import java.util.zip.Deflater;
  22.  
  23. import javax.swing.JButton;
  24. import javax.swing.JComboBox;
  25. import javax.swing.JFileChooser;
  26. import javax.swing.JFrame;
  27. import javax.swing.JLabel;
  28. import javax.swing.JOptionPane;
  29. import javax.swing.JScrollPane;
  30. import javax.swing.JTextArea;
  31. import javax.swing.filechooser.FileFilter;
  32.  
  33. public class FrmMain extends JFrame implements ActionListener {
  34.  
  35. private static final long serialVersionUID = 2016913328739206536L;
  36. // 选择的文件(用户在文件选择器中选择的)
  37. private List<File> userSelectedFiles = new ArrayList<>();
  38. // 我们经过分析得到的最终会被打包的文件
  39. private List<File> finalFiles = new ArrayList<>();
  40. // 文件打包路径及物理文件
  41. private Map<String, File> filePaths = new Hashtable<>();
  42.  
  43. public FrmMain() {
  44. setSize(480, 320);
  45. setResizable(false);
  46. setLocationRelativeTo(null);
  47. setTitle("通用可执行Jar包生成工具");
  48. setDefaultCloseOperation(EXIT_ON_CLOSE);
  49. setLayout(null);
  50. // 在运行时获取资源文件的方式,一定是使用Class.getResource方式
  51. // 在jar包中这种方式也行得通
  52. // ‘/’代表根路径
  53. setIconImage(Toolkit.getDefaultToolkit().getImage(FrmMain.class.getResource("/resources/icon.png")));
  54. initComponents();
  55. }
  56.  
  57. // 初始化组件
  58. private void initComponents() {
  59. // 提示
  60. lblTip = new JLabel("选择需要打包的文件并设置启动类");
  61. lblTip.setLocation(20, 10);
  62. lblTip.setSize(350, 20);
  63. add(lblTip);
  64.  
  65. // 浏览按钮
  66. btnBrowser = new JButton("浏 览");
  67. btnBrowser.setLocation(380, 10);
  68. btnBrowser.setSize(80, 24);
  69. btnBrowser.addActionListener(this);
  70. add(btnBrowser);
  71.  
  72. // 展示已选择文件
  73. JScrollPane jspFiles = new JScrollPane();
  74. txtFiles = new JTextArea();
  75. txtFiles.setEditable(false);
  76. jspFiles.setSize(440, 160);
  77. jspFiles.setLocation(20, 40);
  78. txtFiles.setSize(440, 201600);
  79. txtFiles.setLocation(20, 40);
  80. txtFiles.setFocusable(false);
  81. jspFiles.setViewportView(txtFiles);
  82. add(jspFiles);
  83.  
  84. // 选择启动类
  85. cobMainClass = new JComboBox<>();
  86. cobMainClass.setSize(440, 30);
  87. cobMainClass.setLocation(20, 210);
  88. add(cobMainClass);
  89.  
  90. // 清除已选
  91. btnCls = new JButton("重 选");
  92. btnCls.setLocation(20, 250);
  93. btnCls.setSize(80, 24);
  94. btnCls.addActionListener(this);
  95. add(btnCls);
  96.  
  97. // 确认按钮
  98. btnConfirm = new JButton("确认");
  99. btnConfirm.setSize(80, 24);
  100. btnConfirm.setLocation(380, 250);
  101. btnConfirm.addActionListener(this);
  102. add(btnConfirm);
  103.  
  104. // 文件选择器
  105. jfcSelect = new JFileChooser();
  106. // 可以选择文件和文件夹
  107. jfcSelect.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
  108. // 可以多选
  109. jfcSelect.setMultiSelectionEnabled(true);
  110.  
  111. // 文件保存
  112. jfcSave = new JFileChooser();
  113. // 设置只接受以“.jar”结尾的文件
  114. jfcSave.setAcceptAllFileFilterUsed(false);
  115. jfcSave.setFileFilter(new FileFilter() {
  116.  
  117. @Override
  118. public String getDescription() {
  119. return "可执行Jar";
  120. }
  121.  
  122. @Override
  123. public boolean accept(File f) {
  124. return f.getName().endsWith(".jar");
  125. }
  126. });
  127. }
  128.  
  129. @Override
  130. public void actionPerformed(ActionEvent e) {
  131. if(e.getSource() == btnBrowser) {
  132. // 浏览
  133. int result = jfcSelect.showOpenDialog(this);
  134.  
  135. // 选择了文件
  136. if(result == JFileChooser.APPROVE_OPTION) {
  137. for(File file : jfcSelect.getSelectedFiles())
  138. userSelectedFiles.add(file);
  139.  
  140. // 整理选择的文件,去除重复项
  141. removeDuplicateItems(userSelectedFiles);
  142.  
  143. // 重新计算选中文件
  144. finalFiles.clear();
  145. for(File file : userSelectedFiles)
  146. addFileToList(file, finalFiles);
  147.  
  148. // 计算文件展示打包路径及展示路径
  149. // 计算可启动类路径
  150. // 展示到文本框中
  151. cobMainClass.removeAllItems();
  152. txtFiles.setText("");
  153. File file,direc;
  154. String filePath,direcPath;
  155. Iterator<File> itd,itf;
  156. for(itd = userSelectedFiles.iterator(); itd.hasNext();) {
  157. direc = itd.next();
  158. direcPath = direc.getAbsolutePath();
  159. for(itf = finalFiles.iterator(); itf.hasNext();) {
  160. file = itf.next();
  161. filePath = file.getAbsolutePath();
  162. if(filePath.equalsIgnoreCase(direcPath)) {
  163. txtFiles.append(file.getName() + "\n");
  164. filePaths.put(file.getName(), file);
  165. if(file.getName().endsWith(".class"))
  166. cobMainClass.addItem(file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
  167. itf.remove();
  168. } else if(filePath.startsWith(direcPath)) {
  169. String nameTmp = filePath.substring(direcPath.lastIndexOf(File.separator) + 1).replace(File.separatorChar, '/');
  170. filePaths.put(nameTmp, file);
  171. txtFiles.append(nameTmp + "\n");
  172. if(nameTmp.endsWith(".class") && nameTmp.indexOf('$') == -1)
  173. cobMainClass.addItem(nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'));
  174. itf.remove();
  175. }
  176. }
  177. }
  178. }
  179. } else if(e.getSource() == btnCls) {
  180. if(userSelectedFiles.size() == 0) return;
  181. else if(JOptionPane.showConfirmDialog(this, "确定重选吗?将清除所有已选项!") == JOptionPane.OK_OPTION) {
  182. userSelectedFiles.clear();
  183. finalFiles.clear();
  184. filePaths.clear();
  185. cobMainClass.removeAllItems();
  186. }
  187. } else if(e.getSource() == btnConfirm) {
  188. if(filePaths.size() == 0) {
  189. JOptionPane.showMessageDialog(this, "未选择文件", "错误", JOptionPane.ERROR_MESSAGE);
  190. return;
  191. } else if(cobMainClass.getSelectedItem() == null) {
  192. JOptionPane.showMessageDialog(this, "未选择启动类", "错误", JOptionPane.ERROR_MESSAGE);
  193. return;
  194. }
  195. // 打包
  196. int result = jfcSave.showSaveDialog(this);
  197. if(result == JFileChooser.APPROVE_OPTION) {
  198. try {
  199. // 清单文件
  200. Manifest man = new Manifest();
  201. // 版本和启动类路径必要
  202. man.getMainAttributes().putValue(Name.MANIFEST_VERSION.toString(), "1.0");
  203. man.getMainAttributes().putValue(Name.MAIN_CLASS.toString(), cobMainClass.getSelectedItem().toString());
  204. // Class-Path一定不要,除非能保证将引用类(即import的类)都联合打包了
  205. JarOutputStream jos = new JarOutputStream(new FileOutputStream(jfcSave.getSelectedFile()), man);
  206. jos.setLevel(Deflater.BEST_COMPRESSION);
  207. BufferedInputStream bis = null;
  208. byte[] cache = new byte[1024];
  209. StringBuffer config = new StringBuffer();
  210. for(String name : filePaths.keySet()) {
  211. bis = new BufferedInputStream(new FileInputStream(filePaths.get(name)), 1024);
  212. config.append(name).append('=').append(bis.available()).append('\n');
  213. jos.putNextEntry(new JarEntry(name));
  214. int count;
  215. while((count = bis.read(cache, 0, 1024)) != -1)
  216. jos.write(cache, 0, count);
  217. jos.closeEntry();
  218. bis.close();
  219. }
  220. jos.flush();
  221. jos.close();
  222. JOptionPane.showMessageDialog(this, "导出成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
  223. System.exit(0);
  224. } catch(Exception ex) {
  225. JOptionPane.showMessageDialog(this, ex.getMessage(), "异常", JOptionPane.ERROR_MESSAGE);
  226. System.exit(1);
  227. }
  228. }
  229. }
  230.  
  231. }
  232.  
  233. // 添加文件(非文件夹)到集合
  234. private void addFileToList(File file, List<File> fileArr) {
  235. if(file.isDirectory())
  236. for(File child : file.listFiles())
  237. addFileToList(child, fileArr);
  238. else
  239. fileArr.add(file);
  240. }
  241.  
  242. // 去除重复项
  243. private void removeDuplicateItems(List<File> fileArr) {
  244. // 去重复项
  245. Set<String> directories = new HashSet<>();
  246. Set<String> files = new HashSet<>();
  247. for(File file : fileArr)
  248. if(file.isDirectory())
  249. directories.add(file.getAbsolutePath());
  250. else
  251. files.add(file.getAbsolutePath());
  252. //去包含项(先去文件夹再去文件应该更好)
  253. String fpath,dpath;
  254. for(Iterator<String> itf = files.iterator(); itf.hasNext();) {
  255. fpath = itf.next();
  256. for(Iterator<String> itd = directories.iterator(); itd.hasNext();) {
  257. dpath = itd.next();
  258. if(fpath.startsWith(dpath))
  259. itf.remove();
  260. }
  261. }
  262. String dpath1,dpath2;
  263. Set<String> directories1 = new HashSet<>(directories);
  264. for(Iterator<String> itd1 = directories.iterator(); itd1.hasNext();) {
  265. dpath1 = itd1.next();
  266. for(Iterator<String> itd2 = directories1.iterator(); itd2.hasNext();) {
  267. dpath2 = itd2.next();
  268. if(dpath1.equals(dpath2))
  269. continue;
  270. else if(dpath2.startsWith(dpath1))
  271. itd2.remove();
  272. else if(dpath1.startsWith(dpath2))
  273. itd1.remove();
  274. }
  275. }
  276. directories.addAll(directories1);
  277.  
  278. fileArr.clear();
  279. for(String file : files)
  280. fileArr.add(new File(file));
  281. for(String directory : directories)
  282. fileArr.add(new File(directory));
  283. }
  284.  
  285. private JLabel lblTip;
  286. private JButton btnBrowser;
  287. private JFileChooser jfcSelect;
  288. private JTextArea txtFiles;
  289. private JComboBox<String> cobMainClass;
  290. private JButton btnCls;
  291. private JButton btnConfirm;
  292. private JFileChooser jfcSave;
  293. }

FrmMain

  这里有我导出的文件(这个是eclipse导出的,它在manifest中加入了classPath没有错误,我有时候加入后有问题)。

欢迎您移步我们的交流群,无聊的时候大家一起打发时间:

或者通过QQ与我联系:

(最后编辑时间2014-03-02 16:12:50)

使用原生Java代码生成可执行Jar包的更多相关文章

  1. 使用eclipse创建java程序可执行jar包

    一.eclipse中,在要打成jar包的项目名上右击,出现如下弹出框,选择“export”: 二.在接下来出现的界面中点击“jar file”,然后next: 三.在接下来出现的界面中,如图所示勾选上 ...

  2. JAVA生成(可执行)Jar包的全面详解说明 [打包][SpringBoot][Eclipse][IDEA][Maven][Gradle][分离][可执行]

    辛苦所得,转载还请注明: https://www.cnblogs.com/applerosa/p/9739007.html  得空整理了关于java 开发中,所有打包方式的 一个操作方法, 有基于ID ...

  3. Java打包可执行jar包 包含外部文件

    外部文件在程序中设置成相对当前工程路径,执行jar包时,将外部文件放在和jar包平级的目录. public class Main { 3 public static void main(String[ ...

  4. java 生成可执行jar包

    jar -cvfm my.jar [配置主函数入口文件] [包] Main-Class: 包名.类名   注意“:”后边有一个空格,类名后边要有回车换行

  5. java 执行 jar 包中的 main 方法

    java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...

  6. IntelliJ IDEA导出Java 可执行Jar包

    原文:IntelliJ IDEA导出Java 可执行Jar包 保证自己的Java代码是没有问题的,在IDEA里面是可以正常运行的,然后,按下面步骤: 打开File -> Project Stru ...

  7. eclipse生成【带有外部jar包】的java可执行jar包

    之前有写过一篇使用eclipse生成java可执行jar包,但是最近的一次使用中无论如何都不成功,当双击执行打成的jar时,弹出如下错误: could not find the main class: ...

  8. java -jar 执行jar包出现 java.lang.NoClassDefFoundError

    我用idea工具将自己开发java程序打成一个可执行的jar包,当然用eclipse或者直接用jar命令行都无所谓,本质都是将程序归档到一个压缩包,并附带一个说明清单文件. 打jar的操作其实很简单, ...

  9. java执行jar包出错:Unable to access jarfile

    java执行jar包出错:Unable to access jarfile 错误的原因有多种: 1.一般都是路径不正确.在Windows中,正确的路径类似于: java -jar "D:\W ...

随机推荐

  1. chapter15中使用generator来实现异步化操作的同步化表达的例子

    在p203中作者给了一个例子,我感觉这个例子写的不好,一开始我没有看懂,因为中间有很多细节没有交代,直到看了第二个用generator来实现ajax的例子之后才有所领悟.   所以我把作者给的这个用g ...

  2. 使用GPStracker自建卫星定位跟踪平台

    经常有人问,我能不能手机定位跟踪谁谁谁,我能不能定位跟踪我的车,等等问题. 话说不难,确实,需要客户端和服务端结合起来就能实现. 今天就给大家介绍一下GPStracker,一套开源的定位跟踪系统,有手 ...

  3. VTK拾取网格模型上的可见点

    消隐与Z-Buffer 使用缓冲器记录物体表面在屏幕上投影所覆盖范围内的全部像素的深度值,依次访问屏幕范围内物体表面所覆盖的每一像素,用深度小(深度用z值表示,z值小表示离视点近)的像素点颜色替代深度 ...

  4. oracle完全删除实例

    问题描述: 重建oracle库实例,因此要删除数据库实例 问题解决: 利用自用自带的dbca库管理,实现图形化删除实例  01.登录安装oracle数据库的linux 打开xshell企业版的Xman ...

  5. 用Docker启动php-5.6 fpm服务配合宿主机nginx运行php测试环境

    因为Ubuntu18.04默认的openssl版本就是1.1.0, 而PHP5.6无法在openssl 1.1下编译 "PHP 5.6 is receiving only security ...

  6. Sequel Pro for Mac(MySQL 数据库管理工具)破解版安装

    1.软件简介    Sequel Pro 是一款管理 Mysql 的工具,界面简洁易用. 2.功能特色 FULL MYSQL SUPPORT Sequel Pro is a fast, easy-to ...

  7. WebStorm for Mac(Web 前端开发工具)破解版安装

    1.软件简介    WebStorm 是 jetbrains 公司旗下一款 JavaScript 开发工具.目前已经被广大中国 JS 开发者誉为 "Web 前端开发神器".&quo ...

  8. Android 组件系列-----Activity生命周期

    本篇随笔将会深入学习Activity,包括如何定义多个Activity,并设置为默认的Activity.如何从一个Activity跳转到另一个Activity,还有就是详细分析Activity的生命周 ...

  9. KeyTool 和 OpenSSL 相互转换 [转]

    REM 生成自签名 CA 证书 REM Win32 OpenSSL REM http://slproweb.com/products/Win32OpenSSL.html REM How to crea ...

  10. Asp.Net WebAPI及相关技术介绍(含PPT下载)

    此PPT讲述了Asp.Net WebAPI及相关Web服务技术发展历史. 共80多页,Asp.Net WebAPI在讲到第36页的时候才会出现,因为这个技术不是凭空产生的,它有着自己的演变进化的历史. ...