001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.io; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.FileOutputStream; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.OutputStream; 025import java.net.URI; 026import java.net.URL; 027 028import org.springframework.util.Assert; 029import org.springframework.util.StringUtils; 030 031/** 032 * {@link Resource} implementation for {@code java.io.File} handles. 033 * Supports resolution as a {@code File} and also as a {@code URL}. 034 * Implements the extended {@link WritableResource} interface. 035 * 036 * @author Juergen Hoeller 037 * @since 28.12.2003 038 * @see java.io.File 039 */ 040public class FileSystemResource extends AbstractResource implements WritableResource { 041 042 private final File file; 043 044 private final String path; 045 046 047 /** 048 * Create a new {@code FileSystemResource} from a {@link File} handle. 049 * <p>Note: When building relative resources via {@link #createRelative}, 050 * the relative path will apply <i>at the same directory level</i>: 051 * e.g. new File("C:/dir1"), relative path "dir2" -> "C:/dir2"! 052 * If you prefer to have relative paths built underneath the given root 053 * directory, use the {@link #FileSystemResource(String) constructor with a file path} 054 * to append a trailing slash to the root path: "C:/dir1/", which 055 * indicates this directory as root for all relative paths. 056 * @param file a File handle 057 */ 058 public FileSystemResource(File file) { 059 Assert.notNull(file, "File must not be null"); 060 this.file = file; 061 this.path = StringUtils.cleanPath(file.getPath()); 062 } 063 064 /** 065 * Create a new {@code FileSystemResource} from a file path. 066 * <p>Note: When building relative resources via {@link #createRelative}, 067 * it makes a difference whether the specified resource base path here 068 * ends with a slash or not. In the case of "C:/dir1/", relative paths 069 * will be built underneath that root: e.g. relative path "dir2" -> 070 * "C:/dir1/dir2". In the case of "C:/dir1", relative paths will apply 071 * at the same directory level: relative path "dir2" -> "C:/dir2". 072 * @param path a file path 073 */ 074 public FileSystemResource(String path) { 075 Assert.notNull(path, "Path must not be null"); 076 this.file = new File(path); 077 this.path = StringUtils.cleanPath(path); 078 } 079 080 081 /** 082 * Return the file path for this resource. 083 */ 084 public final String getPath() { 085 return this.path; 086 } 087 088 /** 089 * This implementation returns whether the underlying file exists. 090 * @see java.io.File#exists() 091 */ 092 @Override 093 public boolean exists() { 094 return this.file.exists(); 095 } 096 097 /** 098 * This implementation checks whether the underlying file is marked as readable 099 * (and corresponds to an actual file with content, not to a directory). 100 * @see java.io.File#canRead() 101 * @see java.io.File#isDirectory() 102 */ 103 @Override 104 public boolean isReadable() { 105 return (this.file.canRead() && !this.file.isDirectory()); 106 } 107 108 /** 109 * This implementation opens a FileInputStream for the underlying file. 110 * @see java.io.FileInputStream 111 */ 112 @Override 113 public InputStream getInputStream() throws IOException { 114 return new FileInputStream(this.file); 115 } 116 117 /** 118 * This implementation checks whether the underlying file is marked as writable 119 * (and corresponds to an actual file with content, not to a directory). 120 * @see java.io.File#canWrite() 121 * @see java.io.File#isDirectory() 122 */ 123 @Override 124 public boolean isWritable() { 125 return (this.file.canWrite() && !this.file.isDirectory()); 126 } 127 128 /** 129 * This implementation opens a FileOutputStream for the underlying file. 130 * @see java.io.FileOutputStream 131 */ 132 @Override 133 public OutputStream getOutputStream() throws IOException { 134 return new FileOutputStream(this.file); 135 } 136 137 /** 138 * This implementation returns a URL for the underlying file. 139 * @see java.io.File#toURI() 140 */ 141 @Override 142 public URL getURL() throws IOException { 143 return this.file.toURI().toURL(); 144 } 145 146 /** 147 * This implementation returns a URI for the underlying file. 148 * @see java.io.File#toURI() 149 */ 150 @Override 151 public URI getURI() throws IOException { 152 return this.file.toURI(); 153 } 154 155 /** 156 * This implementation returns the underlying File reference. 157 */ 158 @Override 159 public File getFile() { 160 return this.file; 161 } 162 163 /** 164 * This implementation returns the underlying File's length. 165 */ 166 @Override 167 public long contentLength() throws IOException { 168 return this.file.length(); 169 } 170 171 /** 172 * This implementation creates a FileSystemResource, applying the given path 173 * relative to the path of the underlying file of this resource descriptor. 174 * @see org.springframework.util.StringUtils#applyRelativePath(String, String) 175 */ 176 @Override 177 public Resource createRelative(String relativePath) { 178 String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); 179 return new FileSystemResource(pathToUse); 180 } 181 182 /** 183 * This implementation returns the name of the file. 184 * @see java.io.File#getName() 185 */ 186 @Override 187 public String getFilename() { 188 return this.file.getName(); 189 } 190 191 /** 192 * This implementation returns a description that includes the absolute 193 * path of the file. 194 * @see java.io.File#getAbsolutePath() 195 */ 196 @Override 197 public String getDescription() { 198 return "file [" + this.file.getAbsolutePath() + "]"; 199 } 200 201 202 /** 203 * This implementation compares the underlying File references. 204 */ 205 @Override 206 public boolean equals(Object obj) { 207 return (obj == this || 208 (obj instanceof FileSystemResource && this.path.equals(((FileSystemResource) obj).path))); 209 } 210 211 /** 212 * This implementation returns the hash code of the underlying File reference. 213 */ 214 @Override 215 public int hashCode() { 216 return this.path.hashCode(); 217 } 218 219}