“包”治百病,归档和压缩(TAR&JAR)
我发现我自己和我的同学们总是记不住很多工具命令,尤其是tar和jar命令,要用的时候都是面向Google编程。
归档命令-tar
tar是一个古老的Linux命令,了解基本功能可对付80%的备份需求,了解更细节的用法则可得心应手。
基本功能
基本功能就是 归档和提取。
归档和提取
tar基本功能就是将多个文件和目录归档到一个归档文件里,并且以后可以从归档文件里提取出原来的文件内容。 如下:
- 当我们将多个文件和目录归档到一个归档文件时,需要使用-c功能,
tar -cf archive.tar foo bar
将foo bar归档到archive.tar里面。 - 当我们从归档文件里提取出原来的文件内容时,需要使用-x功能,
tar -xf archive.tar
提取archive.tar里的文件到当前目录。
我们可以发现基本功能后面都使用了f选项,去掉f选项将不能正常工作,这是为什么呢?
因为在tar的设计里面-f 后面接归档的文件名字,比如这里就是archive.tar;不论是归档还是提取,这个f后面都是接归档的文件名字。
我们需要知道归档文件的内容才好提取文件到目录(按需,不然可能存在安全的问题),那tar也提供了查询归档文件内容的功能。
Table列出
t(table)表示列出包里面的内容,-v显示功能动作具体的执行过程,如下:
# tar tvf archive.tar
-rwxr-xr-x root/root 106 2021-11-15 21:48 hello
-rw-r--r-- root/root 0 2021-11-15 23:18 hello2
tar的使用风格比较古老,
tar tvf archive.tar
和tar -tvf archive.tar
等价。
更多功能-细节&高效
tar还提供很多细节功能:
- 追加内容
- 提取部分内容
- 创建过程,可以排除文件
- 压缩和解压缩
- -j 支持bg2压缩格式
- -z 支持gz压缩
添加上额外功能后,整个tar的功能图变得生动起来了:
- -r 追加,使用
tar -rvf archive.tar /zhangsan
可以将 /zhangsan目录加到archive.tar 里面 - 还可以只提取某一个文件,并且指定提取到目录,这里
tar -xf archive.tar file1 -C /tmp/
提取file1到指定目录/tmp/ - -p 后面不跟参数,归档时文件权限保留
- -z和-j都表示归档文件是压缩文件,只是格式不一样
- 对于tar.gz 格式的归档文件,归档和压缩时都加-z,tar.bzip一样
tar -cvzf backup.tar.gz ...
创建tar.gz的归档文件,对于这样的文件,t和x操作的时候可以不加z选项。
Java打包-jar包
jar和tar非常的类似,jar(Java Archive)能够将多个源码、资源等文件打包并压缩到一个归档文件中。也支持更新、查看、提取。 更重要的是,jar包可以按照各种java程序运行的约定去打包。
基本功能
- 基本功能也是c x t,这几个选项基本和tar的对应的用法一模一样
- u 更新文件,相当于tar的r
- v:显示详细过程
- f:指明jar文件的名字
具体如下图所示
可以看出,功能上jar和tar非常的类似,甚至在提取和查看时,直接用tar命令也是可以的。
但是JAR 创建包的时候会默认加上一个 META-INF/MANIFEST.MF,如下演示:
# jar cvf doc.jar A.md
# jar tf doc.jar
META-INF/
META-INF/MANIFEST.MF
A.md
# jar xf doc.jar META-INF/MANIFEST.MF
# cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 12.0.2 (Oracle Corporation)
也可以使用unzip -p控制台查看:
# unzip -p doc.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 12.0.2 (Oracle Corporation)
jar包运行:清单文件
那什么是META-INF/MANIFEST.MF? 为什么要加META-INF/MANIFEST.MF?
即使什么都不做,查看MANIFEST.MF文件的内容可以知道它记录着jar包的版本信息、创建时间。 最重要的是java将jar包作为可运行的程序,指定程序入口,便可以直接java -jar的方式运行程序了。
谚语说:如果你把事情整理的整整有条,用的时候就不用去找了。
如下图所示:
- -e选项:可以指定main方法所在的类,清单文件中就会多一行Main-Class: com.ywz.Main
- -m选项:创建自己的清单文件 写入Main-Class: com.ywz.Main ;
演示: 只用了简单的一个java类:
//$ cat com/ywz/Main.java
package com.ywz;
public class Main{
public static void main(String[] args) {
System.out.println("Hello,My Reader!");
}
}
操作演示:
$ javac com/ywz/Main.java#编译
$ jar cvf example.jar com/ywz/Main.class
已添加清单
正在添加: com/ywz/Main.class(输入 = 426) (输出 = 298)(压缩了 30%)
$ jar tf example.jar #list jar包的内容
META-INF/
META-INF/MANIFEST.MF
com/ywz/Main.class
$ unzip -p example.jar META-INF/MANIFEST.MF #基本信息
Manifest-Version: 1.0
Created-By: 12.0.2 (Oracle Corporation)
##cp指定Class-Path是example.jar ,java程序的候默认class loader会从 example.jar来搜索class
$ java -cp example.jar com.ywz.Main #指定jar包资源的运行,com/ywz/Main和com.ywz.Main都可以
Hello,My Reader!
##不指定cp的时候就是当前路径
$ java com/ywz/Main #当前路径的运行,com/ywz/Main和com.ywz.Main都可以
Hello,My Reader!
## -e 指定Main-Class: com.ywz.Main
$ jar cvfe example.jar com.ywz.Main com/ywz/Main.class
已添加清单
正在添加: com/ywz/Main.class(输入 = 426) (输出 = 298)(压缩了 30%)
$ unzip -p example.jar META-INF/MANIFEST.MF #验证加了Main-Class
Manifest-Version: 1.0
Created-By: 12.0.2 (Oracle Corporation)
Main-Class: com.ywz.Main
$ java -jar example.jar #-jar运行
Hello,My Reader!
## -m 指定Main-Class: com.ywz.Main
$ echo "Main-Class: com.ywz.Main" > example_manifest.txt
$ jar cvfm example.jar example_manifest.txt com/ywz/Main.class
已添加清单
正在添加: com/ywz/Main.class(输入 = 426) (输出 = 298)(压缩了 30%)
$ unzip -p example.jar META-INF/MANIFEST.MF #验证加了Main-Class
Manifest-Version: 1.0
Main-Class: com.ywz.Main
Created-By: 12.0.2 (Oracle Corporation)
$ java -jar example.jar #-jar运行
Hello,My Reader!
-
javac编译java文件
-
cp指定Class-Path是example.jar ,java程序的候默认class loader会从 example.jar来搜索class,所以运行的时候需要知道哪个类是main类,需要指定,因此运行的命令写法还比较麻烦。
-
-e或-m 指定Main-Class: com.ywz.Main,打包好便可以直接java -jar example.jar运行
maven打包
上面描述的是jar的低级功能,现在一般都使用更高级的工具maven来帮助构建和打包java程序。 程序目录结构:
$ tree
.
├── pom.xml
├── src
│ └── main
│ └── java
│ └── Main.java
$ cat pom.xml
因为代码简单,就没有上传github源码了
- Main.java和上面描述的一样
- pom文件配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ywz</groupId>
<artifactId>test</artifactId>
<version>1.0</version>
<properties>
<argLine>-Dfile.encoding=UTF-8</argLine>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.ywz.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 使用插件maven-jar-plugin,指定archive manifest的mainClass是com.ywz.Main
- 生成的jar包和之前用jar命令生成的差不多,运行也是同样的效果。如下:
$ mvn package
$ tar tf target/test-1.0.jar #只多了META-INF/maven的信息
META-INF/
META-INF/MANIFEST.MF
com/
com/ywz/
com/ywz/Main.class
META-INF/maven/
META-INF/maven/com.ywz/
META-INF/maven/com.ywz/test/
META-INF/maven/com.ywz/test/pom.xml
META-INF/maven/com.ywz/test/pom.properties
$ unzip -p target/test-1.0.jar META-INF/MANIFEST.MF #标记是被Apache Maven 3.6.1创建
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven 3.6.1
Main-Class: com.ywz.Main
$ java -jar target/test-1.0.jar#运行
Hello,My Reader!
可以看出:
- jar包里只多了META-INF/maven的信息
- META-INF/MANIFEST.MF标记是被Apache Maven 3.6.1创建的.
清楚jar的用法之后,我们就不会被maven各种各样的插件功能遮挡视线,而且发现jar打包和插件逻辑也是很简单的!
转载自:https://juejin.cn/post/7031716728702926884