一、类路径

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文件的更多相关文章

  1. linux下gcc默认搜索头文件及库文件的路径

    一.头文件gcc 在编译时如何去寻找所需要的头文件:※所以header file的搜寻会从-I开始※然后找gcc的环境变量 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC ...

  2. java实现基于关键字的文件夹(文件)的搜索、文件夹(文件)的复制、删除

    最近在做一个项目,需要实现这几项功能,上网查了很多资料,自己研究了好几天终于实现了,现在与大家分享一下. 一.JAVA实现文件夹的搜索   在百度搜索N个技术文章,从哪些大牛们共享的资料中终于写出了我 ...

  3. 获取文件的缩略图Thumbnail和通过 AQS - Advanced Query Syntax 搜索本地文件

    演示如何获取文件的缩略图 FileSystem/ThumbnailAccess.xaml <Page x:Class="XamlDemo.FileSystem.ThumbnailAcc ...

  4. Linux如何搜索查找文件里面内容

    在Linux系统当中,如何搜.索查找文件里面的内容呢? 这个应该是系统维护.管理当中遇到最常见的需求.那么下面介绍,总结一下如何搜索.查找文件当中的内容. 搜索.查找文件当中的内容,一般最常用的是gr ...

  5. C#搜索指定文件夹内的符合要求的文件

    下面的列子是文件的模糊查找, 具体功能是:选定文件夹,搜索所有文件命中包含“_bui”字样的shp图层(后缀为.shp)并将信息显示在ListView中.实际应用中可随便修改. 这里采用递归方法进行深 ...

  6. Java递归搜索指定文件夹下的匹配文件

    import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Queue; /** ...

  7. PostgreSQL的存储系统二:REDOLOG文件存储结构二

    REDOLOG文件里的用户数据和数据文件里的用户数据存储结构相同 几个月前同事给台湾一家公司培训<pg9 ad admin>时,有个学员提及WAL里记录的内容为Query时的SQL语句(比 ...

  8. 重新想象 Windows 8 Store Apps (22) - 文件系统: 访问文件夹和文件, 通过 AQS 搜索本地文件

    原文:重新想象 Windows 8 Store Apps (22) - 文件系统: 访问文件夹和文件, 通过 AQS 搜索本地文件 [源码下载] 重新想象 Windows 8 Store Apps ( ...

  9. 从零开始学C++之IO流类库(二):文件流(fstream, ifstream, ofstream)的打开关闭、流状态

    一.文件流 ofstream,由ostream派生而来,用于写文件 ifstream,由istream派生而来, 用于读文件 fstream,由iostream派生而来,用于读写文件 二.打开文件 说 ...

  10. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

随机推荐

  1. hdu3549 最大流

    #include<stdio.h> #include<string.h> #include<queue> #define MAXN 1010 using names ...

  2. 服务网关zuul----zuul中的动态刷新路由配置

    Spring Cloud实战小贴士:Zuul处理Cookie和重定向 所以解决该问题的思路也很简单,我们只需要通过设置sensitiveHeaders即可,设置方法分为两种: 全局设置: zuul.s ...

  3. 【uml】之用例图中的关系 标签: uml图形 2014-11-23 11:10 1422人阅读 评论(29)

    用例图显示谁是相关的用户,用户希望系统提供什么样的服务(用例),用例之间的关系图,用例图主要的作用是获取需求.指导测试.所以,用例图是站在用户的角度来画的图,应该体现的是用户想要的功能,并不需要体现如 ...

  4. DateFormat 日期格式化类(必须掌握)

    package com.sxt.utils.date1; import java.util.Date; import java.text.DateFormat; import java.text.Si ...

  5. spring的父子关系

    1.父容器不能拿子容器的资源 2.子容器可以拿到父容器的资源

  6. @atcoder - CODE FESTIVAL 2017 Final - J@ Tree MST

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N 个点,第 i 点有一个点权 Xi,再给定一棵边带权的树 ...

  7. Vue.js 第5章 webpack配置

    为什么我们需要打包构建工具:因为我们以后做项目的时候,会使用到很多种不同的工具或者语言,这些工具或者语言其实浏览器并不支持 webpack 是一个现代 JavaScript 应用程序的模块打包器(mo ...

  8. 06多次查询某区间内topk问题

            题目描述:给定一个数组,需要多次查找不同区间内的,第k大或者第k小的元素.         考虑题目是多次查找,如果采用只对查询区间内的元素进行排序的思路,然后输出第k大的数的策略,那 ...

  9. maxCompute odps 行转列

    select name ,REGEXP_REPLACE(str,"[\\[\"\\]]",'') from ( select trans_array(, ",& ...

  10. hdu 1434 幸福列车 (Leftist Tree)

    Problem - 1434 网上题解是普通的堆合并,都是用优先队列直接做的.可是正解的堆合并应该是用左偏堆或者斐波那契堆的吧,不然O(X * N ^ 2)的复杂度应该是过不了的.斐波那契堆的实现相对 ...