/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.util; import java.io.File; import java.io.IOException; import java.io.OutputStream; import org.apache.tools.ant.util.FileUtils; /** * Class that delays opening the output file until the first bytes * shall be written or the method {@link #open open} has been invoked * explicitly. * * @since Ant 1.6 */ public class LazyFileOutputStream extends OutputStream { private OutputStream fos; private File file; private boolean append; private boolean alwaysCreate; private boolean opened = false; private boolean closed = false; /** * Creates a stream that will eventually write to the file with * the given name and replace it. * @param name the filename. */ public LazyFileOutputStream(String name) { this(name, false); } /** * Creates a stream that will eventually write to the file with * the given name and optionally append to instead of replacing * it. * @param name the filename. * @param append if true append rather than replace. */ public LazyFileOutputStream(String name, boolean append) { this(new File(name), append); } /** * Creates a stream that will eventually write to the file with * the given name and replace it. * @param f the file to create. */ public LazyFileOutputStream(File f) { this(f, false); } /** * Creates a stream that will eventually write to the file with * the given name and optionally append to instead of replacing * it. * @param file the file to create. * @param append if true append rather than replace. */ public LazyFileOutputStream(File file, boolean append) { this(file, append, false); } /** * Creates a stream that will eventually write to the file with * the given name, optionally append to instead of replacing * it, and optionally always create a file (even if zero length). * @param file the file to create. * @param append if true append rather than replace. * @param alwaysCreate if true create the file even if nothing to write. */ public LazyFileOutputStream(File file, boolean append, boolean alwaysCreate) { this.file = file; this.append = append; this.alwaysCreate = alwaysCreate; } /** * Explicitly open the file for writing. * * <p>Returns silently if the file has already been opened.</p> * @throws IOException if there is an error. */ public void open() throws IOException { ensureOpened(); } /** * Close the file. * @throws IOException if there is an error. */ @Override public synchronized void close() throws IOException { if (alwaysCreate && !closed) { ensureOpened(); } if (opened) { fos.close(); } closed = true; } /** * Delegates to the three-arg version. * @param b the bytearray to write. * @throws IOException if there is a problem. */ @Override public void write(byte[] b) throws IOException { write(b, 0, b.length); } /** * Write part of a byte array. * @param b the byte array. * @param offset write from this index. * @param len the number of bytes to write. * @throws IOException if there is a problem. */ @Override public synchronized void write(byte[] b, int offset, int len) throws IOException { ensureOpened(); fos.write(b, offset, len); } /** * Write a byte. * @param b the byte to write. * @throws IOException if there is a problem. */ @Override public synchronized void write(int b) throws IOException { ensureOpened(); fos.write(b); } private synchronized void ensureOpened() throws IOException { if (closed) { throw new IOException(file + " has already been closed."); } if (!opened) { fos = FileUtils.newOutputStream(file.toPath(), append); opened = true; } } }