/** * Closes the underlying OutputStream. * * @throws IOException on error */ @Override public void close() throws IOException { try { if (!finished) { finish(); } } finally { if (!closed) { out.close(); closed = true; } } }
@Override public void flush() throws IOException { out.flush(); }
@Override public void close() throws IOException { if (closed.compareAndSet(false, true)) { try { flushBlock(); } finally { out.close(); } } }
/** * Potentially pads and then writes the current block to the underlying stream. * @throws IOException if writing fails */ public void flushBlock() throws IOException { if (buffer.position() != 0) { padBlock(); writeBlock(); } }
@Override public void write(int b) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); } buffer.put((byte) b); maybeFlush(); }
@Override public int write(ByteBuffer src) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); src.limit(src.position() + n); buffer.put(src); writeBlock(); srcLeft -= n;
/** * Write an archive record to the archive. * * @param record The record data to write to the archive. * @throws IOException on error */ private void writeRecord(final byte[] record) throws IOException { if (record.length != RECORD_SIZE) { throw new IOException("record to write has length '" + record.length + "' which is not the record size of '" + RECORD_SIZE + "'"); } out.write(record); recordsWritten++; }
private void maybeFlush() throws IOException { if (!buffer.hasRemaining()) { writeBlock(); } }
/** * Constructor for TarArchiveOutputStream. * * @param os the output stream to use * @param blockSize the block size to use. Must be a multiple of 512 bytes. * @param encoding name of the encoding to use for file names * @since 1.4 */ public TarArchiveOutputStream(final OutputStream os, final int blockSize, final String encoding) { int realBlockSize; if (BLOCK_SIZE_UNSPECIFIED == blockSize) { realBlockSize = RECORD_SIZE; } else { realBlockSize = blockSize; } if (realBlockSize <=0 || realBlockSize % RECORD_SIZE != 0) { throw new IllegalArgumentException("Block size must be a multiple of 512 bytes. Attempt to use set size of " + blockSize); } out = new FixedLengthBlockOutputStream(countingOut = new CountingOutputStream(os), RECORD_SIZE); this.encoding = encoding; this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); this.recordBuf = new byte[RECORD_SIZE]; this.recordsPerBlock = realBlockSize / RECORD_SIZE; }
@Override public void write(byte[] b, final int offset, final int length) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); } int off = offset; int len = length; while (len > 0) { int n = Math.min(len, buffer.remaining()); buffer.put(b, off, n); maybeFlush(); len -= n; off += n; } }
/** * Potentially pads and then writes the current block to the underlying stream. * @throws IOException if writing fails */ public void flushBlock() throws IOException { if (buffer.position() != 0) { padBlock(); writeBlock(); } }
@Override public int write(ByteBuffer src) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); src.limit(src.position() + n); buffer.put(src); writeBlock(); srcLeft -= n;
/** * Writes bytes to the current tar archive entry. This method is aware of the current entry and * will throw an exception if you attempt to write bytes past the length specified for the * current entry. * * @param wBuf The buffer to write to the archive. * @param wOffset The offset in the buffer from which to get bytes. * @param numToWrite The number of bytes to write. * @throws IOException on error */ @Override public void write(final byte[] wBuf, int wOffset, int numToWrite) throws IOException { if (!haveUnclosedEntry) { throw new IllegalStateException("No current tar entry"); } if (currBytes + numToWrite > currSize) { throw new IOException("request to write '" + numToWrite + "' bytes exceeds size in header of '" + currSize + "' bytes for entry '" + currName + "'"); } out.write(wBuf, wOffset, numToWrite); currBytes += numToWrite; }
private void maybeFlush() throws IOException { if (!buffer.hasRemaining()) { writeBlock(); } }
/** * Constructor for TarArchiveOutputStream. * * @param os the output stream to use * @param blockSize the block size to use. Must be a multiple of 512 bytes. * @param encoding name of the encoding to use for file names * @since 1.4 */ public TarArchiveOutputStream(final OutputStream os, final int blockSize, final String encoding) { int realBlockSize; if (BLOCK_SIZE_UNSPECIFIED == blockSize) { realBlockSize = RECORD_SIZE; } else { realBlockSize = blockSize; } if (realBlockSize <=0 || realBlockSize % RECORD_SIZE != 0) { throw new IllegalArgumentException("Block size must be a multiple of 512 bytes. Attempt to use set size of " + blockSize); } out = new FixedLengthBlockOutputStream(countingOut = new CountingOutputStream(os), RECORD_SIZE); this.encoding = encoding; this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); this.recordBuf = new byte[RECORD_SIZE]; this.recordsPerBlock = realBlockSize / RECORD_SIZE; }
@Override public void write(int b) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); } buffer.put((byte) b); maybeFlush(); }
/** * Close an entry. This method MUST be called for all file entries that contain data. The reason * is that we must buffer data written to the stream in order to satisfy the buffer's record * based writes. Thus, there may be data fragments still being assembled that must be written to * the output stream before this entry is closed and the next entry written. * * @throws IOException on error */ @Override public void closeArchiveEntry() throws IOException { if (finished) { throw new IOException("Stream has already been finished"); } if (!haveUnclosedEntry) { throw new IOException("No current entry to close"); } out.flushBlock(); if (currBytes < currSize) { throw new IOException("entry '" + currName + "' closed at '" + currBytes + "' before the '" + currSize + "' bytes specified in the header were written"); } recordsWritten += (currSize / RECORD_SIZE); if (0 != currSize % RECORD_SIZE) { recordsWritten++; } haveUnclosedEntry = false; }
/** * Ends the TAR archive without closing the underlying OutputStream. * * An archive consists of a series of file entries terminated by an * end-of-archive entry, which consists of two 512 blocks of zero bytes. * POSIX.1 requires two EOF records, like some other implementations. * * @throws IOException on error */ @Override public void finish() throws IOException { if (finished) { throw new IOException("This archive has already been finished"); } if (haveUnclosedEntry) { throw new IOException("This archive contains unclosed entries."); } writeEOFRecord(); writeEOFRecord(); padAsNeeded(); out.flush(); finished = true; }
/** * Write an archive record to the archive. * * @param record The record data to write to the archive. * @throws IOException on error */ private void writeRecord(final byte[] record) throws IOException { if (record.length != RECORD_SIZE) { throw new IOException("record to write has length '" + record.length + "' which is not the record size of '" + RECORD_SIZE + "'"); } out.write(record); recordsWritten++; }
/** * Closes the underlying OutputStream. * * @throws IOException on error */ @Override public void close() throws IOException { if (!finished) { finish(); } if (!closed) { out.close(); closed = true; } }