001/* 002 * Copyright (C) 2007 The Guava 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 * http://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 com.google.common.io; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021 022import com.google.common.annotations.Beta; 023import com.google.common.base.Charsets; 024import com.google.common.base.Objects; 025import com.google.common.collect.Lists; 026 027import java.io.IOException; 028import java.io.InputStream; 029import java.io.InputStreamReader; 030import java.io.OutputStream; 031import java.net.URL; 032import java.nio.charset.Charset; 033import java.util.List; 034 035/** 036 * Provides utility methods for working with resources in the classpath. 037 * Note that even though these methods use {@link URL} parameters, they 038 * are usually not appropriate for HTTP or other non-classpath resources. 039 * 040 * <p>All method parameters must be non-null unless documented otherwise. 041 * 042 * @author Chris Nokleberg 043 * @author Ben Yu 044 * @author Colin Decker 045 * @since 1.0 046 */ 047@Beta 048public final class Resources { 049 private Resources() {} 050 051 /** 052 * Returns a factory that will supply instances of {@link InputStream} that 053 * read from the given URL. 054 * 055 * @param url the URL to read from 056 * @return the factory 057 */ 058 public static InputSupplier<InputStream> newInputStreamSupplier(URL url) { 059 return ByteStreams.asInputSupplier(asByteSource(url)); 060 } 061 062 /** 063 * Returns a {@link ByteSource} that reads from the given URL. 064 * 065 * @since 14.0 066 */ 067 public static ByteSource asByteSource(URL url) { 068 return new UrlByteSource(url); 069 } 070 071 /** 072 * A byte source that reads from a URL using {@link URL#openStream()}. 073 */ 074 private static final class UrlByteSource extends ByteSource { 075 076 private final URL url; 077 078 private UrlByteSource(URL url) { 079 this.url = checkNotNull(url); 080 } 081 082 @Override 083 public InputStream openStream() throws IOException { 084 return url.openStream(); 085 } 086 087 @Override 088 public String toString() { 089 return "Resources.asByteSource(" + url + ")"; 090 } 091 } 092 093 /** 094 * Returns a factory that will supply instances of 095 * {@link InputStreamReader} that read a URL using the given character set. 096 * 097 * @param url the URL to read from 098 * @param charset the charset used to decode the input stream; see {@link 099 * Charsets} for helpful predefined constants 100 * @return the factory 101 */ 102 public static InputSupplier<InputStreamReader> newReaderSupplier( 103 URL url, Charset charset) { 104 return CharStreams.asInputSupplier(asCharSource(url, charset)); 105 } 106 107 /** 108 * Returns a {@link CharSource} that reads from the given URL using the given character set. 109 * 110 * @since 14.0 111 */ 112 public static CharSource asCharSource(URL url, Charset charset) { 113 return asByteSource(url).asCharSource(charset); 114 } 115 116 /** 117 * Reads all bytes from a URL into a byte array. 118 * 119 * @param url the URL to read from 120 * @return a byte array containing all the bytes from the URL 121 * @throws IOException if an I/O error occurs 122 */ 123 public static byte[] toByteArray(URL url) throws IOException { 124 return asByteSource(url).read(); 125 } 126 127 /** 128 * Reads all characters from a URL into a {@link String}, using the given 129 * character set. 130 * 131 * @param url the URL to read from 132 * @param charset the charset used to decode the input stream; see {@link 133 * Charsets} for helpful predefined constants 134 * @return a string containing all the characters from the URL 135 * @throws IOException if an I/O error occurs. 136 */ 137 public static String toString(URL url, Charset charset) throws IOException { 138 return asCharSource(url, charset).read(); 139 } 140 141 /** 142 * Streams lines from a URL, stopping when our callback returns false, or we 143 * have read all of the lines. 144 * 145 * @param url the URL to read from 146 * @param charset the charset used to decode the input stream; see {@link 147 * Charsets} for helpful predefined constants 148 * @param callback the LineProcessor to use to handle the lines 149 * @return the output of processing the lines 150 * @throws IOException if an I/O error occurs 151 */ 152 public static <T> T readLines(URL url, Charset charset, 153 LineProcessor<T> callback) throws IOException { 154 return CharStreams.readLines(newReaderSupplier(url, charset), callback); 155 } 156 157 /** 158 * Reads all of the lines from a URL. The lines do not include 159 * line-termination characters, but do include other leading and trailing 160 * whitespace. 161 * 162 * <p>This method returns a mutable {@code List}. For an 163 * {@code ImmutableList}, use 164 * {@code Resources.asCharSource(url, charset).readLines()}. 165 * 166 * @param url the URL to read from 167 * @param charset the charset used to decode the input stream; see {@link 168 * Charsets} for helpful predefined constants 169 * @return a mutable {@link List} containing all the lines 170 * @throws IOException if an I/O error occurs 171 */ 172 public static List<String> readLines(URL url, Charset charset) 173 throws IOException { 174 // don't use asCharSource(url, charset).readLines() because that returns 175 // an immutable list, which would change the behavior of this method 176 return readLines(url, charset, new LineProcessor<List<String>>() { 177 final List<String> result = Lists.newArrayList(); 178 179 @Override 180 public boolean processLine(String line) { 181 result.add(line); 182 return true; 183 } 184 185 @Override 186 public List<String> getResult() { 187 return result; 188 } 189 }); 190 } 191 192 /** 193 * Copies all bytes from a URL to an output stream. 194 * 195 * @param from the URL to read from 196 * @param to the output stream 197 * @throws IOException if an I/O error occurs 198 */ 199 public static void copy(URL from, OutputStream to) throws IOException { 200 asByteSource(from).copyTo(to); 201 } 202 203 /** 204 * Returns a {@code URL} pointing to {@code resourceName} if the resource is 205 * found using the {@linkplain Thread#getContextClassLoader() context class 206 * loader}. In simple environments, the context class loader will find 207 * resources from the class path. In environments where different threads can 208 * have different class loaders, for example app servers, the context class 209 * loader will typically have been set to an appropriate loader for the 210 * current thread. 211 * 212 * <p>In the unusual case where the context class loader is null, the class 213 * loader that loaded this class ({@code Resources}) will be used instead. 214 * 215 * @throws IllegalArgumentException if the resource is not found 216 */ 217 public static URL getResource(String resourceName) { 218 ClassLoader loader = Objects.firstNonNull( 219 Thread.currentThread().getContextClassLoader(), 220 Resources.class.getClassLoader()); 221 URL url = loader.getResource(resourceName); 222 checkArgument(url != null, "resource %s not found.", resourceName); 223 return url; 224 } 225 226 /** 227 * Given a {@code resourceName} that is relative to {@code contextClass}, 228 * returns a {@code URL} pointing to the named resource. 229 * 230 * @throws IllegalArgumentException if the resource is not found 231 */ 232 public static URL getResource(Class<?> contextClass, String resourceName) { 233 URL url = contextClass.getResource(resourceName); 234 checkArgument(url != null, "resource %s relative to %s not found.", 235 resourceName, contextClass.getName()); 236 return url; 237 } 238}