使用原生Java代码生成可执行Jar包
最近想做一个功能,就是把我们编译后的字节码及其资源文件打包成一个可执行的jar包,在装有jre的机器上双击就能运行。
首先是我们需要选择哪些字节码和文件需要打包到文件中,这个我们用JFileChooser来做,让用户选择,我做了一个窗体来让用户选择。
效果如下:
我们让浏览文件系统,并选择需要打包的文件夹,然后计算出可以作为启动类的文件,通过下方的下拉让用户选择。
生成文件路径在确认按钮点击后弹出文件保存框让用户选择就好(也可以弹出输入框)。
代码如下:
Main
package org.coderecord.commons.ejarmaker; import java.awt.EventQueue; import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; public class Main { public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() { @Override
public void run() {
new FrmMain().setVisible(true);
}
});
} }
Main
FrmMain(只是界面代码,业务代码最后贴出)
package org.coderecord.commons.ejarmaker; import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List; import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.filechooser.FileFilter; public class FrmMain extends JFrame implements ActionListener { private static final long serialVersionUID = 2016913328739206536L;
// 选择的文件(用户在文件选择器中选择的)
private List<File> userSelectedFiles = new ArrayList<>();
// 我们经过分析得到的最终会被打包的文件
private List<File> finalFiles = new ArrayList<>(); public FrmMain() {
setSize(480, 320);
setResizable(false);
setLocationRelativeTo(null);
setTitle("通用可执行Jar包生成工具");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
// 在运行时获取资源文件的方式,一定是使用Class.getResource方式
// 在jar包中这种方式也行得通
// ‘/’代表根路径
setIconImage(Toolkit.getDefaultToolkit().getImage(FrmMain.class.getResource("/resources/icon.png")));
initComponents();
} // 初始化组件
private void initComponents() {
// 提示
lblTip = new JLabel("选择需要打包的文件并设置启动类");
lblTip.setLocation(20, 10);
lblTip.setSize(350, 20);
add(lblTip); // 浏览按钮
btnBrowser = new JButton("浏 览");
btnBrowser.setLocation(380, 10);
btnBrowser.setSize(80, 24);
btnBrowser.addActionListener(this);
add(btnBrowser); // 展示已选择文件
JScrollPane jspFiles = new JScrollPane();
txtFiles = new JTextArea();
txtFiles.setEditable(false);
jspFiles.setSize(440, 160);
jspFiles.setLocation(20, 40);
txtFiles.setSize(440, 201600);
txtFiles.setLocation(20, 40);
txtFiles.setFocusable(false);
jspFiles.setViewportView(txtFiles);
add(jspFiles); // 选择启动类
cobMainClass = new JComboBox<>();
cobMainClass.setSize(440, 30);
cobMainClass.setLocation(20, 210);
add(cobMainClass); // 清除已选
btnCls = new JButton("重 选");
btnCls.setLocation(20, 250);
btnCls.setSize(80, 24);
btnCls.addActionListener(this);
add(btnCls); // 确认按钮
btnConfirm = new JButton("确认");
btnConfirm.setSize(80, 24);
btnConfirm.setLocation(380, 250);
btnConfirm.addActionListener(this);
add(btnConfirm); // 文件选择器
jfcSelect = new JFileChooser();
// 可以选择文件和文件夹
jfcSelect.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
// 可以多选
jfcSelect.setMultiSelectionEnabled(true); // 文件保存
jfcSave = new JFileChooser();
// 设置只接受以“.jar”结尾的文件
jfcSave.setAcceptAllFileFilterUsed(false);
jfcSave.setFileFilter(new FileFilter() { @Override
public String getDescription() {
return "可执行Jar";
} @Override
public boolean accept(File f) {
return f.getName().endsWith(".jar");
}
});
} @Override
public void actionPerformed(ActionEvent e) { } private JLabel lblTip;
private JButton btnBrowser;
private JFileChooser jfcSelect;
private JTextArea txtFiles;
private JComboBox<String> cobMainClass;
private JButton btnCls;
private JButton btnConfirm;
private JFileChooser jfcSave;
}
FrmMain_UI
然后开始业务部分,首先是选择文件,我们允许用户选择多个文件和文件夹(甚至可以通过多次选择来选择不同盘符、路径下的文件和文件夹),在选择后可能有重复的地方或两次选择后有包含的项目,我们要去除。
我们为“浏览”按钮事件添加处理,让用户选择文件并处理选中文件:
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnBrowser) {
// 浏览
int result = jfcSelect.showOpenDialog(this); // 选择了文件
if(result == JFileChooser.APPROVE_OPTION) {
for(File file : jfcSelect.getSelectedFiles())
userSelectedFiles.add(file); // 整理选择的文件,去除重复项
removeDuplicateItems(userSelectedFiles); // 重新计算选中文件
finalFiles.clear();
for(File file : userSelectedFiles)
addFileToList(file, finalFiles); // 计算文件展示打包路径及展示路径
// 计算可启动类路径
// 展示到文本框中
cobMainClass.removeAllItems();
txtFiles.setText("");
File file,direc;
String filePath,direcPath;
Iterator<File> itd,itf;
for(itd = userSelectedFiles.iterator(); itd.hasNext();) {
direc = itd.next();
direcPath = direc.getAbsolutePath();
for(itf = finalFiles.iterator(); itf.hasNext();) {
file = itf.next();
filePath = file.getAbsolutePath();
if(filePath.equalsIgnoreCase(direcPath)) {
txtFiles.append(file.getName() + "\n");
filePaths.put(file.getName(), file);
//fileNames.put(file.getName(), file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
if(file.getName().endsWith(".class"))
cobMainClass.addItem(file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
itf.remove();
} else if(filePath.startsWith(direcPath)) {
String nameTmp = filePath.substring(direcPath.lastIndexOf(File.separator) + 1).replace(File.separatorChar, '/');
filePaths.put(nameTmp, file);
txtFiles.append(nameTmp + "\n");
//fileNames.put(nameTmp, nameTmp.endsWith(".class")?nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'):nameTmp);
if(nameTmp.endsWith(".class") && nameTmp.indexOf('$') == -1)
cobMainClass.addItem(nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'));
itf.remove();
}
}
}
}
}
} // 添加文件(非文件夹)到集合
private void addFileToList(File file, List<File> fileArr) {
if(file.isDirectory())
for(File child : file.listFiles())
addFileToList(child, fileArr);
else
fileArr.add(file);
} // 去除重复项
private void removeDuplicateItems(List<File> fileArr) {
// 去重复项
Set<String> directories = new HashSet<>();
Set<String> files = new HashSet<>();
for(File file : fileArr)
if(file.isDirectory())
directories.add(file.getAbsolutePath());
else
files.add(file.getAbsolutePath());
//去包含项(先去文件夹再去文件应该更好)
String fpath,dpath;
for(Iterator<String> itf = files.iterator(); itf.hasNext();) {
fpath = itf.next();
for(Iterator<String> itd = directories.iterator(); itd.hasNext();) {
dpath = itd.next();
if(fpath.startsWith(dpath))
itf.remove();
}
}
String dpath1,dpath2;
Set<String> directories1 = new HashSet<>(directories);
for(Iterator<String> itd1 = directories.iterator(); itd1.hasNext();) {
dpath1 = itd1.next();
for(Iterator<String> itd2 = directories1.iterator(); itd2.hasNext();) {
dpath2 = itd2.next();
if(dpath1.equals(dpath2))
continue;
else if(dpath2.startsWith(dpath1))
itd2.remove();
else if(dpath1.startsWith(dpath2))
itd1.remove();
}
}
directories.addAll(directories1); fileArr.clear();
for(String file : files)
fileArr.add(new File(file));
for(String directory : directories)
fileArr.add(new File(directory));
}
btnBrowser_event_handler
“重选”按钮点击后清除已选项,逻辑就先不详细介绍了。
然后是“确定”按钮,我们弹出文件保存框让用户选择保存位置,然后生成可执行的jar包:
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnBrowser) {
} else if(e.getSource() == btnCls) {
if(userSelectedFiles.size() == 0) return;
else if(JOptionPane.showConfirmDialog(this, "确定重选吗?将清除所有已选项!") == JOptionPane.OK_OPTION) {
userSelectedFiles.clear();
finalFiles.clear();
filePaths.clear();
cobMainClass.removeAllItems();
}
} else if(e.getSource() == btnConfirm) {
if(filePaths.size() == 0) {
JOptionPane.showMessageDialog(this, "未选择文件", "错误", JOptionPane.ERROR_MESSAGE);
return;
} else if(cobMainClass.getSelectedItem() == null) {
JOptionPane.showMessageDialog(this, "未选择启动类", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 打包
int result = jfcSave.showSaveDialog(this);
if(result == JFileChooser.APPROVE_OPTION) {
try {
// 清单文件
Manifest man = new Manifest();
// 版本和启动类路径必要
man.getMainAttributes().putValue(Name.MANIFEST_VERSION.toString(), "1.0");
man.getMainAttributes().putValue(Name.MAIN_CLASS.toString(), cobMainClass.getSelectedItem().toString());
// Class-Path一定不要,除非能保证将引用类(即import的类)都联合打包了
JarOutputStream jos = new JarOutputStream(new FileOutputStream(jfcSave.getSelectedFile()), man);
jos.setLevel(Deflater.BEST_COMPRESSION);
BufferedInputStream bis = null;
byte[] cache = new byte[1024];
StringBuffer config = new StringBuffer();
for(String name : filePaths.keySet()) {
bis = new BufferedInputStream(new FileInputStream(filePaths.get(name)), 1024);
config.append(name).append('=').append(bis.available()).append('\n');
jos.putNextEntry(new JarEntry(name));
int count;
while((count = bis.read(cache, 0, 1024)) != -1)
jos.write(cache, 0, count);
jos.closeEntry();
bis.close();
}
jos.flush();
jos.close();
JOptionPane.showMessageDialog(this, "导出成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
} catch(Exception ex) {
JOptionPane.showMessageDialog(this, ex.getMessage(), "异常", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
} }
btnConfirm_event_handler
当然,这里还有一个小问题:选择文件(自己写的文件名就算不加后缀也能保存成功-_-)。
先展示一下结果:
在文件系统中选择:
导出到桌面:
运行一下:
我最后再将完整的源码贴出一份:
package org.coderecord.commons.ejarmaker; import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.jar.Attributes.Name;
import java.util.zip.Deflater; import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.filechooser.FileFilter; public class FrmMain extends JFrame implements ActionListener { private static final long serialVersionUID = 2016913328739206536L;
// 选择的文件(用户在文件选择器中选择的)
private List<File> userSelectedFiles = new ArrayList<>();
// 我们经过分析得到的最终会被打包的文件
private List<File> finalFiles = new ArrayList<>();
// 文件打包路径及物理文件
private Map<String, File> filePaths = new Hashtable<>(); public FrmMain() {
setSize(480, 320);
setResizable(false);
setLocationRelativeTo(null);
setTitle("通用可执行Jar包生成工具");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
// 在运行时获取资源文件的方式,一定是使用Class.getResource方式
// 在jar包中这种方式也行得通
// ‘/’代表根路径
setIconImage(Toolkit.getDefaultToolkit().getImage(FrmMain.class.getResource("/resources/icon.png")));
initComponents();
} // 初始化组件
private void initComponents() {
// 提示
lblTip = new JLabel("选择需要打包的文件并设置启动类");
lblTip.setLocation(20, 10);
lblTip.setSize(350, 20);
add(lblTip); // 浏览按钮
btnBrowser = new JButton("浏 览");
btnBrowser.setLocation(380, 10);
btnBrowser.setSize(80, 24);
btnBrowser.addActionListener(this);
add(btnBrowser); // 展示已选择文件
JScrollPane jspFiles = new JScrollPane();
txtFiles = new JTextArea();
txtFiles.setEditable(false);
jspFiles.setSize(440, 160);
jspFiles.setLocation(20, 40);
txtFiles.setSize(440, 201600);
txtFiles.setLocation(20, 40);
txtFiles.setFocusable(false);
jspFiles.setViewportView(txtFiles);
add(jspFiles); // 选择启动类
cobMainClass = new JComboBox<>();
cobMainClass.setSize(440, 30);
cobMainClass.setLocation(20, 210);
add(cobMainClass); // 清除已选
btnCls = new JButton("重 选");
btnCls.setLocation(20, 250);
btnCls.setSize(80, 24);
btnCls.addActionListener(this);
add(btnCls); // 确认按钮
btnConfirm = new JButton("确认");
btnConfirm.setSize(80, 24);
btnConfirm.setLocation(380, 250);
btnConfirm.addActionListener(this);
add(btnConfirm); // 文件选择器
jfcSelect = new JFileChooser();
// 可以选择文件和文件夹
jfcSelect.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
// 可以多选
jfcSelect.setMultiSelectionEnabled(true); // 文件保存
jfcSave = new JFileChooser();
// 设置只接受以“.jar”结尾的文件
jfcSave.setAcceptAllFileFilterUsed(false);
jfcSave.setFileFilter(new FileFilter() { @Override
public String getDescription() {
return "可执行Jar";
} @Override
public boolean accept(File f) {
return f.getName().endsWith(".jar");
}
});
} @Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnBrowser) {
// 浏览
int result = jfcSelect.showOpenDialog(this); // 选择了文件
if(result == JFileChooser.APPROVE_OPTION) {
for(File file : jfcSelect.getSelectedFiles())
userSelectedFiles.add(file); // 整理选择的文件,去除重复项
removeDuplicateItems(userSelectedFiles); // 重新计算选中文件
finalFiles.clear();
for(File file : userSelectedFiles)
addFileToList(file, finalFiles); // 计算文件展示打包路径及展示路径
// 计算可启动类路径
// 展示到文本框中
cobMainClass.removeAllItems();
txtFiles.setText("");
File file,direc;
String filePath,direcPath;
Iterator<File> itd,itf;
for(itd = userSelectedFiles.iterator(); itd.hasNext();) {
direc = itd.next();
direcPath = direc.getAbsolutePath();
for(itf = finalFiles.iterator(); itf.hasNext();) {
file = itf.next();
filePath = file.getAbsolutePath();
if(filePath.equalsIgnoreCase(direcPath)) {
txtFiles.append(file.getName() + "\n");
filePaths.put(file.getName(), file);
if(file.getName().endsWith(".class"))
cobMainClass.addItem(file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
itf.remove();
} else if(filePath.startsWith(direcPath)) {
String nameTmp = filePath.substring(direcPath.lastIndexOf(File.separator) + 1).replace(File.separatorChar, '/');
filePaths.put(nameTmp, file);
txtFiles.append(nameTmp + "\n");
if(nameTmp.endsWith(".class") && nameTmp.indexOf('$') == -1)
cobMainClass.addItem(nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'));
itf.remove();
}
}
}
}
} else if(e.getSource() == btnCls) {
if(userSelectedFiles.size() == 0) return;
else if(JOptionPane.showConfirmDialog(this, "确定重选吗?将清除所有已选项!") == JOptionPane.OK_OPTION) {
userSelectedFiles.clear();
finalFiles.clear();
filePaths.clear();
cobMainClass.removeAllItems();
}
} else if(e.getSource() == btnConfirm) {
if(filePaths.size() == 0) {
JOptionPane.showMessageDialog(this, "未选择文件", "错误", JOptionPane.ERROR_MESSAGE);
return;
} else if(cobMainClass.getSelectedItem() == null) {
JOptionPane.showMessageDialog(this, "未选择启动类", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 打包
int result = jfcSave.showSaveDialog(this);
if(result == JFileChooser.APPROVE_OPTION) {
try {
// 清单文件
Manifest man = new Manifest();
// 版本和启动类路径必要
man.getMainAttributes().putValue(Name.MANIFEST_VERSION.toString(), "1.0");
man.getMainAttributes().putValue(Name.MAIN_CLASS.toString(), cobMainClass.getSelectedItem().toString());
// Class-Path一定不要,除非能保证将引用类(即import的类)都联合打包了
JarOutputStream jos = new JarOutputStream(new FileOutputStream(jfcSave.getSelectedFile()), man);
jos.setLevel(Deflater.BEST_COMPRESSION);
BufferedInputStream bis = null;
byte[] cache = new byte[1024];
StringBuffer config = new StringBuffer();
for(String name : filePaths.keySet()) {
bis = new BufferedInputStream(new FileInputStream(filePaths.get(name)), 1024);
config.append(name).append('=').append(bis.available()).append('\n');
jos.putNextEntry(new JarEntry(name));
int count;
while((count = bis.read(cache, 0, 1024)) != -1)
jos.write(cache, 0, count);
jos.closeEntry();
bis.close();
}
jos.flush();
jos.close();
JOptionPane.showMessageDialog(this, "导出成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
} catch(Exception ex) {
JOptionPane.showMessageDialog(this, ex.getMessage(), "异常", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
} } // 添加文件(非文件夹)到集合
private void addFileToList(File file, List<File> fileArr) {
if(file.isDirectory())
for(File child : file.listFiles())
addFileToList(child, fileArr);
else
fileArr.add(file);
} // 去除重复项
private void removeDuplicateItems(List<File> fileArr) {
// 去重复项
Set<String> directories = new HashSet<>();
Set<String> files = new HashSet<>();
for(File file : fileArr)
if(file.isDirectory())
directories.add(file.getAbsolutePath());
else
files.add(file.getAbsolutePath());
//去包含项(先去文件夹再去文件应该更好)
String fpath,dpath;
for(Iterator<String> itf = files.iterator(); itf.hasNext();) {
fpath = itf.next();
for(Iterator<String> itd = directories.iterator(); itd.hasNext();) {
dpath = itd.next();
if(fpath.startsWith(dpath))
itf.remove();
}
}
String dpath1,dpath2;
Set<String> directories1 = new HashSet<>(directories);
for(Iterator<String> itd1 = directories.iterator(); itd1.hasNext();) {
dpath1 = itd1.next();
for(Iterator<String> itd2 = directories1.iterator(); itd2.hasNext();) {
dpath2 = itd2.next();
if(dpath1.equals(dpath2))
continue;
else if(dpath2.startsWith(dpath1))
itd2.remove();
else if(dpath1.startsWith(dpath2))
itd1.remove();
}
}
directories.addAll(directories1); fileArr.clear();
for(String file : files)
fileArr.add(new File(file));
for(String directory : directories)
fileArr.add(new File(directory));
} private JLabel lblTip;
private JButton btnBrowser;
private JFileChooser jfcSelect;
private JTextArea txtFiles;
private JComboBox<String> cobMainClass;
private JButton btnCls;
private JButton btnConfirm;
private JFileChooser jfcSave;
}
FrmMain
这里有我导出的文件(这个是eclipse导出的,它在manifest中加入了classPath没有错误,我有时候加入后有问题)。
欢迎您移步我们的交流群,无聊的时候大家一起打发时间:
或者通过QQ与我联系:
(最后编辑时间2014-03-02 16:12:50)
使用原生Java代码生成可执行Jar包的更多相关文章
- 使用eclipse创建java程序可执行jar包
一.eclipse中,在要打成jar包的项目名上右击,出现如下弹出框,选择“export”: 二.在接下来出现的界面中点击“jar file”,然后next: 三.在接下来出现的界面中,如图所示勾选上 ...
- JAVA生成(可执行)Jar包的全面详解说明 [打包][SpringBoot][Eclipse][IDEA][Maven][Gradle][分离][可执行]
辛苦所得,转载还请注明: https://www.cnblogs.com/applerosa/p/9739007.html 得空整理了关于java 开发中,所有打包方式的 一个操作方法, 有基于ID ...
- Java打包可执行jar包 包含外部文件
外部文件在程序中设置成相对当前工程路径,执行jar包时,将外部文件放在和jar包平级的目录. public class Main { 3 public static void main(String[ ...
- java 生成可执行jar包
jar -cvfm my.jar [配置主函数入口文件] [包] Main-Class: 包名.类名 注意“:”后边有一个空格,类名后边要有回车换行
- java 执行 jar 包中的 main 方法
java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...
- IntelliJ IDEA导出Java 可执行Jar包
原文:IntelliJ IDEA导出Java 可执行Jar包 保证自己的Java代码是没有问题的,在IDEA里面是可以正常运行的,然后,按下面步骤: 打开File -> Project Stru ...
- eclipse生成【带有外部jar包】的java可执行jar包
之前有写过一篇使用eclipse生成java可执行jar包,但是最近的一次使用中无论如何都不成功,当双击执行打成的jar时,弹出如下错误: could not find the main class: ...
- java -jar 执行jar包出现 java.lang.NoClassDefFoundError
我用idea工具将自己开发java程序打成一个可执行的jar包,当然用eclipse或者直接用jar命令行都无所谓,本质都是将程序归档到一个压缩包,并附带一个说明清单文件. 打jar的操作其实很简单, ...
- java执行jar包出错:Unable to access jarfile
java执行jar包出错:Unable to access jarfile 错误的原因有多种: 1.一般都是路径不正确.在Windows中,正确的路径类似于: java -jar "D:\W ...
随机推荐
- conda虚拟环境
https://blog.csdn.net/lyy14011305/article/details/59500819 1.首先在所在系统中安装Anaconda.可以打开命令行输入conda -V检验是 ...
- JavaScript性能优化小知识总结
原文出处: YouYaInsist 欢迎分享原创到伯乐头条 前言 一直在学习javascript,也有看过<犀利开发Jquery内核详解与实践>,对这本书的评价只有两个字犀利,可能是对 ...
- EditText控件设置只读
android的文本框输入控件(EditText),有时需要设置控件为只读,最简单的方法就是在layout xml文件中设置EditText的android:editable属性值为false即可,但 ...
- Mac下打开多个eclipse
命令行执行: open -n /Eclipse所在路径/Eclipse.app
- ORA-19602: cannot backup or copy active file in NOARCHIVELOG mode
备份数据库,报错如下 RMAN> backup database; Starting backup at -JAN- allocated channel: ORA_DISK_1 channel ...
- HTML中input type="text"和type="password" 显示的长度不一样
在CSS里边加上input {width:100px;}能把所有input标签的控件宽度改为相同! 加上这个属性 style="width:180px;"
- 基于SIFT特征的全景图像拼接
基于SIFT特征的全景图像拼接 分类: image Machine learning2013-07-05 13:33 2554人阅读 评论(3) 收藏 举报 基于SIFT特征的全景图像拼接 分类: 计 ...
- StyleCop 代码走错 去掉 修改csproj文件
<Import Project="..\packages\StyleCop.MSBuild.4.7.55.0\build\StyleCop.MSBuild.Targets" ...
- 6种常见的Git错误以及解决的办法
我们都会犯错误,尤其是在使用像Git这样复杂的东西时.如果你是Git的新手,可以学习如何在命令行上开始使用Git.下面介绍如何解决六个最常见的Git错误. Photo by Pawel Janiak ...
- NodeJs相关系列文章
1.图片上传之FileAPI与NodeJs 2.NodeJs之调试 3.CentOS下使用NVM 4.NodeJs之进程守护 5.Ubuntu下使用nvm 6.NodeJs之pm2 7.NodeJs之 ...