First of all, Please Pardon me for Poor Coding!
Requirement:
1. Create xls/xlsx Report in Memory from Database ResultSet (ie. Plain Text File should not be written to Disk).
2.Create ZIP on Disk From the xlsx file in Memory.
Environment:
WinXP SP2, JDK1.6_06, Zip4j1.3.1, poi3.8
I am using Apache's POI and Zip4j and am following Mr.Shrikant's Example published at "http://www.lingala.net/zip4j/forum/index.php?topic=257.0"
Observations:
1. This program Writes 27,842 bytes xlsx file to disk for sample data.
2. The same Workbook Creates ByteArrayOutputStream,baoStream of size is 49022bytes
3. After Encryption and Zipping It Creates File of Size 43,084 bytes.
4. While Extracting Zip file,
a) WinZip, throws Error "UnExpected End of File"
b) Winrar, throws "CRC Error"
Please correct me, wherever I am wrong and improve, wherever I am poor!
Thanks in Advance!
package zipconversion;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import net.lingala.zip4j.io.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ZipCreationInMemory {
ZipOutputStream zos = null;
XSSFWorkbook workbook = null;
ByteArrayOutputStream baoStream = null;
String path = null;
String xlsxfileExtn = null;
String zipfileExtn = null;
String onlyFileName = null;
String xlsxFileName = null;
String zipFileName = null;
String xlsxFilePath = null;
String zipFilePath = null;
public static int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
public void createXlsxFile() {
try {
SimpleDateFormat timeFormat = new SimpleDateFormat("hh_mm_ss");
path = "D:\\abcd\\";
xlsxfileExtn = ".xlsx";
zipfileExtn = ".zip";
onlyFileName = "ReportData_".concat(timeFormat.format(new Date()));
xlsxFileName = onlyFileName + xlsxfileExtn;
zipFileName = onlyFileName + zipfileExtn;
xlsxFilePath = path + xlsxFileName;
zipFilePath = path + zipFileName;
FileOutputStream out = new FileOutputStream(new File(xlsxFilePath));
workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Report");
XSSFRow rowHead = sheet.createRow((short) 0);
XSSFCellStyle headStyle = workbook.createCellStyle();
XSSFFont headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setColor(new XSSFColor(new java.awt.Color(255, 0, 0)));
headStyle.setFont(headerFont);
headStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255)));
headStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
XSSFCellStyle oddStyle = workbook.createCellStyle();
oddStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(randInt(125, 255), randInt(125, 255), randInt(125, 255))));
oddStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
//JDBC CONFIGURATIONS
Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
String dbURL = "jdbc:derby://localhost:1527/DATABASE_NAME;create=true;user=USER_ID;password=PASSWORD";
Connection connection = DriverManager.getConnection(dbURL);
Statement st = connection.createStatement();
ResultSet resultSet = st.executeQuery("Select * from TABLE_NAME");
ResultSetMetaData metaData = resultSet.getMetaData();
int colCount = metaData.getColumnCount();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
for (int curColIndx = 0; curColIndx < colCount; curColIndx++) {
XSSFCell cell = rowHead.createCell((short) curColIndx);
cell.setCellStyle(headStyle);
cell.setCellValue(metaData.getColumnName(curColIndx + 1));
}
int index = 1;
while (resultSet.next()) {
XSSFRow row = sheet.createRow((short) index);
for (int curColIndx = 0; curColIndx < colCount; curColIndx++) {
XSSFCell cell = row.createCell((short) curColIndx);
if (index % 2 == 1) {
cell.setCellStyle(oddStyle);
}
else {
cell.setCellStyle(evenStyle);
}
int type = metaData.getColumnType(curColIndx + 1);
if (type == Types.TIMESTAMP) {
cell.setCellValue(sdf.format(resultSet.getDate(curColIndx + 1)));
} else if (type == Types.VARCHAR || type == Types.CHAR) {
cell.setCellValue(resultSet.getString(curColIndx + 1));
} else {
cell.setCellValue(resultSet.getLong(curColIndx + 1));
}
}
index++;
}
baoStream = new ByteArrayOutputStream();
try {
//This Writes 27,842 bytes xlsx file to disk for sample data.
workbook.write(out);
//same workbook is written to ByteArrayOutputStream()
workbook.write(baoStream);
//But, baoStream size is 49022bytes and After Encryption and Zipping It Creates File of Size 43,084 bytes.
System.out.println("baoStream.size() :" + baoStream.size());
try {
//byte[] bytesToWrite = getBytesFromFile();
byte[] bytesToWrite = baoStream.toByteArray();
InMemoryOutputStream inMemoryOutputStream = new InMemoryOutputStream();
zos = new ZipOutputStream(inMemoryOutputStream);
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
parameters.setFileNameInZip(xlsxFileName);
parameters.setSourceExternalStream(true);
zos.putNextEntry(null, parameters);
zos.write(bytesToWrite);
zos.closeEntry();
zos.finish();
zos.close();
// Write contents in our InMemoryOutputStream to a zip file to test if this worked
writeContentsToZipFile(inMemoryOutputStream);
} catch (Exception e) {
e.printStackTrace();
}
out.close();
resultSet.close();
connection.close();
System.out.println("Excel written successfully..");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("Exception is :" + e.toString());
}
}
public ZipCreationInMemory() {
//testZipCreationInMemory();
createXlsxFile();
}
package zipconversion;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Writes the content to memory.
*
*/
public class InMemoryOutputStream extends OutputStream {
// As we cannot know the size of the zip file that is being created,
// we cannot maintain a byte array. We will copy all the bytes that
// gets passed in the write() method to a List. Once all writing is done,
// we can create a byte array from this List and this will be the content
// of the zip file
private List byteList;
// flag to keep track if the outputstream is closed
// no further write operations should be performed once this stream is closed
private boolean closed;
public InMemoryOutputStream() {
byteList = new ArrayList();
closed = false;
}
public void write(int b) throws IOException {
if (closed) {
throw new IOException("trying to write on a closed output stream");
}
byteList.add(Integer.toString(b));
}
public void write(byte[] b) throws IOException {
if (b == null) {
return;
}
write(b, 0, b.length);
}
public void write(byte[] b, int off, int len) throws IOException {
if (closed) {
throw new IOException("trying to write on a closed output stream");
}
if (b != null && len > 0) {
for (int i = 0; i < len; i++) {
byteList.add(Byte.toString(b[i]));
}
}
}
public byte[] getZipContent() {
if (byteList.size() <= 0) {
return null;
}
byte[] zipContent = new byte[byteList.size()+1];
for (int i = 0; i < byteList.size(); i++) {
zipContent[i] = Byte.parseByte((String) byteList.get(i));
}
return zipContent;
}
public void close() throws IOException {
closed = true;
}
}
The bug is possible in method
writeContentsToZipFile(inMemoryOutputStream)
, but you didn't post it's source code...I think the implement of
class InMemoryOutputStream
is not required, it's not effective and cause more problem.FileOutputStream
ByteArrayInputStream inMemoryOutputStream = new ByteArrayInputStream(bytesToWrite.length);
Note: The first parameter of
zos.putNextEntry(null, parameters)
is null. It works whenparameters.setSourceExternalStream(true)
. Under this mode, file name and other parameters are supplied via ZipParameters.