二、搜索class文件
一、类路径
https://blog.csdn.net/THMAIL/article/details/70025366
二、准备工作
在%GOPATH%\src\jvmgo下创建classpath文件夹,修改cmd.go里的Cmd结构体,增加一句 XjreOption string
,并在parseCmd()函数中增加一句flag.StringVar(&cmd.XjreOption,"Xjre","","path to jre"),在flag.Parse()语句的上面
三、实现
类路径由启动类路径、扩展类路径和用户类路径构成,此次套用组合模式来设计和实现类路径。在classpath中创建
1、Entry接口
文件名为entry.go
package classpath import "os"
import "strings" // :(linux/unix) or ;(windows)
const pathListSeparator = string(os.PathListSeparator) type Entry interface {
// className: fully/qualified/ClassName.class
readClass(className string) ([]byte, Entry, error)
String() string
} func newEntry(path string) Entry {
if strings.Contains(path, pathListSeparator) {
return newCompositeEntry(path)
} if strings.HasSuffix(path, "*") {
return newWildcardEntry(path)
} if strings.HasSuffix(path, ".jar") || strings.HasSuffix(path, ".JAR") ||
strings.HasSuffix(path, ".zip") || strings.HasSuffix(path, ".ZIP") { return newZipEntry(path)
} return newDirEntry(path)
}
常量pathListSeparator存放路径分隔符,Entry接口有两个方法,readClass()负责寻找和加载class文件;string()用于返回变量的字符串表示。readClass()的用法,如果读取java.lang.Object类,应传入java\lang\Object.class,返回值就是读取的字节数据、最终定位到class文件的Entry,以及错误信息。
Entry接口有四个实现,分别是DirEntry、ZipEntry、CompositeEntry、WildcardEntry。
2、DirEntry
文件名为entry_dir.go
package classpath import "io/ioutil"
import "path/filepath" type DirEntry struct {
absDir string
} func newDirEntry(path string) *DirEntry {
absDir, err := filepath.Abs(path)
if err != nil {
panic(err)
}
return &DirEntry{absDir}
} func (self *DirEntry) readClass(className string) ([]byte, Entry, error) {
fileName := filepath.Join(self.absDir, className)
data, err := ioutil.ReadFile(fileName)
return data, self, err
} func (self *DirEntry) String() string {
return self.absDir
}
DirEntry有一个用于存放目录绝对路径的字段
newDirEntry()先把参数转换成绝对路径,若转换出错,则panic终止程序,否则创建DirEntry实例并返回。
readClass()先把目录和class文件拼成一条完整路径,调用ioutil包的ReadFile()函数读取class文件内容,最后返回。String()函数直接返回目录。
3、ZipEntry
在文件entry_zip.go中,表示ZIP或JAR文件形式的类路径
package classpath import "archive/zip"
import "errors"
import "io/ioutil"
import "path/filepath" type ZipEntry struct {
absPath string
} func newZipEntry(path string) *ZipEntry {
absPath, err := filepath.Abs(path)
if err != nil {
panic(err)
}
return &ZipEntry{absPath}
} func (self *ZipEntry) readClass(className string) ([]byte, Entry, error) {
r, err := zip.OpenReader(self.absPath)
if err != nil {
return nil, nil, err
} defer r.Close()
for _, f := range r.File {
if f.Name == className {
rc, err := f.Open()
if err != nil {
return nil, nil, err
} defer rc.Close()
data, err := ioutil.ReadAll(rc)
if err != nil {
return nil, nil, err
} return data, self, nil
}
} return nil, nil, errors.New("class not found: " + className)
} func (self *ZipEntry) String() string {
return self.absPath
}
absPath存放ZIP或JAR文件的句对路径,newZipEntry()和String()和DirEntry大致相同,
readClass()函数从ZIP文件中读取class文件,首先打开ZIP文件,若出错,直接返回。然后遍历ZIP压缩包里的文件,看是否能找到class文件,若找到,则打开class文件,读取里面内容,并返回,若找不到或出现其他错误,返回错误信息,使用defer确保打开的文件能关闭。
readClass()方法每次都要打开和关闭ZIP文件,效率并不是很高。可以参考下面进行优化
package classpath import "archive/zip"
import "errors"
import "io/ioutil"
import "path/filepath" type ZipEntry2 struct {
absPath string
zipRC *zip.ReadCloser
} func newZipEntry2(path string) *ZipEntry2 {
absPath, err := filepath.Abs(path)
if err != nil {
panic(err)
} return &ZipEntry2{absPath, nil}
} func (self *ZipEntry2) readClass(className string) ([]byte, Entry, error) {
if self.zipRC == nil {
err := self.openJar()
if err != nil {
return nil, nil, err
}
} classFile := self.findClass(className)
if classFile == nil {
return nil, nil, errors.New("class not found: " + className)
} data, err := readClass(classFile)
return data, self, err
} // todo: close zip
func (self *ZipEntry2) openJar() error {
r, err := zip.OpenReader(self.absPath)
if err == nil {
self.zipRC = r
}
return err
} func (self *ZipEntry2) findClass(className string) *zip.File {
for _, f := range self.zipRC.File {
if f.Name == className {
return f
}
}
return nil
} func readClass(classFile *zip.File) ([]byte, error) {
rc, err := classFile.Open()
if err != nil {
return nil, err
}
// read class data
data, err := ioutil.ReadAll(rc)
rc.Close()
if err != nil {
return nil, err
}
return data, nil
} func (self *ZipEntry2) String() string {
return self.absPath
}
readClass()函数通过调用openJar()打开ZIP文件,通过findClass()查找class文件,再通过readClass()参数是*zip.File的函数读取class文件内容。
4、CompositeEntry
在entry_composite.go文件中创建
package classpath import "errors"
import "strings" type CompositeEntry []Entry func newCompositeEntry(pathList string) CompositeEntry {
compositeEntry := []Entry{} for _, path := range strings.Split(pathList, pathListSeparator) {
entry := newEntry(path)
compositeEntry = append(compositeEntry, entry)
} return compositeEntry
} func (self CompositeEntry) readClass(className string) ([]byte, Entry, error) {
for _, entry := range self {
data, from, err := entry.readClass(className)
if err == nil {
return data, from, nil
}
} return nil, nil, errors.New("class not found: " + className)
} func (self CompositeEntry) String() string {
strs := make([]string, len(self)) for i, entry := range self {
strs[i] = entry.String()
} return strings.Join(strs, pathListSeparator)
}
newCompositeEntry()把参数按分隔符分成小路径然后把每个小路径转换成具体的Entry实例。
readClass()是依次调用每一个字路径的readClass()函数,若遇到错误,则继续,若找到class文件则返回,否则返回错误。
string()函数调用每一个字路径的String()函数,把得到的字符串用路径分隔符拼接起来。
5、WildcardEntry
创建entry_wildcard.go文件
package classpath import "os"
import "path/filepath"
import "strings" func newWildcardEntry(path string) CompositeEntry {
baseDir := path[:len(path)-1] // remove *
compositeEntry := []Entry{} walkFn := func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() && path != baseDir {
return filepath.SkipDir
}
if strings.HasSuffix(path, ".jar") || strings.HasSuffix(path, ".JAR") {
jarEntry := newZipEntry(path)
compositeEntry = append(compositeEntry, jarEntry)
}
return nil
} filepath.Walk(baseDir, walkFn) return compositeEntry
}
newWildcardEntry()函数使用CompositeEntry结构体,首先把末尾的*号去掉,得到baseDir,调用filepath包的Walk()函数遍历baseDir创建ZipEntry
6、classpath
在classpath.go中创建
package classpath import "os"
import "path/filepath" type Classpath struct {
bootClasspath Entry
extClasspath Entry
userClasspath Entry
} func Parse(jreOption, cpOption string) *Classpath {
cp := &Classpath{}
cp.parseBootAndExtClasspath(jreOption)
cp.parseUserClasspath(cpOption)
return cp
} func (self *Classpath) parseBootAndExtClasspath(jreOption string) {
jreDir := getJreDir(jreOption) // jre/lib/*
jreLibPath := filepath.Join(jreDir, "lib", "*")
self.bootClasspath = newWildcardEntry(jreLibPath) // jre/lib/ext/*
jreExtPath := filepath.Join(jreDir, "lib", "ext", "*")
self.extClasspath = newWildcardEntry(jreExtPath)
} func getJreDir(jreOption string) string {
if jreOption != "" && exists(jreOption) {
return jreOption
}
if exists("./jre") {
return "./jre"
}
if jh := os.Getenv("JAVA_HOME"); jh != "" {
return filepath.Join(jh, "jre")
}
panic("Can not find jre folder!")
} func exists(path string) bool {
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
} func (self *Classpath) parseUserClasspath(cpOption string) {
if cpOption == "" {
cpOption = "."
}
self.userClasspath = newEntry(cpOption)
} // className: fully/qualified/ClassName
func (self *Classpath) ReadClass(className string) ([]byte, Entry, error) {
className = className + ".class"
if data, entry, err := self.bootClasspath.readClass(className); err == nil {
return data, entry, err
}
if data, entry, err := self.extClasspath.readClass(className); err == nil {
return data, entry, err
}
return self.userClasspath.readClass(className)
} func (self *Classpath) String() string {
return self.userClasspath.String()
}
Calsspath结构体有三种字段对应三种类路径。Parse()函数使用-Xjre()选项解析启动类路径和扩展类路径,使用-classpath选项解析用户类路径。parseBootAndExtClasspath()函数。
getJreDir优先使用用户输入的-Xjre作为jre路径,若没有则在当前目录下查找jre目录,若没有,尝试JAVA_HOME环境变量。
exists()判断目录是否存在。
parsseUserClasspath()函数,若没有提供-cp选项,则使用当前目录为用户类路径,readClass()依次从启动类路径、扩展类路径和用户类路径中搜素class文件。
注意:传递给readClass()方法的类名不包含".class"后缀。
String()返回用户类路径的字符串。
四、测试
在main.go文件中添加两条import语句
import "strings"
import "jvmgo/classpath"
main()函数不变,重写startJVM()函数
func startJVM(cmd *Cmd) {
cp:=classpath.Parse(cmd.XjreOption,cmd.cpOption)
fmt.Printf("classpath:%v class: %v args: %v\n",cp,cmd.class,cmd.args)
className:= strings.Replace(cmd.class,".","/",-1)
classData,_,err:=cp.ReadClass(className)
if(err !=nil){
fmt.Printf("Could not find or load main class %s \n",cmd.class)
return
}
fmt.Printf("class Date:%v\n",classData)
}
然后运行go install jvmgo
在cmd中运行jvmgo.exe进行测试
PS D:\Program_Files\go\bin> .\jvmgo.exe -Xjre "D:\APP\java\java1.8\jdk1.8.0_171\jre" java.lang.Object
classpath:D:\Program_Files\go\bin class: java.lang.Object args: []
class Date:[202 254 186 190 0 0 0 52 0 78 3 0 15 66 63 8 0 16 8 0 38 8 0 42 1 0 3 40 41 73 1 0 20 40 41 76 106 97 118 97 47 108 97 110 103 47 79 98 106 101 99 116 59 1 0 20 40 41 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59 1 0 3 40 41 86 1 0 21 40 73 41 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59 1 0 4 40 74 41 86 1 0 5 40 74 73 41 86 1 0 21 40 76 106 97 118 97 47 108 97 110 103 47 79 98 106 101 99 116 59 41 90 1 0 21 40 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59 41 86 1 0 8 60 99 108 105 110 105 116 62 1 0 6 60 105 110 105 116 62 1 0 1 64 1 0 4 67 111 100 101 1 0 10 69 120 99 101 112 116 105 111 110 115 1 0 15 76 105 110 101 78 117 109 98 101 114 84 97 98 108 101 1 0 9 83 105 103 110 97 116 117 114 101 1 0 10 83 111 117 114 99 101 70 105 108 101 1 0 13 83 116 97 99 107 77 97 112 84 97 98 108 101 1 0 6 97 112 112 101 110 100 1 0 5 99 108 111 110 101 1 0 6 101 113 117 97 108 115 1 0 8 102 105 110 97 108 105 122 101 1 0 8 103 101 116 67 108 97 115 115 1 0 7 103 101 116 78 97 109 101 1 0 8 104 97 115 104 67 111 100 101 1 0 15 106 97 118 97 47 108 97 110 103 47 67 108 97 115 115 1 0 36 106 97 118 97 47 108 97 110 103 47 67 108 111 110 101 78 111 116 83 117 112 112 111 114 116 101 100 69 120 99 101 112 116 105 111 110 1 0 34 106 97 118 97 47 108 97 110 103 47 73 108 108 101 103 97 108 65 114 103 117 109 101 110 116 69 120 99 101 112 116 105 111 110 1 0 17 106 97 118 97 47 108 97 110 103 47 73 110 116 101 103 101 114 1 0 30 106 97 118 97 47 108 97 110 103 47 73 110 116 101 114 114 117 112 116 101 100 69 120 99 101 112 116 105 111 110 1 0 16 106 97 118 97 47 108 97 110 103 47 79 98 106 101 99 116 1 0 23 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 66 117 105 108 100 101 114 1 0 19 106 97 118 97 47 108 97 110 103 47 84 104 114 111 119 97 98 108 101 1 0 37 110 97 110 111 115 101 99 111 110 100 32 116 105 109 101 111 117 116 32 118 97 108 117 101 32 111 117 116 32 111 102 32 114 97 110 103 101 1 0 6 110 111 116 105 102 121 1 0 9 110 111 116 105 102 121 65 108 108 1 0 15 114 101 103 105 115 116 101 114 78 97 116 105 118 101 115 1 0 25 116 105 109 101 111 117 116 32 118 97 108 117 101 32 105 115 32 110 101 103 97 116 105 118 101 1 0 11 116 111 72 101 120 83 116 114 105 110 103 1 0 8 116 111 83 116 114 105 110 103 1 0 4 119 97 105 116 7 0 30 7 0 31 7 0 32 7 0 33 7 0 34 7 0 35 7 0 36 7 0 37 1 0 19 40 41 76 106 97 118 97 47 108 97 110 103 47 67 108 97 115 115 59 1 0 22 40 41 76 106 97 118 97 47 108 97 110 103 47 67 108 97 115 115 60 42 62 59 1 0 45 40 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59 41 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 66 117 105 108 100 101 114 59 12 0 29 0 5 12 0 15 0 8 12 0 41 0 8 12 0 45 0 10 12 0 27 0 54 12 0 28 0 7 12 0 44 0 7 12 0 43 0 9 12 0 15 0 13 12 0 23 0 56 10 0 46 0 62 10 0 48 0 65 10 0 49 0 64 10 0 51 0 57 10 0 51 0 59 10 0 51 0 60 10 0 51 0 61 10 0 52 0 58 10 0 52 0 63 10 0 52 0 66 1 0 11 79 98 106 101 99 116 46 106 97 118 97 0 33 0 51 0 0 0 0 0 0 0 14 0 1 0 15 0 8 0 1 0 17 0 0 0 25 0 0 0 1 0 0 0 1 177 0 0 0 1 0 19 0 0 0 6 0 1 0 0 0 37 1 10 0 41 0 8 0 0 1 17 0 27 0 54 0 1 0 20 0 0 0 2 0 55 1 1 0 29 0 5 0 0 0 1 0 25 0 12 0 1 0 17 0 0 0 46 0 2 0 2 0 0 0 11 42 43 166 0 7 4 167 0 4 3 172 0 0 0 2 0 22 0 0 0 5 0 2 9 64 1 0 19 0 0 0 6 0 1 0 0 0 149 1 4 0 24 0 6 0 1 0 18 0 0 0 4 0 1 0 47 0 1 0 44 0 7 0 1 0 17 0 0 0 60 0 2 0 1 0 0 0 36 187 0 52 89 183 0 74 42 182 0 73 182 0 67 182 0 76 18 2 182 0 76 42 182 0 70 184 0 69 182 0 76 182 0 75 176 0 0 0 1 0 19 0 0 0 6 0 1 0 0 0 236 1 17 0 39 0 8 0 0 1 17 0 40 0 8 0 0 1 17 0 45 0 10 0 1 0 18 0 0 0 4 0 1 0 50 0 17 0 45 0 11 0 2 0 17 0 0 0 114 0 4 0 4 0 0 0 50 31 9 148 156 0 13 187 0 48 89 18 4 183 0 68 191 29 155 0 9 29 18 1 164 0 13 187 0 48 89 18 3 183 0 68 191 29 158 0 7 31 10 97 64 42 31 182 0 72 177 0 0 0 2 0 22 0 0 0 6 0 4 16 9 9 7 0 19 0 0 0 34 0 8 0 0 1 191 0 6 1 192 0 16 1 195 0 26 1 196 0 36 1 200 0 40 1 201 0 44 1 204 0 49 1 205 0 18 0 0 0 4 0 1 0 50 0 17 0 45 0 8 0 2 0 17 0 0 0 34 0 3 0 1 0 0 0 6 42 9 182 0 72 177 0 0 0 1 0 19 0 0 0 10 0 2 0 0 1 246 0 5 1 247 0 18 0 0 0 4 0 1 0 50 0 4 0 26 0 8 0 2 0 17 0 0 0 25 0 0 0 1 0 0 0 1 177 0 0 0 1 0 19 0 0 0 6 0 1 0 0 2 43 0 18 0 0 0 4 0 1 0 53 0 8 0 14 0 8 0 1 0 17 0 0 0 32 0 0 0 0 0 0 0 4 184 0 71 177 0 0 0 1 0 19 0 0 0 10 0 2 0 0 0 41 0 3 0 42 0 1 0 21 0 0 0 2 0 77]
二、搜索class文件的更多相关文章
- linux下gcc默认搜索头文件及库文件的路径
一.头文件gcc 在编译时如何去寻找所需要的头文件:※所以header file的搜寻会从-I开始※然后找gcc的环境变量 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC ...
- java实现基于关键字的文件夹(文件)的搜索、文件夹(文件)的复制、删除
最近在做一个项目,需要实现这几项功能,上网查了很多资料,自己研究了好几天终于实现了,现在与大家分享一下. 一.JAVA实现文件夹的搜索 在百度搜索N个技术文章,从哪些大牛们共享的资料中终于写出了我 ...
- 获取文件的缩略图Thumbnail和通过 AQS - Advanced Query Syntax 搜索本地文件
演示如何获取文件的缩略图 FileSystem/ThumbnailAccess.xaml <Page x:Class="XamlDemo.FileSystem.ThumbnailAcc ...
- Linux如何搜索查找文件里面内容
在Linux系统当中,如何搜.索查找文件里面的内容呢? 这个应该是系统维护.管理当中遇到最常见的需求.那么下面介绍,总结一下如何搜索.查找文件当中的内容. 搜索.查找文件当中的内容,一般最常用的是gr ...
- C#搜索指定文件夹内的符合要求的文件
下面的列子是文件的模糊查找, 具体功能是:选定文件夹,搜索所有文件命中包含“_bui”字样的shp图层(后缀为.shp)并将信息显示在ListView中.实际应用中可随便修改. 这里采用递归方法进行深 ...
- Java递归搜索指定文件夹下的匹配文件
import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Queue; /** ...
- PostgreSQL的存储系统二:REDOLOG文件存储结构二
REDOLOG文件里的用户数据和数据文件里的用户数据存储结构相同 几个月前同事给台湾一家公司培训<pg9 ad admin>时,有个学员提及WAL里记录的内容为Query时的SQL语句(比 ...
- 重新想象 Windows 8 Store Apps (22) - 文件系统: 访问文件夹和文件, 通过 AQS 搜索本地文件
原文:重新想象 Windows 8 Store Apps (22) - 文件系统: 访问文件夹和文件, 通过 AQS 搜索本地文件 [源码下载] 重新想象 Windows 8 Store Apps ( ...
- 从零开始学C++之IO流类库(二):文件流(fstream, ifstream, ofstream)的打开关闭、流状态
一.文件流 ofstream,由ostream派生而来,用于写文件 ifstream,由istream派生而来, 用于读文件 fstream,由iostream派生而来,用于读写文件 二.打开文件 说 ...
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
随机推荐
- 通过iOS 9 SFSafariViewController提供完整的Web浏览体验
http://www.cocoachina.com/ios/20150826/13157.html 本文由CocoaChina译者@涛声依旧-忆往昔翻译自tutsplus校对:BenBeng原文:iO ...
- SDUT-2138_判断可达性
数据结构实验之图论三:判断可达性 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 在古老的魔兽传说中,有两个军团,一个叫 ...
- Nacos 发布 1.0.0 GA 版本,可大规模投入到生产环境
经过 3 个 RC 版本的社区体验之后,Nacos 正式发布 1.0.0 GA 版本,在架构.功能和 API 设计上进行了全方位的重构和升级. 1.0.0 版本的发布标志着 Nacos 已经可以大规模 ...
- Android 高仿微信语音聊天页面高斯模糊效果
目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...
- C#面向对象基础--类与对象
1.类与对象 类是面向对象编程的基本单元:类造出来的变量叫对象. 一个类包含俩种成员:字段与方法. 字段即变量,方法即函数. 面向对象思想:教给我们如何合理的运用类的规则去编写代码. 2.类的字段 字 ...
- jmeter日期处理beanshell(1)
import java.time.LocalDate; //昨天: String sdate1 = LocalDate.now().minusDays(1).toString(); vars.put( ...
- shell awk杂项
awk '{ ;++i<=NF;){ a[i]=a[i]?a[i]",'\''"$i"'\''":"'\''"$i"'\'' ...
- ORA-01089: 即時シャットダウン処理中 - 操作はできません
一:当时的情景 SQL> shutdown immediate --无任何返回结果 二:问题定位过程 1.查询相关进程只有ORACLE的关键进程存在 ps -ef |grep ora_ soad ...
- LRJ-Example-06-01-Uva210
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstdlib> #include <cstrin ...
- C++高精度加减乘除模板
其中高精度乘法通过了POJ2389,其他没有测过,不过应该是没有问题的. 其中高精度除法返回一对string,分别表示商和余数. 代码: #include <bits/stdc++.h> ...