Mercurial > lasercutter
view src/clojure/java/io.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 ; Copyright (c) Rich Hickey. All rights reserved.2 ; The use and distribution terms for this software are covered by the3 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)4 ; which can be found in the file epl-v10.html at the root of this distribution.5 ; By using this software in any fashion, you are agreeing to be bound by6 ; the terms of this license.7 ; You must not remove this notice, or any other, from this software.9 (ns10 ^{:author "Stuart Sierra, Chas Emerick, Stuart Halloway",11 :doc "This file defines polymorphic I/O utility functions for Clojure."}12 clojure.java.io13 (:import14 (java.io Reader InputStream InputStreamReader PushbackReader15 BufferedReader File OutputStream16 OutputStreamWriter BufferedWriter Writer17 FileInputStream FileOutputStream ByteArrayOutputStream18 StringReader ByteArrayInputStream19 BufferedInputStream BufferedOutputStream20 CharArrayReader Closeable)21 (java.net URI URL MalformedURLException Socket)))23 (def24 ^{:doc "Type object for a Java primitive byte array."25 :private true26 }27 byte-array-type (class (make-array Byte/TYPE 0)))29 (def30 ^{:doc "Type object for a Java primitive char array."31 :private true}32 char-array-type (class (make-array Character/TYPE 0)))34 (defprotocol ^{:added "1.2"} Coercions35 "Coerce between various 'resource-namish' things."36 (^{:tag java.io.File, :added "1.2"} as-file [x] "Coerce argument to a file.")37 (^{:tag java.net.URL, :added "1.2"} as-url [x] "Coerce argument to a URL."))39 (extend-protocol Coercions40 nil41 (as-file [_] nil)42 (as-url [_] nil)44 String45 (as-file [s] (File. s))46 (as-url [s] (URL. s))48 File49 (as-file [f] f)50 (as-url [f] (.toURL f))52 URL53 (as-url [u] u)54 (as-file [u]55 (if (= "file" (.getProtocol u))56 (as-file (.getPath u))57 (throw (IllegalArgumentException. "Not a file: " u))))59 URI60 (as-url [u] (.toURL u))61 (as-file [u] (as-file (as-url u))))63 (defprotocol ^{:added "1.2"} IOFactory64 "Factory functions that create ready-to-use, buffered versions of65 the various Java I/O stream types, on top of anything that can66 be unequivocally converted to the requested kind of stream.68 Common options include70 :append true to open stream in append mode71 :encoding string name of encoding to use, e.g. \"UTF-8\".73 Callers should generally prefer the higher level API provided by74 reader, writer, input-stream, and output-stream."75 (^{:added "1.2"} make-reader [x opts] "Creates a BufferedReader. See also IOFactory docs.")76 (^{:added "1.2"} make-writer [x opts] "Creates a BufferedWriter. See also IOFactory docs.")77 (^{:added "1.2"} make-input-stream [x opts] "Creates a BufferedInputStream. See also IOFactory docs.")78 (^{:added "1.2"} make-output-stream [x opts] "Creates a BufferedOutputStream. See also IOFactory docs."))80 (defn ^Reader reader81 "Attempts to coerce its argument into an open java.io.Reader.82 Default implementations always return a java.io.BufferedReader.84 Default implementations are provided for Reader, BufferedReader,85 InputStream, File, URI, URL, Socket, byte arrays, character arrays,86 and String.88 If argument is a String, it tries to resolve it first as a URI, then89 as a local file name. URIs with a 'file' protocol are converted to90 local file names.92 Should be used inside with-open to ensure the Reader is properly93 closed."94 {:added "1.2"}95 [x & opts]96 (make-reader x (when opts (apply hash-map opts))))98 (defn ^Writer writer99 "Attempts to coerce its argument into an open java.io.Writer.100 Default implementations always return a java.io.BufferedWriter.102 Default implementations are provided for Writer, BufferedWriter,103 OutputStream, File, URI, URL, Socket, and String.105 If the argument is a String, it tries to resolve it first as a URI, then106 as a local file name. URIs with a 'file' protocol are converted to107 local file names.109 Should be used inside with-open to ensure the Writer is properly110 closed."111 {:added "1.2"}112 [x & opts]113 (make-writer x (when opts (apply hash-map opts))))115 (defn ^InputStream input-stream116 "Attempts to coerce its argument into an open java.io.InputStream.117 Default implementations always return a java.io.BufferedInputStream.119 Default implementations are defined for OutputStream, File, URI, URL,120 Socket, byte array, and String arguments.122 If the argument is a String, it tries to resolve it first as a URI, then123 as a local file name. URIs with a 'file' protocol are converted to124 local file names.126 Should be used inside with-open to ensure the InputStream is properly127 closed."128 {:added "1.2"}129 [x & opts]130 (make-input-stream x (when opts (apply hash-map opts))))132 (defn ^OutputStream output-stream133 "Attempts to coerce its argument into an open java.io.OutputStream.134 Default implementations always return a java.io.BufferedOutputStream.136 Default implementations are defined for OutputStream, File, URI, URL,137 Socket, and String arguments.139 If the argument is a String, it tries to resolve it first as a URI, then140 as a local file name. URIs with a 'file' protocol are converted to141 local file names.143 Should be used inside with-open to ensure the OutputStream is144 properly closed."145 {:added "1.2"}146 [x & opts]147 (make-output-stream x (when opts (apply hash-map opts))))149 (defn- ^Boolean append? [opts]150 (boolean (:append opts)))152 (defn- ^String encoding [opts]153 (or (:encoding opts) "UTF-8"))155 (defn- buffer-size [opts]156 (or (:buffer-size opts) 1024))158 (def default-streams-impl159 {:make-reader (fn [x opts] (make-reader (make-input-stream x opts) opts))160 :make-writer (fn [x opts] (make-writer (make-output-stream x opts) opts))161 :make-input-stream (fn [x opts]162 (throw (IllegalArgumentException.163 (str "Cannot open <" (pr-str x) "> as an InputStream."))))164 :make-output-stream (fn [x opts]165 (throw (IllegalArgumentException.166 (str "Cannot open <" (pr-str x) "> as an OutputStream."))))})168 (defn- inputstream->reader169 [^InputStream is opts]170 (make-reader (InputStreamReader. is (encoding opts)) opts))172 (defn- outputstream->writer173 [^OutputStream os opts]174 (make-writer (OutputStreamWriter. os (encoding opts)) opts))176 (extend BufferedInputStream177 IOFactory178 (assoc default-streams-impl179 :make-input-stream (fn [x opts] x)180 :make-reader inputstream->reader))182 (extend InputStream183 IOFactory184 (assoc default-streams-impl185 :make-input-stream (fn [x opts] (BufferedInputStream. x))186 :make-reader inputstream->reader))188 (extend Reader189 IOFactory190 (assoc default-streams-impl191 :make-reader (fn [x opts] (BufferedReader. x))))193 (extend BufferedReader194 IOFactory195 (assoc default-streams-impl196 :make-reader (fn [x opts] x)))198 (extend Writer199 IOFactory200 (assoc default-streams-impl201 :make-writer (fn [x opts] (BufferedWriter. x))))203 (extend BufferedWriter204 IOFactory205 (assoc default-streams-impl206 :make-writer (fn [x opts] x)))208 (extend OutputStream209 IOFactory210 (assoc default-streams-impl211 :make-output-stream (fn [x opts] (BufferedOutputStream. x))212 :make-writer outputstream->writer))214 (extend BufferedOutputStream215 IOFactory216 (assoc default-streams-impl217 :make-output-stream (fn [x opts] x)218 :make-writer outputstream->writer))220 (extend File221 IOFactory222 (assoc default-streams-impl223 :make-input-stream (fn [^File x opts] (make-input-stream (FileInputStream. x) opts))224 :make-output-stream (fn [^File x opts] (make-output-stream (FileOutputStream. x (append? opts)) opts))))226 (extend URL227 IOFactory228 (assoc default-streams-impl229 :make-input-stream (fn [^URL x opts]230 (make-input-stream231 (if (= "file" (.getProtocol x))232 (FileInputStream. (.getPath x))233 (.openStream x)) opts))234 :make-output-stream (fn [^URL x opts]235 (if (= "file" (.getProtocol x))236 (make-output-stream (File. (.getPath x)) opts)237 (throw (IllegalArgumentException. (str "Can not write to non-file URL <" x ">")))))))239 (extend URI240 IOFactory241 (assoc default-streams-impl242 :make-input-stream (fn [^URI x opts] (make-input-stream (.toURL x) opts))243 :make-output-stream (fn [^URI x opts] (make-output-stream (.toURL x) opts))))245 (extend String246 IOFactory247 (assoc default-streams-impl248 :make-input-stream (fn [^String x opts]249 (try250 (make-input-stream (URL. x) opts)251 (catch MalformedURLException e252 (make-input-stream (File. x) opts))))253 :make-output-stream (fn [^String x opts]254 (try255 (make-output-stream (URL. x) opts)256 (catch MalformedURLException err257 (make-output-stream (File. x) opts))))))259 (extend Socket260 IOFactory261 (assoc default-streams-impl262 :make-input-stream (fn [^Socket x opts] (make-input-stream (.getInputStream x) opts))263 :make-output-stream (fn [^Socket x opts] (make-output-stream (.getOutputStream x) opts))))265 (extend byte-array-type266 IOFactory267 (assoc default-streams-impl268 :make-input-stream (fn [x opts] (make-input-stream (ByteArrayInputStream. x) opts))))270 (extend char-array-type271 IOFactory272 (assoc default-streams-impl273 :make-reader (fn [x opts] (make-reader (CharArrayReader. x) opts))))275 (extend Object276 IOFactory277 default-streams-impl)279 (defmulti280 #^{:doc "Internal helper for copy"281 :private true282 :arglists '([input output opts])}283 do-copy284 (fn [input output opts] [(type input) (type output)]))286 (defmethod do-copy [InputStream OutputStream] [#^InputStream input #^OutputStream output opts]287 (let [buffer (make-array Byte/TYPE (buffer-size opts))]288 (loop []289 (let [size (.read input buffer)]290 (when (pos? size)291 (do (.write output buffer 0 size)292 (recur)))))))294 (defmethod do-copy [InputStream Writer] [#^InputStream input #^Writer output opts]295 (let [#^"[B" buffer (make-array Byte/TYPE (buffer-size opts))]296 (loop []297 (let [size (.read input buffer)]298 (when (pos? size)299 (let [chars (.toCharArray (String. buffer 0 size (encoding opts)))]300 (do (.write output chars)301 (recur))))))))303 (defmethod do-copy [InputStream File] [#^InputStream input #^File output opts]304 (with-open [out (FileOutputStream. output)]305 (do-copy input out opts)))307 (defmethod do-copy [Reader OutputStream] [#^Reader input #^OutputStream output opts]308 (let [#^"[C" buffer (make-array Character/TYPE (buffer-size opts))]309 (loop []310 (let [size (.read input buffer)]311 (when (pos? size)312 (let [bytes (.getBytes (String. buffer 0 size) (encoding opts))]313 (do (.write output bytes)314 (recur))))))))316 (defmethod do-copy [Reader Writer] [#^Reader input #^Writer output opts]317 (let [#^"[C" buffer (make-array Character/TYPE (buffer-size opts))]318 (loop []319 (let [size (.read input buffer)]320 (when (pos? size)321 (do (.write output buffer 0 size)322 (recur)))))))324 (defmethod do-copy [Reader File] [#^Reader input #^File output opts]325 (with-open [out (FileOutputStream. output)]326 (do-copy input out opts)))328 (defmethod do-copy [File OutputStream] [#^File input #^OutputStream output opts]329 (with-open [in (FileInputStream. input)]330 (do-copy in output opts)))332 (defmethod do-copy [File Writer] [#^File input #^Writer output opts]333 (with-open [in (FileInputStream. input)]334 (do-copy in output opts)))336 (defmethod do-copy [File File] [#^File input #^File output opts]337 (with-open [in (FileInputStream. input)338 out (FileOutputStream. output)]339 (do-copy in out opts)))341 (defmethod do-copy [String OutputStream] [#^String input #^OutputStream output opts]342 (do-copy (StringReader. input) output opts))344 (defmethod do-copy [String Writer] [#^String input #^Writer output opts]345 (do-copy (StringReader. input) output opts))347 (defmethod do-copy [String File] [#^String input #^File output opts]348 (do-copy (StringReader. input) output opts))350 (defmethod do-copy [char-array-type OutputStream] [input #^OutputStream output opts]351 (do-copy (CharArrayReader. input) output opts))353 (defmethod do-copy [char-array-type Writer] [input #^Writer output opts]354 (do-copy (CharArrayReader. input) output opts))356 (defmethod do-copy [char-array-type File] [input #^File output opts]357 (do-copy (CharArrayReader. input) output opts))359 (defmethod do-copy [byte-array-type OutputStream] [#^"[B" input #^OutputStream output opts]360 (do-copy (ByteArrayInputStream. input) output opts))362 (defmethod do-copy [byte-array-type Writer] [#^"[B" input #^Writer output opts]363 (do-copy (ByteArrayInputStream. input) output opts))365 (defmethod do-copy [byte-array-type File] [#^"[B" input #^Writer output opts]366 (do-copy (ByteArrayInputStream. input) output opts))368 (defn copy369 "Copies input to output. Returns nil or throws IOException.370 Input may be an InputStream, Reader, File, byte[], or String.371 Output may be an OutputStream, Writer, or File.373 Options are key/value pairs and may be one of375 :buffer-size buffer size to use, default is 1024.376 :encoding encoding to use if converting between377 byte and char streams.379 Does not close any streams except those it opens itself380 (on a File)."381 {:added "1.2"}382 [input output & opts]383 (do-copy input output (when opts (apply hash-map opts))))385 (defn ^String as-relative-path386 "Take an as-file-able thing and return a string if it is387 a relative path, else IllegalArgumentException."388 {:added "1.2"}389 [x]390 (let [^File f (as-file x)]391 (if (.isAbsolute f)392 (throw (IllegalArgumentException. (str f " is not a relative path")))393 (.getPath f))))395 (defn ^File file396 "Returns a java.io.File, passing each arg to as-file. Multiple-arg397 versions treat the first argument as parent and subsequent args as398 children relative to the parent."399 {:added "1.2"}400 ([arg]401 (as-file arg))402 ([parent child]403 (File. ^File (as-file parent) ^String (as-relative-path child)))404 ([parent child & more]405 (reduce file (file parent child) more)))407 (defn delete-file408 "Delete file f. Raise an exception if it fails unless silently is true."409 {:added "1.2"}410 [f & [silently]]411 (or (.delete (file f))412 silently413 (throw (java.io.IOException. (str "Couldn't delete " f)))))415 (defn make-parents416 "Given the same arg(s) as for file, creates all parent directories of417 the file they represent."418 {:added "1.2"}419 [f & more]420 (.mkdirs (.getParentFile ^File (apply file f more))))422 (defn ^URL resource423 "Returns the URL for a named resource. Use the context class loader424 if no loader is specified."425 {:added "1.2"}426 ([n] (resource n (.getContextClassLoader (Thread/currentThread))))427 ([n ^ClassLoader loader] (.getResource loader n)))