我自己制作的一个 jar 文件的属性文件, * 是不具备通用性的。不过源码既然放出,变得适应各种不同的需求,自然是不存在什么难题~ * 为了方便地提供最基本的适应需求,主要将 configPath 修改为各自 jar包中 配置文件的 classPath 即可~ * 一言以蔽之: * 这个工具主要起到了快捷修改jar文件中某个配置文件的作用~ * 遗憾的是,还有一些需求我没能完成,诸如怎么将JTextArea中属性文件的内容修改的和elcipse中打开属性文件一样, * 那样的话,‘=’,‘true’,‘false’,整数等值具备了不同高亮颜色的话,看起来就舒服多了~ * 各位有兴趣可以试试,据我目前所知,JTextPane貌似更加适合做这个功能,但是有些小细节我不明了。。。 * 如有对这个同样感兴趣且扩展出上述“高亮”功能的大侠,还请给我邮一份,不甚感激! * 在下邮箱:bestfighter@yeah.net */ public class JarCfgEditor extends JFrame {	private static final long serialVersionUID = -7044615012246731094L;	public String configPath = "org/bruce/vertices/resources/DefaultCfg.properties";	public static final int CONSOLE_DIALOG_WIDTH = 500;	public static final int CONSOLE_DIALOG_HEIGHT = 400;	private JScrollPane jsp;	private JTextArea jta;	private File original;	private void initMemberVariables() {	jta = new JTextArea();	jsp = new JScrollPane();	}	public JarCfgEditor() {	super();	this.initMemberVariables();	this.setSize(500, 400);	jsp.setViewportView(jta);	this.add(jsp);	JScrollBar jsb = jsp.getVerticalScrollBar();	jsb.setValue(jsb.getMaximum());	int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;	int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;	this.setLocation((screenWidth-CONSOLE_DIALOG_WIDTH)/2,	(screenHeight-CONSOLE_DIALOG_HEIGHT)/2);	/** 关闭的时候将修改过的属性覆盖到 jar 里面的属性配置文件~ */	this.addWindowListener(new WindowAdapter() {	public void windowClosing(WindowEvent arg0) {	if(original != null) {	write2JarFile();	}	System.exit(0);	}	});	new DropTarget(jta, DnDConstants.ACTION_COPY_OR_MOVE, new MyDropTargetListener(this));	this.setTitle("CfgViewer0.1");	this.setVisible(true);	}	/**	* 写入jar文件的话会将 jar文件原来的内容统统抹掉!!切记!!~	*/	private void write2JarFile() {	String originalPath = original.getAbsolutePath();	/** 创建一个临时文件来做暂存,待一切操作完毕之后会将该文件重命名为原文件的名称(原文件会被删除掉)~ */	String tempPath = originalPath.substring(0, originalPath.length()-4) + "_temp.jar";	System.out.println(tempPath);	JarFile originalJar = null;	try {	originalJar = new JarFile(originalPath);	} catch (IOException e1) {	e1.printStackTrace();	}	Listlists = new LinkedList(); for(Enumerationentrys = originalJar.entries(); entrys.hasMoreElements();) { JarEntry jarEntry = entrys.nextElement(); // System.out.println(jarEntry.getName()); lists.add(jarEntry); }	// 定义一个 jaroutputstream 流File handled = new File(tempPath);	JarOutputStream jos = null;	try {	FileOutputStream fos = new FileOutputStream(handled);	jos = new JarOutputStream(fos);	/**	* 将源文件中的内容复制过来~	* 可以利用循环将一个文件夹中的文件都写入jar包中 其实很简单	*/	for(JarEntry je : lists) {	// jar 中的每一个文件夹 每一个文件 都是一个 jarEntry	JarEntry newEntry = new JarEntry(je.getName());	//	newEntry.setComment(je.getComment()); //	newEntry.setCompressedSize(je.getCompressedSize()); //	newEntry.setCrc(je.getCrc()); //	newEntry.setExtra(je.getExtra()); //	newEntry.setMethod(je.getMethod()); //	newEntry.setTime(je.getTime()); //	System.out.println(je.getAttributes());	/** 这句代码有问题,会导致将jar包重命名为zip包之后无法解压缩~ */ //	newEntry.setSize(je.getSize());	// 表示将该entry写入jar文件中 也就是创建该文件夹和文件	jos.putNextEntry(newEntry);	/** 如果当前已经处理到属性文件了,那么将在 JTextArea 中编辑过的文本写入到该属性文件~ */	if(je.getName().equals(configPath)) {	jos.write(jta.getText().getBytes());	continue;	}	InputStream is = originalJar.getInputStream(je);	byte[] bytes = inputStream2byteArray(is);	is.close();	// 然后就是往entry中的jj.txt文件中写入内容	jos.write(bytes);	}	// 最后不能忘记关闭流	jos.close();	fos.close();	/** 删除原始文件,将新生成的文件重命名为原始文件的名称~ */	original.delete();	handled.renameTo(new File(originalPath));	} catch (Exception e) {	e.printStackTrace();	}	}	/**	* InputStream 转byte[]~	* @param is	* @return	*/	public static byte[] inputStream2byteArray(InputStream is) {	ByteArrayOutputStream baos = new ByteArrayOutputStream();	int i;	try {	while((i = is.read()) != -1) {	baos.write(i);	}	baos.close();	} catch (IOException e) {	e.printStackTrace();	}	byte[] bytes = baos.toByteArray();	return bytes;	}	/** getters && setters~ */	public JTextArea getJta() {	return jta;	}	public void setJta(JTextArea jta) {	this.jta = jta;	}	public File getJarFile() {	return original;	}	public void setJarFile(File jarFile) {	this.original = jarFile;	}	/**	* 主方法~	* @param args	*/	public static void main(String[] args) {	new JarCfgEditor();	} } /** * @author Bruce Yang * 拖拽监听~ */ class MyDropTargetListener extends DropTargetAdapter {	private JarCfgEditor jce;	public MyDropTargetListener(JarCfgEditor jce) {	this.jce = jce;	}	@Override	@SuppressWarnings("unchecked")	public void drop(DropTargetDropEvent event) {	if (event.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {	event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);	DataFlavor df = DataFlavor.javaFileListFlavor;	Listlist = null;	try {	list = (List)(event.getTransferable().getTransferData(df));	} catch (Exception e) {	e.printStackTrace();	}	Iteratoriterator = list.iterator();	while (iterator.hasNext()) {	File file = iterator.next();	if(file.exists() && file.isFile()) {	String filePath = file.getAbsolutePath();	if(filePath == null || filePath.equals("")) {	System.out.println("文件名为 null 或为 \"\"~");	break;	}	if(!filePath.contains("GetVerticesMVC") || !filePath.endsWith(".jar")) {	String str = "此工具专门为 GetVerticesMVC 设计,不通用!! 请注意!!";	JOptionPane.showMessageDialog(null, str);	break;	}	System.out.println("jarFilePath=" + filePath);	jce.setJarFile(file);	JarFile jarFile = null;	try {	jarFile = new JarFile(filePath);	ZipEntry entry = jarFile.getEntry(jce.configPath);	if(entry == null) {	System.out.println(jce.configPath+"路径所代表的文件不存在!读取失败~");	// 安全起见,将jarFile 置为 null,这样在关闭窗口的时候将不会执行收尾操作~	jce.setJarFile(null);	break;	}	//获取到inputstream了 就相当简单了	InputStream is = jarFile.getInputStream(entry);	byte[] bytes = JarCfgEditor.inputStream2byteArray(is);	String cfgStr = new String(bytes);	jce.getJta().setText(cfgStr);	} catch (IOException e) {	e.printStackTrace();	}	}	// 一次只能处理一个,要避免处理多个的情况,因此 break 跳出~	break;	}	event.dropComplete(true);	} else {	event.rejectDrop();	}	} }