All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.util.io.FileBytes Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.util.io;


import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import com.hfg.exception.ProgrammingException;
import com.hfg.util.collection.CollectionUtil;

//------------------------------------------------------------------------------
/**
 Container for a file name plus file contents as bytes.
 Useful for holding temp files created in memory before producing a zip archive.
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class FileBytes extends OutputStream implements FileSource { private String mName; private Long mLength; private List mCompressedDataChunks; private byte[] mUncompressedDataChunk; private int mUncompressedDataChunkSize; private static int sDefaultChunkSize = 8192; //########################################################################### // CONSTRUCTORS //########################################################################### //-------------------------------------------------------------------------- public FileBytes(String inName) { mName = inName; } //-------------------------------------------------------------------------- public FileBytes(File inFile) throws IOException { mName = inFile.getName(); FileInputStream fileStream = null; try { fileStream = new FileInputStream(inFile); setData(StreamUtil.inputStreamToBytes(fileStream)); } finally { StreamUtil.close(fileStream); } } //########################################################################### // PUBLIC METHODS //########################################################################### //-------------------------------------------------------------------------- @Deprecated public String name() { return mName; } //-------------------------------------------------------------------------- @Override public String getName() { return mName; } //-------------------------------------------------------------------------- public long length() { return mLength != null ? mLength : 0; } //-------------------------------------------------------------------------- /** * This method directly sets the stored byte[] of content and bypasses any content compression. * @param inData the specified byte[] of file contents * @return this FileBytes object to enable method chaining. * @throws IOException */ public FileBytes setData(byte[] inData) throws IOException { clearData(); if (inData != null) { mUncompressedDataChunk = inData; mUncompressedDataChunkSize = mUncompressedDataChunk.length; mLength = (long) mUncompressedDataChunkSize; } return this; } //-------------------------------------------------------------------------- public FileBytes setData(InputStream inStream) throws IOException { clearData(); if (inStream != null) { mCompressedDataChunks = new ArrayList<>(50); BufferedInputStream bufferedStream = null; try { bufferedStream = new BufferedInputStream(inStream); byte[] readBuffer = new byte[4096]; int readSize = 0; while ((readSize = bufferedStream.read(readBuffer)) >= 0) { mCompressedDataChunks.add(GZIP.compress(readBuffer, 0, readSize)); mLength += readSize; } } finally { if (bufferedStream != null) { bufferedStream.close(); } } } return this; } //-------------------------------------------------------------------------- public void write(int inByte) throws IOException { appendData(inByte); } //-------------------------------------------------------------------------- public void write(byte[] inBytes) throws IOException { appendData(inBytes); } //-------------------------------------------------------------------------- public void write(byte[] inBytes, int inOffset, int inLength) throws IOException { appendData(inBytes, inOffset, inLength); } //-------------------------------------------------------------------------- public void appendData(int inByte) throws IOException { if (null == mUncompressedDataChunk) { mUncompressedDataChunk = new byte[sDefaultChunkSize]; mUncompressedDataChunkSize = 0; } mUncompressedDataChunk[mUncompressedDataChunkSize++] = (byte) inByte; if (mUncompressedDataChunkSize == mUncompressedDataChunk.length) { if (null == mCompressedDataChunks) { mCompressedDataChunks = new ArrayList<>(50); } mCompressedDataChunks.add(GZIP.compress(mUncompressedDataChunk, 0, mUncompressedDataChunkSize)); mUncompressedDataChunkSize = 0; } else { mUncompressedDataChunkSize++; } if (mLength != null) { mLength++; } else { mLength = 1L; } } //-------------------------------------------------------------------------- public FileBytes appendData(byte[] inBytes) throws IOException { return appendData(inBytes, 0, inBytes.length); } //-------------------------------------------------------------------------- public FileBytes appendData(byte[] inBytes, int inOffset, int inLength) throws IOException { if (null == mUncompressedDataChunk) { mUncompressedDataChunk = new byte[sDefaultChunkSize]; mUncompressedDataChunkSize = 0; } int totalBytesAdded = 0; while (totalBytesAdded < inLength) { int lengthRemainingToCopy = inLength - totalBytesAdded; int bytesCopied = Math.min(lengthRemainingToCopy, mUncompressedDataChunk.length - mUncompressedDataChunkSize); System.arraycopy(inBytes, inOffset, mUncompressedDataChunk, mUncompressedDataChunkSize, bytesCopied); if (mUncompressedDataChunkSize == mUncompressedDataChunk.length) { if (null == mCompressedDataChunks) { mCompressedDataChunks = new ArrayList<>(50); } mCompressedDataChunks.add(GZIP.compress(mUncompressedDataChunk, 0, mUncompressedDataChunkSize)); mUncompressedDataChunkSize = 0; } else { mUncompressedDataChunkSize += bytesCopied; } totalBytesAdded += bytesCopied; } if (mLength != null) { mLength += inBytes.length; } else { mLength = (long) inLength; } return this; } //-------------------------------------------------------------------------- public FileBytes appendData(FileBytes inFileBytes) throws IOException { if (inFileBytes.length() > 0) { if (null == mCompressedDataChunks) { mCompressedDataChunks = new ArrayList<>(50); } // Add whatever we have sitting uncompressed at the moment if (mUncompressedDataChunkSize > 0) { mCompressedDataChunks.add(GZIP.compress(mUncompressedDataChunk, 0, mUncompressedDataChunkSize)); mUncompressedDataChunkSize = 0; } // Add the new compressed chunks for (byte[] bytes : inFileBytes.mCompressedDataChunks) { mCompressedDataChunks.add(bytes); } // Add the new uncompressed chunk if (inFileBytes.mUncompressedDataChunk != null) { mUncompressedDataChunk = Arrays.copyOf(inFileBytes.mUncompressedDataChunk, sDefaultChunkSize); mUncompressedDataChunkSize = inFileBytes.mUncompressedDataChunkSize; } else { mUncompressedDataChunkSize = 0; } if (mLength != null) { mLength += inFileBytes.length(); } else { mLength = inFileBytes.length(); } } return this; } //-------------------------------------------------------------------------- public byte[] getBytes() { ByteArrayOutputStream stream; try { stream = new ByteArrayOutputStream(); StreamUtil.writeToStream(getDataStream(), stream); } catch (IOException e) { throw new ProgrammingException(e); } return stream.toByteArray(); } //-------------------------------------------------------------------------- public InputStream getInputStream() { return new DataStreamer(); } //-------------------------------------------------------------------------- @Deprecated public InputStream getDataStream() { return new DataStreamer(); } //-------------------------------------------------------------------------- public void writeData(OutputStream inStream) throws IOException { if (CollectionUtil.hasValues(mCompressedDataChunks)) { for (byte[] chunk : mCompressedDataChunks) { inStream.write(GZIP.uncompress(chunk)); } } if (mUncompressedDataChunkSize > 0) { inStream.write(mUncompressedDataChunk, 0, mUncompressedDataChunkSize); } inStream.flush(); } //-------------------------------------------------------------------------- public static void streamAsZipFile(OutputStream inWriteTarget, String inBaseZipFileName, Collection inFiles) throws IOException { ZipOutputStream zipStream = null; try { zipStream = new ZipOutputStream(inWriteTarget); for (FileBytes file : inFiles) { ZipEntry zipEntry = new ZipEntry(inBaseZipFileName + "/" + file.getName()); zipStream.putNextEntry(zipEntry); file.writeData(zipStream); zipStream.closeEntry(); } } finally { if (zipStream != null) { zipStream.finish(); } } } //########################################################################### // PRIVATE METHODS //########################################################################### //-------------------------------------------------------------------------- private void clearData() { mCompressedDataChunks = null; mLength = 0L; } //########################################################################### // INNER CLASS //########################################################################### private class DataStreamer extends InputStream { private byte[] mCurrentCompressedChunk; private int mCurrentCompressedChunkIndex; private int mUncompressedChunkIndex; private int mByteIndex; private boolean mDone = false; int count = 0; //----------------------------------------------------------------------- public DataStreamer() { mCurrentCompressedChunkIndex = 0; } //----------------------------------------------------------------------- public int read() { return (mDone ? -1 : getNextByte()); } //----------------------------------------------------------------------- @Override public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1 && mDone) { return -1; } b[off] = (byte) c; int i = 1; for (; i < len; i++) { c = read(); if (c == -1 && mDone) { break; } b[off + i] = (byte) c; } return i; } //----------------------------------------------------------------------- private byte getNextByte() { byte nextByte = -1; if (null == mCurrentCompressedChunk && mCompressedDataChunks != null) { mCurrentCompressedChunk = GZIP.uncompress(mCompressedDataChunks.get(mCurrentCompressedChunkIndex)); mByteIndex = 0; } if (null == mCurrentCompressedChunk) { // Done with compressed chunks. Read from the uncompressed chunk. nextByte = mUncompressedDataChunk[mUncompressedChunkIndex++]; if (mUncompressedChunkIndex >= mUncompressedDataChunkSize) { // This was the last chunk. mDone = true; } } else { nextByte = mCurrentCompressedChunk[mByteIndex++]; if (mByteIndex >= mCurrentCompressedChunk.length) { // This is the last byte in this chunk. mCurrentCompressedChunk = null; mCurrentCompressedChunkIndex++; if (mCurrentCompressedChunkIndex < 0 || mCurrentCompressedChunkIndex == mCompressedDataChunks.size()) { if (mUncompressedDataChunkSize > 0) { mUncompressedChunkIndex = 0; } else { // This was the last chunk. mDone = true; } } } } return nextByte; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy