您的位置:首页 > 其它

关于项目中读取文件的探讨

2016-09-24 16:28 246 查看
知识点来自:
1.javase中的类加载路径

2.java.io中的基本api类

前言:

        最近负责一个代码生成器的项目,还要做成一个eclipse插件的形式,后期还要做成可视化的方式。本身项目所要求的技术点不难,需要用到大量的文件读写,文件复制,已经文件所在位置的查找,读写以及复制比较好说,前提就是查找文件所在位置这点,故此有了此篇文章。

先来说一个概念:

URL:是网络中存在的一个资源文件,表示统一资源定位符号(uniform resource locator URL),表示toString的形式一般是:file:/D:/Day1.java或者jar:/D:/Day1.java,还有或者是其他的,例如笔者所做的项目中URL表示形式:bundleresource://709.fwk15218962:1/META-INF/MANIFEST.MF

File:表示的是一个文件,可以是目录,也可以是文件夹,表示toString的形式是:D:\Day1.java

以上2点很概念重要,对于子个项目进行集成时候。

进入正题:

读取项目中的文件(位置):

maven项目中的目录结构以及真实发布后的结构如下:



我们要读的是红线画圈的所表示的文件,实际打包后要读取的是target中的打包中文件所在的位置,推荐方式使用java的class所在方式进行读取。

使用类加载的方式读取文件的好处是能读取到classes中该类所在的位置,在在同级,上级,下级目录或者文件就简单容易很多。

细节如下:

1.getResource()

URL resource = MyFile.class.getResource("");
URL resource1 = MyFile.class.getResource("/");


打印结果:

file
file:/D:/Users/eclipse-git/File/target/classes/com/lgy/file/
---------
d5c7
-----------
file
file:/D:/Users/eclipse-git/File/target/classes/
说明:

不加/和加/的区别:前者查找出类所在的绝对路径,后者加/是查找classes下的路径,/com则是查找classes下的com路径,若没有则会抛出空指针异常。

注意,在maven项目汇总的test目录下进行测试时候会发现,resource1的打印结果会是file:/D:/Users/eclipse-git/File/target/test-classes/,但是项目的真实环境不会出现,没人会把test下的文件拿出来使用。

2.getClassLoader

与上面类似。只不过相反,不做解释

对应的读取文件位置就简单多了:

URL resource = MyFile.class.getResource("/");
String path = resource.getPath();
System.out.println(path);
File f = new File(path+ "bbb.txt") ;
System.out.println(f.exists());


打印结果为true

这种方式真是是一劳永逸吗?

--------------------------------------------------------------------------------jar篇幅-------------------------------------------------------------------------------------------------------------------------------------

尝试着把你那个项目使用maven依赖,供其他子项目进行使用,你发现原来读写那个文件是好使的变成不好使不?依赖的pom文件如下:

<dependency>
<groupId>com.lgy</groupId>
<artifactId>File</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>




之前File项目中有一个MyFile测试方法内容如下:

package com.lgy.file;

import java.io.File;
import java.net.URL;

public class MyFile {
public static void main(String[] args) {
MyFile.test();
}

public static void test() {
//测试com/lgy/file 中的ccc.txt文件
URL resource = MyFile.class.getResource("/com/lgy/file/");
String path = resource.getPath();
System.out.println(resource.getProtocol());
System.out.println(path);
File f = new File(path+ "ccc.txt") ;
System.out.println(f.exists());

System.out.println("**************************");
//测试resources中的文件
URL resource1 = MyFile.class.getResource("/");
String path1 = resource1.getPath();
System.out.println(resource1.getProtocol());
System.out.println(path1);
File f1 = new File(path1+ "aaa.txt") ;
System.out.println(f1.exists());
}
}


打印结果:

file
/D:/Users/eclipse-git/File/target/classes/com/lgy/file/
true
**************************
file
/D:/Users/eclipse-git/File/target/classes/
true


一个是类路径下放的一个文件,一个是resource下存放的一个文件,都有。此时在新的项目TestMaven下面执行该方法,结果如下:

file
/D:/Users/eclipse-git/File/target/classes/com/lgy/file/
true
**************************
file
/D:/Users/eclipse-git/TestMaven/target/classes/
false


可以看到放在类路径下的文件找到了打印为True,而在resource下的文件确找不到打印却为了fasle。

分析原因,不难找出, MyFile.class.getResource("/")获取resources根路径时候找的是本项目的,此项目若没有则不会在其他依赖中的项目进行查找。

问题?若其他项目放在了resources下的文件如何查找呢?

带着这个问题,试着将之前的那个文件打包成jar,供另一个maven项目使用。此时的项目目录结构如下:



同样的MyFile测试方法方法,执行结果如何呢?

jar
file:/D:/Users/eclipse-git/File/target/File.jar!/com/lgy/file/
false
**************************
file
/D:/Users/eclipse-git/TestMaven/target/classes/
false


分析结果:都为false文件查找不存在,第二个还是查找本项目中的resources下的文件所有查找不到,但是第一个打印的是什么?jar,回头看看打印出jar这个函数:

URL resource = MyFile.class.getResource("/com/lgy/file/");

System.out.println(resource.getProtocol());

没错就是URL中的protocol,URL中的协议类型说明了此资源定位符所在的协议类型是什么,此时打印出来的jar恰巧说明了文件在jar中。若要读取该下的文件如何读取呢?

方式一:

类加载起中有一种加载方式可以获取到jar下的文件,以流的方式:

InputStream in = Test.class.getResourceAsStream("/com/lgy/file/ccc.txt");


此时并可读到在类路径下的ccc.txt下的内容文件。

方式二:

如果文件的协议是jar,则用解析jar的方式进行:

if (url.getProtocol().equalsIgnoreCase("jar")) {
String path = MyFile.class.getProtectionDomain().getCodeSource().getLocation().getPath();

try {
JarFile jf = new JarFile(path);
Enumeration<JarEntry> e = jf.entries();
while (e.hasMoreElements()) {
JarEntry je = e.nextElement();
//获取jar中文件的名称
if (je.getName().startsWith("com/lgy/file/ccc.txt")) {
System.out.println(je.getName());
System.out.println(je.isDirectory());
System.out.println(changeInpstream2String(jf.getInputStream(je)));
}
}
jf.close();

} catch (IOException e) {
e.printStackTrace();
}
}


最后关于URL的一个问题,笔者在制作eclipse plugin的时候遇到读取file是的协议是:bundleresource,解决思路是:

package com.gsafety.cloudframework.eclipseurl;

import java.io.IOException;
import java.net.URL;

import org.eclipse.core.runtime.FileLocator;

public class EclipseLocator implements Locator {
public URL resolve(URL url)  {
try {
return FileLocator.resolve(url);
} catch (IOException e) {
e.printStackTrace();
}
return url;
}
}


使用eclipse中提供的api转换为新的URL,此时的URL是的协议类型是jar,在解析的话就容易许多。

完结,总结不易,但是成长确实很大。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: