java 修改 jar 包文件内容的一个实例

开发这个小工具的初衷是为了修改工具 jar 包中的配置文件

本来打算将这个功能集成到 工具 jar 包自身

但是这里貌似有点儿问题,因为该 jar 包文件当前正在被 java 虚拟机使用,所以无法对其进行修改操作~

这里我有点儿疑惑,难道不是将 jar 包整个加载到内存中去了么?

为什么磁盘上的物理文件还是被牢牢锁定?mac上是这样,windows里面也是这样,应该有点儿蹊跷,不深究了~

本示例主要包含了以下知识点:

1。遍历 jar 文件中的所有文件(jar包实际上就是zip压缩包,没什么神奇的)

2。就像读取磁盘中的其他文件一样,对jar执行 读入和写出操作

3。将 jar文件中的某个文件读到 swing的 jTextArea 里面,在退出的时候将修改过的文字覆盖回原文件

4。将InputStream 安全的转换为 byte[] 数组

5。拖拽取得文件的完整路径

下面直接上代码实例:

package org.bruce.vertices.extra;import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;/*** @author Bruce Yang* PS:本示例专门用于编辑我自己制作的一个 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();}List<JarEntry> lists = new LinkedList<JarEntry>();for(Enumeration<JarEntry> entrys = 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 中的每一个文件夹 每一个文件 都是一个 jarEntryJarEntry 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;List<File> list = null;try {list = (List<File>)(event.getTransferable().getTransferData(df));} catch (Exception e) {e.printStackTrace();}Iterator<File> iterator = 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();}}
}


转载于:https://www.cnblogs.com/yang3wei/archive/2012/04/06/2739796.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/409936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python画图灰白_python 站点资料插值画图及白化

import cmaps import maskout import pandas as pd import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import Rbf from mpl_toolkits.basemap import Basemap plt.rcParams[font.sans-serif][SimHei] #用来正常显示中文 plt.rcParams[axes.unicode_…

[html] 在普通网页中如何调用html5+的plus对象?

[html] 在普通网页中如何调用html5的plus对象&#xff1f; document.addEventListener( "plusready", onPlusReady, false ); onPlusReady 函数中就可以引用plus对象个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定…

算法之归并排序

package com.ebiz.sort;import java.util.Arrays;/*** author YHj* create 2019-09-03 22:21* /*** 归并排序&#xff08;递归&#xff09;** ①. 将序列每相邻两个数字进行归并操作&#xff0c;形成 floor(n/2)个序列* ②. 执行①直到每组有一个元素 * ③. 各组之间进行比较*…

eureka需要替换吗_nacos无缝替换eureka

首先安装好nacos之后直接引入客户端依赖和配置文件&#xff0c;同时把eureka的内容去掉从nacos官网 https://nacos.io/zh-cn/index.html 下载安装包下载好之后解压&#xff0c;打开配置文件 conf/application.properties 配置一下mysql和地址&#xff0c;其他的的按需配置serve…

程旭元系统漫画第三期:加班 !

对于苦逼的程旭元来说 加班已经变成了生活中不可缺少的部分 他的原则是不能像胖子那样贪吃 不能像销售员那样狡诈 一定要尽忠职守 精忠报国 &#xff01;老板说什么他就做什么&#xff01; 对于一个从来只说加班不加工资的boss来说 唯命是从就是存活在公司的最好方式~ 但是有…

python 的库如何开发_一篇文章入门Python生态系统

译者按&#xff1a;原文写于2011年末&#xff0c;虽然文中关于Python 3的一些说法可以说已经不成立了&#xff0c;但是作为一篇面向从其他语言转型到Python的程序员来说&#xff0c;本文对Python的生态系统还是做了较为全面的介绍。文中提到了一些第三方库&#xff0c;但是Pyth…

[html] 你知道什么是html5plus吗?

[html] 你知道什么是html5plus吗&#xff1f; 用js的方式来调用移动app(安卓和ios)的原生能力&#xff0c;例如拍照&#xff0c;摄像个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一…

机器学习线性回归案例讲解_09机器学习实战之简单线性回归

基本概念1. 介绍&#xff1a;回归(regression) Y变量为连续数值型(continuous numerical variable)如&#xff1a;房价&#xff0c;人数&#xff0c;降雨量分类(Classification): Y变量为类别型(categorical variable)如&#xff1a;颜色类别&#xff0c;电脑品牌&#xff0c;有…

silverlight Image Source URI : 一个反斜杠引发的血案

silverlight Image Source URI : 一个反斜杠引发的血案 Silverlight2 现在支持的Image格式有jpg和png&#xff0c;部分png编码也不支持&#xff0c;同时有些png在xaml的design预览中不可见&#xff0c;但运行时可见。请看XAML markup中两行代码的异同&#xff1a; <StackPan…

python编码和解码_Python中的编码与解码(转)

Python中的字符编码与解码困扰了我很久了&#xff0c;一直没有认真整理过&#xff0c;这次下静下心来整理了一下我对方面知识的理解。 文章中对有些知识没有做深入的探讨&#xff0c;一是我自己也没有去深入的了解&#xff0c;例如各种编码方案的实现方式等&#xff1b;二是我觉…

[html] 怎样使用iframe刷新父级页面

[html] 怎样使用iframe刷新父级页面 //在父页面中window.addEventListener("message",function(e){if(e.data.reload){winodw.location.reload()}}, false);//在子页面中window.parent.postMessage({reload:true})个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前…

Nginx编译安装和平滑升级

一、Nginx的编译安装 1、安装依赖包gcc&#xff0c;gcc-c&#xff0c;pcre&#xff0c;openssl-devel 命令&#xff1a;yum -y install gcc gcc-c pcre-devel openssl-devel 2、下载Nginx源码包 Nginx下载地址&#xff1a;http://nginx.org/download/nginx-1.12.2.tar.gz …

python 调用shell 不阻塞_遇到问题---python调用shell脚本时subprocess.check_call不阻塞

遇到的问题使用命令subprocess.check_call(cmd, shellTrue, stdoutsubprocess.PIPE, stderrsubprocess.STDOUT)在ubuntu系统中python中使用subprocess.check_call调用shell命令。发现subprocess.check_call的阻塞无效&#xff0c;导致下面的命令缺失信息。但是同样的代码在cent…

android ListView详解

在android开发中ListView是比较常用的组件&#xff0c;它以列表的形式展示具体内容&#xff0c;并且能够根据数据的长度自适应显示。抽空把对ListView的使用做了整理&#xff0c;并写了个小例子&#xff0c;如下图。 列表的显示需要三个元素&#xff1a;1&#xff0e;ListVeiw …

[html] iframe在更改了src之后,不出现后退或者前进按钮怎么解决?

[html] iframe在更改了src之后&#xff0c;不出现后退或者前进按钮怎么解决&#xff1f; 更改src时可以先删除旧的iframe后&#xff0c;新建一个iframe设置好src添加进去个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。…

python一次性输入3个数_python实现输入数字的连续加减方法

不用库&#xff0c;写了很久&#xff0c;一直出bug&#xff0c;到网上一搜&#xff0c;可以直接输入之后&#xff0c;eval(str)即可得到结果&#xff01; eval程序如下&#xff1a; sinput("请输入要运算的数字") print("The result is{}".format(eval(s))…

gd动态曲线 php_php中用GD绘制折线图

1 ClassChart{2 private $image; //定义图像3 private $title; //定义标题4 private $ydata; //定义Y轴数据5 private $xdata; //定义X轴数据6 private $seriesName; //定义每个系列数据的名称7 private $color; //定义条形图颜色8 private $bgcolor; //定义图片背景颜色9 priv…

Nginx网站用户认证

一、Nginx网站用户认证 用户认证&#xff1a;用户访问网页时需要输入一个用户名和密码才能打开网页。 nginx的默认网页时安装目录下的html/index.html&#xff0c;配置文件在安装目录下的conf目录中的nginx.conf 无用户认证网页 修改配置文件/usr/local/nginx/conf/nginx.conf(…

STL源码剖析学习二:空间配置器(allocator)

STL源码剖析学习二&#xff1a;空间配置器&#xff08;allocator&#xff09; 标准接口&#xff1a;vlaue_typepointerconst_pointerreferenceconst_referencesize_typedifference_typerebindallocator()--default constructorallocator(const allocator<U>&--copy c…

[html] iframe如何自动调整高度?

[html] iframe如何自动调整高度&#xff1f; 未跨域时&#xff0c;在iframe中利用他的父窗口对象将本页面的滚动高度设置给iframe的height 跨域时&#xff0c;在iframe中将自己的的滚动高设置在本页面内的一个隐藏于父页面不跨域的iframe的hash值&#xff0c; 在隐藏的iframe中…