众所周知,MANIFEST.MF文件中的空格开头的行是相当于拼接在上一行末尾的。很多又长又乱的Import-Package或者Export-Package,有时候想要搜索某个package却可能被换行截断而搜不到。

这时候咱们可以对它进行格式化重新排列,同时又不影响它的正常运行。再排个序方便查找。

排列前 vs 排列后

附上干货 !!!

(脚本方式,对于长一点的package慢的一批,待优化;可对jar文件直接执行,免解压读取META-INF/MANIFEST.MF)

#!/bin/bash

# MANIFEST.MF文件对Import-Package/Export-Package重排列
function main() {
echo $ | egrep ".jar$|.zip$" &>/dev/null
if [ $? -eq ];then
MANIFEST=$(unzip -p $ META-INF/MANIFEST.MF)
[ $? -ne ] && echo ${MANIFEST} && exit
else
MANIFEST=$(cat $)
fi
isWindowsDoc="false"
# 判断文件格式是windows还是unix
[ "" != "$(echo "$MANIFEST" | sed -n ":a;N;/\r\n/p;ba")" ] && isWindowsDoc="true"
MANIFEST=$(echo "$MANIFEST" | dos2unix) # 空格开头的行,合并到一行
MANIFEST=$(echo "$MANIFEST" | sed ":a;N;s/\n //g;ba") importPackage=$(echo "${MANIFEST}" | egrep "^Import-Package:" | sed 's/^Import-Package: *//g' | sed 's/ //g')
exportPackage=$(echo "${MANIFEST}" | egrep "^Export-Package:" | sed 's/^Export-Package: *//g' | sed 's/ //g') output=$(echo "${MANIFEST}")
# 引号外的逗号转为特殊分隔符
if [ "" != "${importPackage}" ];then
importPackage=$(dealStrByPython ${importPackage})
importPackage="Import-Package: \n${importPackage}"
len=${#importPackage}
importPackage=$(echo -e "${importPackage:0:$((len-1))}") # 去掉最后一个字符
oneLineImport=$(echo "${importPackage}" | sed ":a;N;s/\n/#/g;ba") # sed命令不能一行换多行,将换行符转为#号变成一行,替换后#号再转回换行符
output=$(echo "${output}" | sed 's/^Import-Package:.*/'"${oneLineImport}"'/g' | sed "s/#/\n/g")
fi
if [ "" != "${exportPackage}" ];then
exportPackage=$(dealStrByPython ${exportPackage})
exportPackage="Export-Package: \n${exportPackage}"
len=${#exportPackage}
exportPackage=$(echo -e "${exportPackage:0:$((len-1))}")
oneLineExport=$(echo "${exportPackage}" | sed ":a;N;s/\n/#/g;ba")
output=$(echo "${output}" | sed 's/^Export-Package:.*/'"${oneLineExport}"'/g' | sed "s/#/\n/g")
fi if [ "true" == "${isWindowsDoc}" ];then
echo "${output}" | unix2dos
else
echo "${output}"
fi
} #按逗号分隔字符串,并忽略双引号中的逗号
#逐个字符遍历
#效率贼慢
function dealStr() {
str=$
newStr=""
isOpenQuotes="false"
splitChar="#"
# 遍历字符串的字符
for((i=; i<${#str}; i++))
do
char=${str:$i:}
if [ "$char" == '"' ];then
if [ "$isOpenQuotes" == "false" ];then
isOpenQuotes="true"
else
isOpenQuotes="false"
fi
fi
[ "$char" == "," ] && [ "$isOpenQuotes" == "false" ] && char=${splitChar}
newStr=${newStr}${char}
done
# 按特殊分隔符分割、排序
echo "${newStr}" | awk -F '#' '{for(n=1;n<=NF;n++) print " "$n","}' | sort
} #按逗号分隔字符串,并忽略双引号中的逗号
#遍历字符串中的双引号和逗号
#效率快了一点点
function dealStrTest() {
str=$
newStr=""
isOpenQuotes="false"
splitChar="#" while true
do
indexOfQuotes=`expr index $str '"'`
indexOfComma=`expr index $str ','`
# 处理引号
if [ $indexOfQuotes -gt ] && [ $indexOfComma -gt ] && [ $indexOfQuotes -lt $indexOfComma ];then
if [ "$isOpenQuotes" == "false" ];then
isOpenQuotes="true"
else
isOpenQuotes="false"
fi
newStr=${newStr}${str::$indexOfQuotes}
str=${str:$indexOfQuotes}
# 处理逗号
elif [ $indexOfQuotes -gt ] && [ $indexOfComma -gt ] && [ $indexOfComma -lt $indexOfQuotes ] || [ $indexOfQuotes -eq ] && [ $indexOfComma -gt ];then
[ "$isOpenQuotes" == "false" ] && newStr=${newStr}${str::$indexOfComma-}${splitChar}
[ "$isOpenQuotes" != "false" ] && newStr=${newStr}${str::$indexOfComma}
str=${str:$indexOfComma}
# 逗号没了
elif [ $indexOfComma -eq ];then
newStr=${newStr}${str}
break
else
break
fi
done
# 按特殊分隔符分割、排序
echo "${newStr}" | awk -F '#' '{for(n=1;n<=NF;n++) print " "$n","}' | sort
} #按逗号分隔字符串,并忽略双引号中的逗号
#使用python逐个字符遍历
#效率更快了
function dealStrByPython() {
str=$
newStr=`python -c "
str='$str'
isOpenQuotes=False
splitChar='#'
chArr=[]
for ch in str.replace(' ',''):
if ch == '\"' :
isOpenQuotes = bool(-isOpenQuotes)
if ch == ',' and isOpenQuotes == False :
chArr.append(splitChar)
else :
chArr.append(ch)
print(''.join(chArr))
"`
# 按特殊分隔符分割、排序
echo "${newStr}" | awk -F '#' '{for(n=1;n<=NF;n++) print " "$n","}' | sort
} main $@

(java方式)

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties; public class ManifestFormatter { private final static String IMPORT_PACKAGE = "Import-Package";
private final static String EXPORT_PACKAGE = "Export-Package";
private final static char SEPARATOR = '#'; public static void main(String[] args) {
File mf = new File(args[0]);
File formatMf = new File(mf.getParentFile(), "MANIFEST.MF.FORMAT");
if (!mf.exists()) {
System.out.println(mf.getAbsolutePath() + " is format failed: " + mf.getAbsolutePath() + " is not exits");
System.exit(2);
}
try (BufferedReader br = new BufferedReader(new FileReader(mf)); BufferedWriter bw = new BufferedWriter(new FileWriter(formatMf));) {
StringBuilder fileToString = new StringBuilder();
char[] chars = new char[1024];
int len;
while ((len = br.read(chars, 0, chars.length)) != -1) {
fileToString.append(new String(chars, 0, len));
} // 转换MANIFEST.MF文件中的属性为单行模式,并保持原来的文档格式
String lineSeparator = fileToString.indexOf("\r\n") != -1 ? "\r\n" : "\n";
String formatStr = fileToString.toString().replaceAll(lineSeparator + " ", "");
ByteArrayInputStream bi = new ByteArrayInputStream(formatStr.getBytes());
Properties properties = new Properties();
properties.load(bi); // 回写MANIFEST.MF文件,重新写入Import-Package与Export-Package
String importPackageStr = properties.getProperty(IMPORT_PACKAGE);
if (importPackageStr != null && importPackageStr.length() > 0) {
List<String> importPackageList = getPackageList(importPackageStr);
String newImportPackageStr = createNewPackage(importPackageList, IMPORT_PACKAGE, lineSeparator);
formatStr = formatStr.replaceAll("Import-Package:.*" + lineSeparator, newImportPackageStr);
}
String exportPackageStr = properties.getProperty(EXPORT_PACKAGE);
if (exportPackageStr != null && exportPackageStr.length() > 0) {
List<String> exportPackageList = getPackageList(exportPackageStr);
String newExportPackageStr = createNewPackage(exportPackageList, EXPORT_PACKAGE, lineSeparator);
formatStr = formatStr.replaceAll("Export-Package:.*" + lineSeparator, newExportPackageStr);
}
bw.write(formatStr);
} catch (IOException e) {
System.out.println(mf.getAbsolutePath() + " is format failed: " + e.getMessage());
e.printStackTrace();
System.exit(1);
}
System.out.println(mf.getAbsolutePath() + " is format successed");
} /**
* 重新创建Import-Package与Export-Package
*
* @param packageList
* @param packageType
* @param lineSeparator
* @return
*/
private static String createNewPackage(List<String> packageList, String packageType, String lineSeparator) {
StringBuilder newPackageString = new StringBuilder(packageType).append(":").append(lineSeparator);
int size = packageList.size();
for (int i = 0; i < size; i++) {
newPackageString.append(" ");
newPackageString.append(packageList.get(i));
if (i < size - 1) {
newPackageString.append(",");
}
newPackageString.append(lineSeparator);
}
return newPackageString.toString();
} /**
* 单行的Import-Package或Export-Package,转化为list数组
*
* @param packageStr 单行的Import-Package或Export-Package
* @param packageType "Import-Package"或"Export-Package"
* @return
*/
private static List<String> getPackageList(String packageStr) {
boolean isOpenQuotes = false;
char[] chArr = packageStr.replaceAll(" ", "").toCharArray();
int len = chArr.length;
// 双引号外面的逗号,转为分隔符
for (int i = 0; i < len; i++) {
if (chArr[i] == '"') {
isOpenQuotes = !isOpenQuotes;
}
if (chArr[i] == ',' && !isOpenQuotes) {
chArr[i] = SEPARATOR;
}
}
List<String> packageList = Arrays.asList(new String(chArr).split(SEPARATOR + ""));
Collections.sort(packageList);
return packageList;
} }

MANIFEST.MF文件对Import-Package/Export-Package重排列的更多相关文章

  1. 关于java中的MANIFEST.MF 文件内容

    打开Java的JAR文件我们经常可以看到文件中包含着一个META-INF目录, 这个目录下会有一些文件,其中必有一个MANIFEST.MF,这个文件描述了该Jar文件的很多信息.可以简化Java应用程 ...

  2. Jar文件 META-INF/MANIFEST.MF文件详解

    打开Java的JAR文件我们经常可以看到文件中包含着一个META-INF目录, 这个目录下会有一些文件,其中必有一个MANIFEST.MF,这个文件描述了该Jar文件的很多信息,下面将详细介绍MANI ...

  3. meta-inf文件夹以及MANIFEST.MF文件的作用

    meta-inf相当于一个信息包,目录中的文件和目录获得Java 2平台的认可与解释,用来配置应用程序.扩展程序.类加载器和服务 manifest.mf文件,在用jar打包时自动生成的. META-I ...

  4. MANIFEST.MF文件Class-Path:节点需要引入的jar太多解决方案

    每行开头结尾都要有一个空格(半角的) 例子如下: Manifest-Version: 1.0 Class-Path: lib/mongo-java-driver-2.11.4.jar lib/guav ...

  5. JAR包中的MANIFEST.MF文件详解以及编写规范

    参考百度百科的解释如下: http://baike.baidu.com/item/MANIFEST.MF MANIFEST.MF:这个 manifest 文件定义了与扩展和包相关的数据.单词“mani ...

  6. MANIFEST.MF 文件内容完全详解(转)

    打开Java的JAR文件我们经常可以看到文件中包含着一个META-INF目录, 这个目录下会有一些文件,其中必有一个MANIFEST.MF,这个文件描述了该Jar文件的很多信息,下面将详细介绍MANI ...

  7. MANIFEST.MF Error: No available bundle exports package

    Issue: When you imported some 3rd jars and compiled MANIFEST.MF, you may got following compling erro ...

  8. jar包的MANIFEST.MF文件

    打包可执行jar包时,MANIFEST.MF总是个让人头疼的东西,经常出现这种那种问题. 一个例子: ================================================= ...

  9. JAR包结构,META-INF/MANIFEST.MF文件详细说明[全部属性][打包][JDK]

    转载请注:[https://www.cnblogs.com/applerosa/p/9736729.html] 常见的属性 jar文件的用途 压缩的和未压缩的 jar工具 可执行的JAR 1.创建可执 ...

随机推荐

  1. hanlp添加词典不起作用

    不起作用的原因很多,这里列举几个 这里的hanlp我虽然用的maven建立的但是要添加自定义词典,所以没有用maven引入的方式,而是下载了data+hanlp.jar文件          data ...

  2. 解决wireshark抓包校验和和分片显示异常

    问题描述: 在使用wireshark抓取报文时,发现从10.81.2.92发过来的报文绝大部分标记为异常报文(开启IPv4和TCP checksum) 分析如下报文,发现http报文(即tcp pay ...

  3. thinkphp漏洞如何修复

    THINKPHP漏洞修复,官方于近日,对现有的thinkphp5.0到5.1所有版本进行了升级,以及补丁更新,这次更新主要是进行了一些漏洞修复,最严重的就是之前存在的SQL注入漏洞,以及远程代码执行查 ...

  4. 最近C#项目中不小心踩的低级坑

    都是很基础的错误问题,大部分都是因为不查一下资料就直接根据其它类似语言的经验写代码导致的 1. 一个企业微信上的正常的界面突然不能滚动了 本以为是浏览器代码计算问题,结果发现是JS出错导致. 2. R ...

  5. 【Mac+Appium+Python】之用 uiautomator2 启动报错

    参数中添加了: automationName: Uiautomator2 运行如下: [UiAutomator2] Starting UIAutomator2 server 3.1.1 [UiAuto ...

  6. Unary模式下客户端创建 default-executor 和 resolver-executor 线程和从启动到执行grpc_connector_connect的主要流程

    (原创)C/C/1.25.0-dev grpc-c/8.0.0, 使用的例子是自带的例子GreeterClient 创建 default-executor 和 resolver-executor 线程 ...

  7. Fiddler手机抓包不完全记录

    准备工作: 1.必须确保安装fiddler的电脑和手机在同一个wifi环境下 备注:如果电脑是笔记本当然最好;如果电脑用的是台式机,可以安装一个随身wifi,来确保台式机和手机在同一wifi环境下   ...

  8. drools规则语法(一)

    1.基本的匹配规则 1.1变量 drools使用匹配的方式对Fact进行比对, 比如 account : Account(balance > 100) 这个规则的含义就是在Fact中找到类型为A ...

  9. SQL 2008R2问题:用户、组或角色'XXX'在当前数据库中已存在?

    为一个数据库添加一个用户或者映射数据库时,提示以下错误信息: 用户.组或角色 '*****' 在当前数据库中已存在. (Microsoft SQLServer, 错误 : 15023) 问题原因:在还 ...

  10. <!DOCTYPE html> 详解

    前段时间的.netcore web应用程序的项目里面使用Frameset与Frame时候出现了一个问题就是使用不了,今晚准备测试一个bug却得到意外收获o(∩_∩)o 哈哈, 找到了最终原因funny ...