001/*
002 * Copyright 2002-2020 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.util;
018
019import java.io.ByteArrayInputStream;
020import java.io.ByteArrayOutputStream;
021import java.io.Closeable;
022import java.io.File;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.OutputStream;
026import java.io.Reader;
027import java.io.StringWriter;
028import java.io.Writer;
029import java.nio.file.Files;
030
031import org.springframework.lang.Nullable;
032
033/**
034 * Simple utility methods for file and stream copying. All copy methods use a block size
035 * of 4096 bytes, and close all affected streams when done. A variation of the copy
036 * methods from this class that leave streams open can be found in {@link StreamUtils}.
037 *
038 * <p>Mainly for use within the framework, but also useful for application code.
039 *
040 * @author Juergen Hoeller
041 * @author Hyunjin Choi
042 * @since 06.10.2003
043 * @see StreamUtils
044 * @see FileSystemUtils
045 */
046public abstract class FileCopyUtils {
047
048        /**
049         * The default buffer size used when copying bytes.
050         */
051        public static final int BUFFER_SIZE = StreamUtils.BUFFER_SIZE;
052
053
054        //---------------------------------------------------------------------
055        // Copy methods for java.io.File
056        //---------------------------------------------------------------------
057
058        /**
059         * Copy the contents of the given input File to the given output File.
060         * @param in the file to copy from
061         * @param out the file to copy to
062         * @return the number of bytes copied
063         * @throws IOException in case of I/O errors
064         */
065        public static int copy(File in, File out) throws IOException {
066                Assert.notNull(in, "No input File specified");
067                Assert.notNull(out, "No output File specified");
068                return copy(Files.newInputStream(in.toPath()), Files.newOutputStream(out.toPath()));
069        }
070
071        /**
072         * Copy the contents of the given byte array to the given output File.
073         * @param in the byte array to copy from
074         * @param out the file to copy to
075         * @throws IOException in case of I/O errors
076         */
077        public static void copy(byte[] in, File out) throws IOException {
078                Assert.notNull(in, "No input byte array specified");
079                Assert.notNull(out, "No output File specified");
080                copy(new ByteArrayInputStream(in), Files.newOutputStream(out.toPath()));
081        }
082
083        /**
084         * Copy the contents of the given input File into a new byte array.
085         * @param in the file to copy from
086         * @return the new byte array that has been copied to
087         * @throws IOException in case of I/O errors
088         */
089        public static byte[] copyToByteArray(File in) throws IOException {
090                Assert.notNull(in, "No input File specified");
091                return copyToByteArray(Files.newInputStream(in.toPath()));
092        }
093
094
095        //---------------------------------------------------------------------
096        // Copy methods for java.io.InputStream / java.io.OutputStream
097        //---------------------------------------------------------------------
098
099        /**
100         * Copy the contents of the given InputStream to the given OutputStream.
101         * Closes both streams when done.
102         * @param in the stream to copy from
103         * @param out the stream to copy to
104         * @return the number of bytes copied
105         * @throws IOException in case of I/O errors
106         */
107        public static int copy(InputStream in, OutputStream out) throws IOException {
108                Assert.notNull(in, "No InputStream specified");
109                Assert.notNull(out, "No OutputStream specified");
110
111                try {
112                        return StreamUtils.copy(in, out);
113                }
114                finally {
115                        close(in);
116                        close(out);
117                }
118        }
119
120        /**
121         * Copy the contents of the given byte array to the given OutputStream.
122         * Closes the stream when done.
123         * @param in the byte array to copy from
124         * @param out the OutputStream to copy to
125         * @throws IOException in case of I/O errors
126         */
127        public static void copy(byte[] in, OutputStream out) throws IOException {
128                Assert.notNull(in, "No input byte array specified");
129                Assert.notNull(out, "No OutputStream specified");
130
131                try {
132                        out.write(in);
133                }
134                finally {
135                        close(out);
136                }
137        }
138
139        /**
140         * Copy the contents of the given InputStream into a new byte array.
141         * Closes the stream when done.
142         * @param in the stream to copy from (may be {@code null} or empty)
143         * @return the new byte array that has been copied to (possibly empty)
144         * @throws IOException in case of I/O errors
145         */
146        public static byte[] copyToByteArray(@Nullable InputStream in) throws IOException {
147                if (in == null) {
148                        return new byte[0];
149                }
150
151                ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
152                copy(in, out);
153                return out.toByteArray();
154        }
155
156
157        //---------------------------------------------------------------------
158        // Copy methods for java.io.Reader / java.io.Writer
159        //---------------------------------------------------------------------
160
161        /**
162         * Copy the contents of the given Reader to the given Writer.
163         * Closes both when done.
164         * @param in the Reader to copy from
165         * @param out the Writer to copy to
166         * @return the number of characters copied
167         * @throws IOException in case of I/O errors
168         */
169        public static int copy(Reader in, Writer out) throws IOException {
170                Assert.notNull(in, "No Reader specified");
171                Assert.notNull(out, "No Writer specified");
172
173                try {
174                        int charCount = 0;
175                        char[] buffer = new char[BUFFER_SIZE];
176                        int charsRead;
177                        while ((charsRead = in.read(buffer)) != -1) {
178                                out.write(buffer, 0, charsRead);
179                                charCount += charsRead;
180                        }
181                        out.flush();
182                        return charCount;
183                }
184                finally {
185                        close(in);
186                        close(out);
187                }
188        }
189
190        /**
191         * Copy the contents of the given String to the given Writer.
192         * Closes the writer when done.
193         * @param in the String to copy from
194         * @param out the Writer to copy to
195         * @throws IOException in case of I/O errors
196         */
197        public static void copy(String in, Writer out) throws IOException {
198                Assert.notNull(in, "No input String specified");
199                Assert.notNull(out, "No Writer specified");
200
201                try {
202                        out.write(in);
203                }
204                finally {
205                        close(out);
206                }
207        }
208
209        /**
210         * Copy the contents of the given Reader into a String.
211         * Closes the reader when done.
212         * @param in the reader to copy from (may be {@code null} or empty)
213         * @return the String that has been copied to (possibly empty)
214         * @throws IOException in case of I/O errors
215         */
216        public static String copyToString(@Nullable Reader in) throws IOException {
217                if (in == null) {
218                        return "";
219                }
220
221                StringWriter out = new StringWriter(BUFFER_SIZE);
222                copy(in, out);
223                return out.toString();
224        }
225
226        /**
227         * Attempt to close the supplied {@link Closeable}, silently swallowing any
228         * exceptions.
229         * @param closeable the {@code Closeable} to close
230         */
231        private static void close(Closeable closeable) {
232                try {
233                        closeable.close();
234                }
235                catch (IOException ex) {
236                        // ignore
237                }
238        }
239
240}