package jef.tools; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import jef.common.log.LogUtil; /** * 习惯用File来进行资源的IO操作。 * 但实际上Java对资源的访问定位基本上是采用URL方式来做的。 * * File方式的好处:File对象可以很方便的进行读写操作 * URL方式的好处:可以以描述zip/jar包中的文件,以及位于网络上的资源文件。虽然这些文件只能读不能写,但URL对象却是是唯一能完整描述各种资源定位的唯一手段。 * * 这个设计思路上的差异随着JEF的变迁日益突出。JEF最初试图封装出一种可读写的资源统一API,(以File为主)。 * 但是随后又碰到各种复杂的资源定位路径的问题,最后越搞越复杂。 * * 这个类就是当初试图让URL类的资源向File类靠拢而设计的。不管怎么说,这个类至少起到了一个本地缓存的作用。或许是今后对统一资源定位抽象设计进行改善的一个方法。 * * @author jiyi * */ public class URLFile extends File { private static final long serialVersionUID = 6607216819937577215L; private File rwFile; private File zipFile;//所在Zip包的文件 private String zippedPath;//在Zip包中的路径 private URL url; private String type; private String path; //仅当URL时 private boolean exist=true; private File data; /** * 将非本地文件复制为一个临时文件 */ private void loadData(){ if(exist && data!=null)return; try{ InputStream in=url.openStream(); data=IOUtils.saveAsTempFile(in); }catch(IOException e){ LogUtil.exception("loading "+url.toString()+" error!", e); exist=false; }catch(Throwable t){ LogUtil.exception("Load file " + url +" error!",t); exist=false; } } /** * 是否一个本地文件 * @return */ public boolean isLocalFile(){ return rwFile!=null; } /** * 返回本地文件,只有当{@link #isLocalFile()}=true时才能使用 * @return */ public File getLocalFile(){ Assert.notNull(rwFile); return rwFile; } public FileInputStream getInputStream() throws IOException{ if(rwFile!=null){ return new FileInputStream(rwFile); } loadData(); if(data!=null){ return new FileInputStream(data); } throw new FileNotFoundException("File " + path +" not exist!" ); } public URLFile(URI uri) { super(""); try { this.url=uri.toURL(); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } init(); } public URLFile(URL url) { super(""); Assert.notNull(url); this.url=url; init(); } private void init(){ this.type=url.getProtocol().toLowerCase(); try { path=URLDecoder.decode(url.getPath(), "UTF-8"); } catch (UnsupportedEncodingException e) { //Never Happens } if("file".equals(type)){ rwFile=new File(path); }else if("jar".equals(type)){//位于JAR文件中 String zipName=StringUtils.substringAfter(StringUtils.substringBefore(path, "!"), "file:"); while(zipName.startsWith("//")){ zipName=zipName.substring(1);//丢弃一个/ } this.zipFile=new File(zipName); Assert.fileExist(zipFile); this.zippedPath=StringUtils.substringAfter(path, "!"); }else if("zip".equals(type)){ String zipName=StringUtils.substringBefore(path, "!"); this.zipFile=new File(zipName); Assert.fileExist(zipFile); this.zippedPath=StringUtils.substringAfter(path, "!"); } if(path.charAt(0)=='/')path=path.substring(1); } @Override public String getName() { return StringUtils.substringAfterLastIfExist(path, "/"); } @Override public String getParent() { if(rwFile!=null){ return rwFile.getParent(); } String s=url.toString(); if(s.indexOf('/')>-1){ return StringUtils.substringBeforeLast(url.toString(), "/"); }else{ return null; } } @Override public File getParentFile() { if(rwFile!=null){ return rwFile.getParentFile(); } String parent=getParent(); if(parent==null)return null; parent=parent.replace('\\', '/'); parent=StringUtils.substringBeforeLast(parent, "/"); if(parent.endsWith("!")){ parent=parent.substring(4,parent.length()-1); } try { URL url=new URL(parent); return new URLFile(url); } catch (MalformedURLException e) { throw new IllegalArgumentException("error create Parent UrlFile:["+parent+"]"+e.getMessage()); } } @Override public String getPath() { if(rwFile!=null){ return rwFile.getPath(); } return path; } @Override public boolean isAbsolute() { if(rwFile!=null){ return rwFile.isAbsolute(); } return true; } @Override public String getAbsolutePath() { if(rwFile!=null){ return rwFile.getAbsolutePath(); } return path; } @Override public File getAbsoluteFile() { if(rwFile!=null){ return rwFile.getAbsoluteFile(); } return this; } @Override public String getCanonicalPath() throws IOException { if(rwFile!=null){ return rwFile.getCanonicalPath(); } return path; } @Override public File getCanonicalFile() throws IOException { if(rwFile!=null){ return rwFile.getCanonicalFile(); } return this; } @Override public URL toURL() throws MalformedURLException { return url; } @Override public URI toURI() { if(rwFile!=null){ return rwFile.toURI(); } try { return url.toURI(); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } } @Override public boolean canRead() { if(rwFile!=null){ return rwFile.canRead(); } loadData(); return exist; } @Override public boolean canWrite() { if(rwFile!=null){ return rwFile.canWrite(); } return false; } @Override public boolean exists() { if(rwFile!=null){ return rwFile.exists(); } loadData(); return exist; } @Override public boolean isDirectory() { if(rwFile!=null){ return rwFile.isDirectory(); } return path.endsWith("/"); } @Override public boolean isFile() { if(rwFile!=null){ return rwFile.isFile(); } return !path.endsWith("/"); } @Override public boolean isHidden() { if(rwFile!=null){ return rwFile.isHidden(); } return false; } @Override public long lastModified() { if(rwFile!=null){ return rwFile.lastModified(); }else if(zipFile!=null){ return zipFile.lastModified();//返回ZIP文件内的日期 } loadData(); if(exist){ return data.lastModified(); } return -1; } public boolean isZipFile(){ return this.zipFile!=null; } public File getZipContainer(){ Assert.notNull(zipFile); return this.zipFile; } public String getZipEntryPath(){ Assert.notNull(zippedPath); return this.zippedPath; } @Override public long length() { if(rwFile!=null){ return rwFile.length(); } loadData(); if(exist){ return data.length(); } return -1; } @Override public boolean createNewFile() throws IOException { if(rwFile!=null){ return rwFile.createNewFile(); } return false; } @Override public boolean delete() { if(rwFile!=null){ return rwFile.delete(); } if(data!=null){ data.delete(); exist=false; data=null; } return false; } @Override public void deleteOnExit() { if(rwFile!=null){ rwFile.deleteOnExit(); } if(data!=null){ data.deleteOnExit(); exist=false; data=null; } } @Override public String[] list() { if(rwFile!=null){ return rwFile.list(); } return ArrayUtils.EMPTY_STRING_ARRAY; } @Override public String[] list(FilenameFilter filter) { if(rwFile!=null){ return rwFile.list(filter); } return ArrayUtils.EMPTY_STRING_ARRAY; } @Override public File[] listFiles() { if(rwFile!=null){ return rwFile.listFiles(); } return new File[0]; } @Override public File[] listFiles(FilenameFilter filter) { if(rwFile!=null){ return rwFile.listFiles(filter); } return new File[0]; } @Override public File[] listFiles(FileFilter filter) { if(rwFile!=null){ return rwFile.listFiles(filter); } return new File[0]; } @Override public boolean mkdir() { if(rwFile!=null){ return rwFile.mkdir(); } return false; } @Override public boolean mkdirs() { if(rwFile!=null){ return rwFile.mkdirs(); } return false; } @Override public boolean renameTo(File dest) { if(rwFile!=null){ return rwFile.renameTo(dest); } return false; } @Override public boolean setLastModified(long time) { if(rwFile!=null){ return rwFile.setLastModified(time); } if(data!=null){ return data.setLastModified(time); } return false; } @Override public boolean setReadOnly() { if(rwFile!=null){ return rwFile.setReadOnly(); } return true; } @Override public int compareTo(File pathname) { if(rwFile!=null){ return rwFile.compareTo(pathname); } if(pathname==null)return 1; return getPath().compareTo(pathname.getPath()); } @Override public boolean equals(Object obj) { if(obj==null)return false; if(rwFile!=null){ return rwFile.equals(obj); } if(obj instanceof File){ return ((File) obj).getPath().equals(this.url.getFile()); } return super.equals(obj); } @Override public int hashCode() { if(rwFile!=null){ return rwFile.hashCode(); } return url.toString().hashCode(); } @Override public String toString() { if(rwFile!=null){ return rwFile.toString(); } return url.toString(); } }