compoundfile.java
来自「jexcelapi_2_4, JXL的API, JXL是JAVA读取EXCEL的」· Java 代码 · 共 553 行 · 第 1/2 页
JAVA
553 行
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* 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
***************************************************************************/
package jxl.write.biff;
import java.io.OutputStream;
import java.io.IOException;
import common.Assert;
import jxl.biff.BaseCompoundFile;
import jxl.biff.IntegerHelper;
/**
* Writes out a compound file
*
* Header block is -1
* Excel data is e..n (where is the head extension blocks, normally 0 and
* n is at least 8)
* Summary information (8 blocks)
* Document summary (8 blocks)
* BBD is block p..q (where p=e+n+16 and q-p+1 is the number of BBD blocks)
* Property storage block is q+b...r (normally 1 block) (where b is the number
* of BBD blocks)
*/
final class CompoundFile extends BaseCompoundFile
{
/**
* The stream to which the jumbled up data is written to
*/
private OutputStream out;
/**
* The organized biff records which form the actual excel data
*/
private byte[] excelData;
/**
* The size of the array
*/
private int size;
/**
* The size the excel data should be in order to comply with the
* general compound file format
*/
private int requiredSize;
/**
* The number of blocks it takes to store the big block depot
*/
private int numBigBlockDepotBlocks;
/**
* The number of extension blocks required for the header to describe
* the BBD
*/
private int numExtensionBlocks;
/**
* The extension block for the header
*/
private int extensionBlock;
/**
* The number of blocks it takes to store the excel data
*/
private int excelDataBlocks;
/**
* The start block of the root entry
*/
private int rootStartBlock;
/**
* The start block of the excel data
*/
private int excelDataStartBlock;
/**
* The start block of the big block depot
*/
private int bbdStartBlock;
// The following member variables are used across methods when
// writing out the big block depot
/**
* The current position within the bbd. Used when writing out the
* BBD
*/
private int bbdPos;
/**
* The current bbd block
*/
private byte[] bigBlockDepot;
/**
* Constructor
*
* @param l the length of the data
* @param os the output stream to write to
* @param data the excel data
*/
public CompoundFile(byte[] data, int l, OutputStream os)
{
super();
size = l;
excelData = data;
int blocks = (l / BIG_BLOCK_SIZE) + 1;
// First pad the data out so that it fits nicely into a whole number
// of blocks
if (l < SMALL_BLOCK_THRESHOLD)
{
requiredSize = SMALL_BLOCK_THRESHOLD;
}
else
{
requiredSize = blocks * BIG_BLOCK_SIZE;
}
out = os;
// Do the calculations
excelDataBlocks = requiredSize/BIG_BLOCK_SIZE;
int blockChainLength = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
int totalBlocks = excelDataBlocks +
8 + // summary block
8 + // document information
1 + // root entry
1; // the BBD block
// Calculate the number of BBD blocks needed to hold this info
numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks /
(double) (BIG_BLOCK_SIZE/4));
// Does this affect the total?
totalBlocks += numBigBlockDepotBlocks;
// And recalculate
numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks /
(double) (BIG_BLOCK_SIZE/4));
// See if the excel bbd chain can fit into the header block.
// Remember to allow for the end of chain indicator
if (numBigBlockDepotBlocks > blockChainLength - 1 )
{
// Sod it - we need an extension block. We have to go through
// the whole tiresome calculation again
extensionBlock = 0;
// Compute the number of extension blocks
int bbdBlocksLeft = numBigBlockDepotBlocks - blockChainLength + 1;
numExtensionBlocks = (int) Math.ceil((double) bbdBlocksLeft /
(double) (BIG_BLOCK_SIZE/4 - 1));
// Modify the total number of blocks required and recalculate the
// the number of bbd blocks
totalBlocks += numExtensionBlocks;
numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks /
(double) (BIG_BLOCK_SIZE/4));
}
else
{
extensionBlock = -2;
numExtensionBlocks = 0;
}
// Set the excel data start block to be after the header (and
// its extensions)
excelDataStartBlock = numExtensionBlocks;
// Set the bbd start block to be after all the excel data
bbdStartBlock = excelDataStartBlock + excelDataBlocks + 16;
// Set the root start block to be after all the big block depot blocks
rootStartBlock = excelDataStartBlock + excelDataBlocks +
16 + numBigBlockDepotBlocks;
}
/**
* Writes out the excel file in OLE compound file format
*
* @exception IOException
*/
public void write() throws IOException
{
writeHeader();
writeExcelData();
writeBigBlockDepot();
writePropertySets();
// Don't flush or close the stream - this is handled by the enclosing File
// object
}
/**
* Writes out the excel data, padding it out with empty bytes as
* necessary
*
* @exception IOException
*/
private void writeExcelData() throws IOException
{
out.write(excelData, 0, size);
byte[] padding = new byte[requiredSize - size];
out.write(padding);
padding = new byte[SMALL_BLOCK_THRESHOLD];
// Write out the summary information
out.write(padding);
// Write out the document summary
out.write(padding);
}
/**
* Writes the compound file header
*
* @exception IOException
*/
private void writeHeader() throws IOException
{
// Build up the header array
byte[] headerBlock = new byte[BIG_BLOCK_SIZE];
byte[] extensionBlockData = new byte[BIG_BLOCK_SIZE * numExtensionBlocks];
// Copy in the identifier
System.arraycopy(IDENTIFIER, 0, headerBlock, 0, IDENTIFIER.length);
// Copy in some magic values - no idea what they mean
headerBlock[0x18] = 0x3e;
headerBlock[0x1a] = 0x3;
headerBlock[0x1c] = (byte) 0xfe;
headerBlock[0x1d] = (byte) 0xff;
headerBlock[0x1e] = 0x9;
headerBlock[0x20] = 0x6;
headerBlock[0x39] = 0x10;
// Set the number of BBD blocks
IntegerHelper.getFourBytes(numBigBlockDepotBlocks,
headerBlock,
NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
// Set the small block depot block to -2 ie. there is no
// small block depot
IntegerHelper.getFourBytes(-2,
headerBlock,
SMALL_BLOCK_DEPOT_BLOCK_POS);
// Set the extension block
IntegerHelper.getFourBytes(extensionBlock,
headerBlock,
EXTENSION_BLOCK_POS);
// Set the number of extension blocks to be the number of BBD blocks - 1
IntegerHelper.getFourBytes(numExtensionBlocks,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?