📄 concat.java
字号:
/* * 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.taskdefs;import java.io.File;import java.io.Reader;import java.io.Writer;import java.io.FileReader;import java.io.InputStream;import java.io.IOException;import java.io.OutputStream;import java.io.StringReader;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStreamReader;import java.util.Arrays;import java.util.Collections;import java.util.Iterator;import java.util.Vector;import org.apache.tools.ant.Task;import org.apache.tools.ant.Project;import org.apache.tools.ant.BuildException;import org.apache.tools.ant.ProjectComponent;import org.apache.tools.ant.filters.util.ChainReaderHelper;import org.apache.tools.ant.types.Path;import org.apache.tools.ant.types.FileSet;import org.apache.tools.ant.types.FileList;import org.apache.tools.ant.types.FilterChain;import org.apache.tools.ant.types.Resource;import org.apache.tools.ant.types.ResourceCollection;import org.apache.tools.ant.types.resources.Restrict;import org.apache.tools.ant.types.resources.Resources;import org.apache.tools.ant.types.resources.FileResource;import org.apache.tools.ant.types.resources.StringResource;import org.apache.tools.ant.types.resources.selectors.Not;import org.apache.tools.ant.types.resources.selectors.Exists;import org.apache.tools.ant.types.resources.selectors.ResourceSelector;import org.apache.tools.ant.util.ConcatResourceInputStream;import org.apache.tools.ant.util.FileUtils;import org.apache.tools.ant.util.ReaderInputStream;import org.apache.tools.ant.util.StringUtils;/** * This class contains the 'concat' task, used to concatenate a series * of files into a single stream. The destination of this stream may * be the system console, or a file. The following is a sample * invocation: * * <pre> * <concat destfile="${build.dir}/index.xml" * append="false"> * * <fileset dir="${xml.root.dir}" * includes="*.xml" /> * * </concat> * </pre> * */public class Concat extends Task implements ResourceCollection { // The size of buffers to be used private static final int BUFFER_SIZE = 8192; private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); private static final ResourceSelector EXISTS = new Exists(); private static final ResourceSelector NOT_EXISTS = new Not(EXISTS); /** * sub element points to a file or contains text */ public static class TextElement extends ProjectComponent { private String value = ""; private boolean trimLeading = false; private boolean trim = false; private boolean filtering = true; private String encoding = null; /** * whether to filter the text in this element * or not. * * @param filtering true if the text should be filtered. * the default value is true. */ public void setFiltering(boolean filtering) { this.filtering = filtering; } /** return the filtering attribute */ private boolean getFiltering() { return filtering; } /** * The encoding of the text element * * @param encoding the name of the charset used to encode */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * set the text using a file * @param file the file to use * @throws BuildException if the file does not exist, or cannot be * read */ public void setFile(File file) throws BuildException { // non-existing files are not allowed if (!file.exists()) { throw new BuildException("File " + file + " does not exist."); } BufferedReader reader = null; try { if (this.encoding == null) { reader = new BufferedReader(new FileReader(file)); } else { reader = new BufferedReader( new InputStreamReader(new FileInputStream(file), this.encoding)); } value = FileUtils.safeReadFully(reader); } catch (IOException ex) { throw new BuildException(ex); } finally { FileUtils.close(reader); } } /** * set the text using inline * @param value the text to place inline */ public void addText(String value) { this.value += getProject().replaceProperties(value); } /** * s:^\s*:: on each line of input * @param strip if true do the trim */ public void setTrimLeading(boolean strip) { this.trimLeading = strip; } /** * whether to call text.trim() * @param trim if true trim the text */ public void setTrim(boolean trim) { this.trim = trim; } /** * @return the text, after possible trimming */ public String getValue() { if (value == null) { value = ""; } if (value.trim().length() == 0) { value = ""; } if (trimLeading) { char[] current = value.toCharArray(); StringBuffer b = new StringBuffer(current.length); boolean startOfLine = true; int pos = 0; while (pos < current.length) { char ch = current[pos++]; if (startOfLine) { if (ch == ' ' || ch == '\t') { continue; } startOfLine = false; } b.append(ch); if (ch == '\n' || ch == '\r') { startOfLine = true; } } value = b.toString(); } if (trim) { value = value.trim(); } return value; } } private interface ReaderFactory { Reader getReader(Object o) throws IOException; } /** * This class reads from each of the source files in turn. * The concatentated result can then be filtered as * a single stream. */ private final class MultiReader extends Reader { private Reader reader = null; private int lastPos = 0; private char[] lastChars = new char[eolString.length()]; private boolean needAddSeparator = false; private Iterator readerSources; private ReaderFactory factory; private MultiReader(Iterator readerSources, ReaderFactory factory) { this.readerSources = readerSources; this.factory = factory; } private Reader getReader() throws IOException { if (reader == null && readerSources.hasNext()) { reader = factory.getReader(readerSources.next()); Arrays.fill(lastChars, (char) 0); } return reader; } private void nextReader() throws IOException { close(); reader = null; } /** * Read a character from the current reader object. Advance * to the next if the reader is finished. * @return the character read, -1 for EOF on the last reader. * @exception IOException - possibly thrown by the read for a reader * object. */ public int read() throws IOException { if (needAddSeparator) { int ret = eolString.charAt(lastPos++); if (lastPos >= eolString.length()) { lastPos = 0; needAddSeparator = false; } return ret; } while (getReader() != null) { int ch = getReader().read(); if (ch == -1) { nextReader(); if (isFixLastLine() && isMissingEndOfLine()) { needAddSeparator = true; lastPos = 0; } } else { addLastChar((char) ch); return ch; } } return -1; } /** * Read into the buffer <code>cbuf</code>. * @param cbuf The array to be read into. * @param off The offset. * @param len The length to read. * @exception IOException - possibly thrown by the reads to the * reader objects. */ public int read(char[] cbuf, int off, int len) throws IOException { int amountRead = 0; while (getReader() != null || needAddSeparator) { if (needAddSeparator) { cbuf[off] = eolString.charAt(lastPos++); if (lastPos >= eolString.length()) { lastPos = 0; needAddSeparator = false; } len--; off++; amountRead++; if (len == 0) { return amountRead; } continue; } int nRead = getReader().read(cbuf, off, len); if (nRead == -1 || nRead == 0) { nextReader(); if (isFixLastLine() && isMissingEndOfLine()) { needAddSeparator = true; lastPos = 0; } } else { if (isFixLastLine()) { for (int i = nRead; i > (nRead - lastChars.length); --i) { if (i <= 0) { break; } addLastChar(cbuf[off + i - 1]); } } len -= nRead; off += nRead; amountRead += nRead; if (len == 0) { return amountRead; } } } if (amountRead == 0) { return -1; } else { return amountRead; } } /** * Close the current reader */ public void close() throws IOException { if (reader != null) { reader.close(); } } /** * if checking for end of line at end of file * add a character to the lastchars buffer */ private void addLastChar(char ch) { for (int i = lastChars.length - 2; i >= 0; --i) { lastChars[i] = lastChars[i + 1]; } lastChars[lastChars.length - 1] = ch; } /** * return true if the lastchars buffer does * not contain the lineseparator */ private boolean isMissingEndOfLine() { for (int i = 0; i < lastChars.length; ++i) { if (lastChars[i] != eolString.charAt(i)) { return true; } } return false; } private boolean isFixLastLine() { return fixLastLine && textBuffer == null; } } private final class ConcatResource extends Resource { private ResourceCollection c; private ConcatResource(ResourceCollection c) { this.c = c; } public InputStream getInputStream() throws IOException { if (binary) { ConcatResourceInputStream result = new ConcatResourceInputStream(c); result.setManagingComponent(this); return result; } Reader resourceReader = getFilteredReader( new MultiReader(c.iterator(), resourceReaderFactory)); Reader rdr; if (header == null && footer == null) { rdr = resourceReader; } else { int readerCount = 1; if (header != null) { readerCount++; } if (footer != null) { readerCount++; } Reader[] readers = new Reader[readerCount]; int pos = 0; if (header != null) { readers[pos] = new StringReader(header.getValue()); if (header.getFiltering()) { readers[pos] = getFilteredReader(readers[pos]); } pos++; } readers[pos++] = resourceReader; if (footer != null) { readers[pos] = new StringReader(footer.getValue()); if (footer.getFiltering()) { readers[pos] = getFilteredReader(readers[pos]); } } rdr = new MultiReader(Arrays.asList(readers).iterator(), identityReaderFactory); } return outputEncoding == null ? new ReaderInputStream(rdr) : new ReaderInputStream(rdr, outputEncoding); } public String getName() { return "concat (" + String.valueOf(c) + ")"; } } // Attributes. /** * The destination of the stream. If <code>null</code>, the system * console is used. */ private File destinationFile; /** * Whether or not the stream should be appended if the destination file * exists. * Defaults to <code>false</code>. */ private boolean append; /** * Stores the input file encoding. */ private String encoding; /** Stores the output file encoding. */ private String outputEncoding; /** Stores the binary attribute */ private boolean binary; // Child elements. /** * This buffer stores the text within the 'concat' element. */ private StringBuffer textBuffer; /** * Stores a collection of file sets and/or file lists, used to * select multiple files for concatenation. */ private ResourceCollection rc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -