一、Excel 导入步骤:
step1: 功能入口:(三个参数 -- 第一个参数:(String)sheetName 第二个参数:( Strign[] ) 标题 第三个参数:(List< Object[] >)数据)
InputStream in = exportExcel(sheetName, title, datas);
step2: 定义一个数据流InputStream inputStream ,
字节数组缓冲区ByteArraryOutputStream byteArraryOutputStream,
声明一个工作簿HSSFWorkbook workbook,生成一个表格HSSFSheet sheet,生成样式HSSFCellStyle style,设置样式style.setXxx(),生成字体HSSFFont font,字体应用于样式style.setFont(font),生成画图管理器HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
step3: 产生表格标题行HSSFRow row,遍历集合,处理数据,产生数据行
step4: 处理的数据放入单元格cell.setCellValue() , 数据写入文件workbook.write(byteArraryOutputStream);,
创建一个大小与此输出流的当前大小的一个新分配缓冲区inputStream = new ByteArraryOutputStream(byteArraryOutputStream.toByteArrary());,并返回。
step5:定义打印的流,并填入文件地址生成文件:FileOutputStream fileOutputStream = new FileOutputStream("E:\\BenTigerkin\\tiger.xls");
定义字节数组 byte[] bytes = new byte[8192]; int bytesRead = 0;
打印进xls中,while(bytesRead = in.read(bytes) != -1){
fileOutputStream .write(bytes,0,bytesRead);
}
二、样式讲解:
// 声明一个工作薄 HSSFWorkbook workbook = new HSSFWorkbook(); // 生成一个表格 HSSFSheet sheet = workbook.createSheet(title); // 设置表格默认列宽度为15个字节 sheet.setDefaultColumnWidth(15); // 生成一个样式 HSSFCellStyle style = workbook.createCellStyle(); // 设置这些样式 style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);//单元格背景色 style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);//图案类型 style.setBorderBottom(HSSFCellStyle.BORDER_THIN);//单元格下边框为细线 style.setBorderLeft(HSSFCellStyle.BORDER_THIN);//单元格左边框 style.setBorderRight(HSSFCellStyle.BORDER_THIN);//单元格右边框 style.setBorderTop(HSSFCellStyle.BORDER_THIN);//单元格上边框 style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//单元格水平对齐方式
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//单元格垂直对齐方式// 生成一个字体HSSFFont font = workbook.createFont();font.setColor(HSSFColor.VIOLET.index);font.setFontHeightInPoints((short) 12);//设定字体大小font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);////字体增粗// 把字体应用到当前的样式style.setFont(font);
// 声明一个画图的*管理器 HSSFPatriarch patriarch = sheet.createDrawingPatriarch();//这里要加一个包commons-codec-1.11.jar // 定义注释的大小和位置,详见文档 HSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0,0, 0, 0, (short) 4, 2, (short) 6, 5));//直线
// new HSSFClientAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2);
//dx1 第1个单元格中x轴的偏移量 //dy1 第1个单元格中y轴的偏移量
//dx2 第2个单元格中x轴的偏移量 //dy2 第2个单元格中y轴的偏移量
// col1 第1个单元格的列号 //row1 第1个单元格的行号
//col2 第2个单元格的列号 //row2 第2个单元格的行号
// 设置注释内容 comment.setString(new HSSFRichTextString("可以在POI中添加注释!")); // 设置注释作者,当鼠标移动到单元格上是可以在状态栏中看到该内容. comment.setAuthor("author:xiaoling");
// 有图片时,设置行高为60px; row.setHeightInPoints(60); // 设置图片所在列宽度为80px,注意这里单位的一个换算 sheet.setColumnWidth(i, (int) (35.7 * 80)); // sheet.autoSizeColumn(i); byte[] bsValue = (byte[]) value; //处理照片位置 HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 100, 50, col , row , col +1, row +1); // 【图片左上角为(col, row)第row+1行col+1列 // 右下角为( col +1, row +1)第 col +1+1行row +1+1列,宽为100,高为50 HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 5, index, (short) 5, index); anchor.setAnchorType(2); patriarch.createPicture(anchor, workbook.addPicture( bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));//通过Image.createImage(width,height);可以得到一份图片的copy。 //也就是说:我们可以把某个图片缓存在内存中,然后随时可以把它调出来用。
更详细的样式属性请参考:http://m.knowsky.com/1052185.html
三、具体代码(可以作为公用类)
public class CreateExcel {
public static InputStream exportExcel(String title, String[] headers,List<Object[]> dataset) {//tittle:sheetName;headers:标题;dataset:数据
InputStream is;
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 声明一个工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
// 生成一个表格
HSSFSheet sheet = workbook.createSheet(title);
// 设置表格默认列宽度为15个字节
sheet.setDefaultColumnWidth(15);
// 生成一个样式
HSSFCellStyle style = workbook.createCellStyle();
// 设置这些样式
style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);//单元格背景色
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);//图案类型
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);//单元格下边框为细线
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);//单元格左边框
style.setBorderRight(HSSFCellStyle.BORDER_THIN);//单元格右边框
style.setBorderTop(HSSFCellStyle.BORDER_THIN);//单元格上边框
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//单元格水平对齐方式
// 生成一个字体
HSSFFont font = workbook.createFont();
font.setColor(HSSFColor.VIOLET.index);
font.setFontHeightInPoints((short) 12);//设定字体大小
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);////字体增粗
// 把字体应用到当前的样式
style.setFont(font);
// 生成并设置另一个样式
HSSFCellStyle style2 = workbook.createCellStyle();
style2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);
style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//单元格垂直对齐方式
// 生成另一个字体
HSSFFont font2 = workbook.createFont();
font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);//字体增粗
// 把字体应用到当前的样式
style2.setFont(font2);
// 声明一个画图的*管理器
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();//这里要加一个包commons-codec-1.11.jar
// 定义注释的大小和位置,详见文档
HSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short) 4, 2, (short) 6, 5));//直线
// 设置注释内容
comment.setString(new HSSFRichTextString("可以在POI中添加注释!"));
// 设置注释作者,当鼠标移动到单元格上是可以在状态栏中看到该内容.
comment.setAuthor("author:xiaoling");
// 产生表格标题行
HSSFRow row = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
sheet.setColumnWidth(2, (int)35.7 * 800);
sheet.setColumnWidth(3, (int)35.7 * 800);
// 遍历集合数据,产生数据行
int index = 0;
for (Object[] o : dataset) {
index++;
row = sheet.createRow(index);
for (int i = 0; i < o.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style2);
try {
Object value = o[i];
if(value== null){
value="";
}
// 判断值的类型后进行强制类型转换
String textValue = null;
if (value instanceof Boolean) {
boolean bValue = (Boolean) value;
textValue = "男";
if (!bValue) {
textValue = "女";
}
} else if (value instanceof Date) {
Date date = (Date) value;
SimpleDateFormat sdf = new SimpleDateFormat("Y-m-d H:i:s");
textValue = sdf.format(date);
} else if (value instanceof byte[]) {
// 有图片时,设置行高为60px;
row.setHeightInPoints(60);
// 设置图片所在列宽度为80px,注意这里单位的一个换算
sheet.setColumnWidth(i, (int) (35.7 * 80));
// sheet.autoSizeColumn(i);
byte[] bsValue = (byte[]) value;
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0,
1023, 255, (short) i, index, (short) i, index);
anchor.setAnchorType(2);
patriarch.createPicture(anchor, workbook.addPicture(
bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));
//也就是说:我们可以把某个图片缓存在内存中,然后随时可以把它调出来用。
} else {
// 其它数据类型都当作字符串简单处理
textValue = value.toString();
}
// 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
if (textValue != null) {
Pattern p = Pattern.compile("^//d+(//.//d+)?$");
Matcher matcher = p.matcher(textValue);
if (matcher.matches()) {
// 是数字当作double处理
cell.setCellValue(Double.parseDouble(textValue));
} else {
HSSFRichTextString richString = new HSSFRichTextString(
textValue);
HSSFFont font3 = workbook.createFont();
font3.setColor(HSSFColor.BLUE.index);
richString.applyFont(font3);
cell.setCellValue(richString);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 清理资源
}
}
}
try {
workbook.write(os);//数据写入文件
} catch (IOException e) {
e.printStackTrace();
}
is = new ByteArrayInputStream(os.toByteArray());//创建一个大小与此输出流的当前大小的一个新分配缓冲区
return is;
}} 注意:性别:true:男 false:女
图片要传读出的字节byte[]
我做的只是一个main()测试类,直接把所有的代码写在一个类里面,
public static void main(String args[]) throws IOException { String[] headers = new String[]{"id", "name", "sno", "sex", "idCard", "pic"}; String filePath = "E:\\\\Testling\\\\bx_ico.png"; byte[] bytePic = redPic(filePath);//读取图片 StudentInfoDao studentInfoDao = new StudentInfoDao(); List<Object[]> studentInfoDaos = new ArrayList<>(); Object[] object1 = new Object[]{1, "xiaoling", "11311010030", true, "342901199402222251", bytePic}; Object[] object2 = new Object[]{2, "xaioxiang", "11311010031", false, "342901195302215242", bytePic}; Object[] object3 = new Object[]{3, "xiaopiqiu", "11311010032", true, "342901199502212233", bytePic}; studentInfoDaos.add(0, object1); studentInfoDaos.add(1, object2); studentInfoDaos.add(2, object3); /** 功能入口 */ InputStream in = exportExcel("xiaolingTitle", headers, studentInfoDaos); FileOutputStream outputStream = null; try{ //定义打印的流,并且填入文件地址生成文件 outputStream = new FileOutputStream("E:\\xaioling123.xls"); //定义字节数组 byte[] bytes = new byte[8192]; int bytesRead = 0; //打印进xls中 while ((bytesRead = in.read(bytes)) != -1) { outputStream.write(bytes, 0, bytesRead); } }catch (Exception e) { e.printStackTrace(); } finally {//先打开的后关闭,后打开的先关闭 if (outputStream != null) { try { outputStream.flush(); outputStream.close(); } catch (Exception e) { e.printStackTrace(); } } if (in != null) { try { in.close(); } catch (Exception e) { e.printStackTrace(); } } } }
/** 读取图片数据 */
private static byte[] redPic(String filePath) { File file = new File(filePath); long fileSize = file.length(); if (fileSize > Integer.MAX_VALUE) { System.out.println("file too big..."); return null; } FileInputStream fi = null; try { fi = new FileInputStream(file); } catch (Exception e) { e.printStackTrace(); } byte[] buffer = new byte[(int) fileSize]; int offset = 0; int numRead = 0; try { while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) { offset += numRead; } } catch (Exception e) { e.printStackTrace(); } // 确保所有数据均被读取 if (offset != buffer.length) { try { throw new IOException("Could not completely read file " + file.getName()); } catch (Exception e) { e.printStackTrace(); } } try { fi.close(); } catch (Exception e) { e.printStackTrace(); } return buffer; }
四、整个过程中总结的小笔记
利用request.getHeader("user-agent")获取客户端浏览器和操作系统信息搜索
String Agent = request.getHeader("User-Agent");
StringTokenizer st = new StringTokenizer(Agent,";");
st.nextToken();
//得到用户的浏览器名
String userbrowser = st.nextToken();
//得到用户的操作系统名
String useros = st.nextToken();
取得本机的信息也可以这样:操作系统信息
System.getProperty("os.version");
request.getHeader(“User-agent”)返回客户端浏览器的版本号、类型
getHeader(String name):获得http协议定义的传送文件头信息,
request. getMethod():获得客户端向服务器端传送数据的方法有GET、POST、PUT等类型
request. getRequestURI():获得发出请求字符串的客户端地址
request. getServletPath():获得客户端所请求的脚本文件的文件路径
request. getServerName():获得服务器的名字
request.getServerPort():获得服务器的端口号
request.getRemoteAddr():获得客户端的IP地址
request.getRemoteHost():获得客户端电脑的名字,若失败,则返回客户端电脑的IP地址
request.getProtocol():request.getHeaderNames():返回所有request header的名字,结果集是一个Enumeration(枚举)类的实例
request.getHeaders(String name):返回指定名字的request header的所有值,结果集是一个Enumeration(枚举)类的实例
InputStream哪里可以读取文件?它是一个Abstract的类,根本不可能实例化
InputStream是所有输入流的基类,FileInputStream是它的一个实现类,允许程序读取机器上面的文件
类:
HSSFWorkbook 创建 xls 的对象; HSSFWorkbook hw = new HSSFWorkbook();
设置分区显示; hw.setRepeatingRowsAndColumns(sheet的index,行,列,行,列);
HSSFSheet 创建 xls 中的sheet(工作表); HSSFSheet sheet = hw.createSheet("sheet1");//sheet1是 sheet 的名称可缺省
设置列高; sheet.setColumnWidth((short)short,(short)short);
HSSFRow 创建 xls 中的行; HSSFRow row = sheet.createRow(0); //0表示第一行
设置行高; row.setHeight((short)short);
HSSFFont 创建xls 中的字体; HSSFFont font = hw.createFont();
设定字体大小; font.setFontHeightInPoints((short)54);
设定为斜体; font.setItalic(true);
设定文字删除线; font.setStrikeout(true);
HSSFCellStyle 设定单元格风格; HSSFCellStyle style = wb.createCellStyle();
加入字体; style.setFont(font);
HSSFCell 设定单元格; HSSFCell cell = row.createCell((short)0);
单元格水平对齐方式; style.setAlignment(align); //单元格水平0:普通1:左对齐2:居中3:右对齐4:填充5:正当 6:居中选择
单元格垂直对齐方式; style.setVerticalAlignment(align); //单元格垂直 0 :居上 1:居中 2:居下 3:正当
单元格下边框为细线; style.setBorderBottom((short)short);
同上一命令一同使用,设置颜色; style.setBottomBorderColor((short)short);
单元格左边框; style.setBorderLeft((short)short); | style.setLeftBorderColor((short)short);
单元格右边框; style.setBorderRight((short)short); | style.setRightBorderColor((short)short);
单元格上边框; style.setBorderTop((short)short); |style.setTopBorderColor((short)short);
单元格字符编号(中文); cell.setEncoding(HSSFCell.ENCODING_UTF_16); //中文
单元格显示的值; cell.setCellValue("中医药"); //值的类型有:double,int,String,Date,boolean
单元格背景色; style.setFillForegroundColor((short)short);
图案类型; style.setFillPattern((short)short);
单元格合并; sheet.addMergedRegion(new Region(行, (short)列, 行, (short)列));
单元格风格加入; cell.setCellStyle(style);
HSSFPatriarch patriarch = ((HSSFSheet)wb.getSheet("sheetname14")).createDrawingPatriarch();
//直线
HSSFClientAnchor clientAnchor1 = new HSSFClientAnchor(0, 0, 0, 0,
(short) 4, 2, (short) 6, 5);
HSSFSimpleShape shape1 = patriarch.createSimpleShape(clientAnchor1);
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
//圆圈(椭圆)
HSSFClientAnchor clientAnchor2 = new HSSFClientAnchor(0, 0, 0, 0,
(short) 8, 4, (short) 6, 5);
HSSFSimpleShape shape2 = patriarch.createSimpleShape(clientAnchor2);
shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
//正方形(长方形)
HSSFClientAnchor clientAnchor3 = new HSSFClientAnchor(0, 0, 0, 0,
(short) 12, 6, (short) 6, 5);
HSSFSimpleShape shape3 = patriarch.createSimpleShape(clientAnchor3);
shape3.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
//Textbox
HSSFClientAnchor clientAnchor4 = new HSSFClientAnchor(0, 0, 0, 0,
(short) 14, 8, (short) 6, 5);
HSSFTextbox textbox = patriarch.createTextbox(clientAnchor4);
textbox.setString(new HSSFRichTextString("This is a test"));
查看源码发现ByteArrayOutputStream的close();是空实现;它其实就是通过一个缓冲的byte[] 对标准输出流进行封装(标准的输出流是打开一个文件 无缓冲); 也就是说它本身没啥好关闭的 能访问时byte[]这个buffer 没有被回收 FileOutputStream有close()方法。执行之后要关闭流
JAVA常用的节点流:
文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件进行处理的节点流。
字符串 StringReader StringWriter 对字符串进行处理的节点流。
数 组 ByteArrayInputStream ByteArrayOutputStreamCharArrayReader CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
管 道 PipedInputStream PipedOutputStream PipedReaderPipedWriter对管道进行处理的节点流。
常用处理流(关闭处理流使用关闭里面的节点流)
缓冲流:BufferedInputStrean BufferedOutputStream BufferedReader BufferedWriter ---增加缓冲功能,避免频繁读写硬盘。
转换流:InputStreamReader OutputStreamReader实现字节流和字符流之间的转换。
数据流 DataInputStream DataOutputStream 等-提供将基础数据类型写入到文件中,或者读取出来.
流的关闭顺序
一般情况下是:先打开的后关闭,后打开的先关闭
另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b。
例如,处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b 可以只关闭处理流,不用关闭节点流。
处理流关闭的时候,会调用其处理的节点流的关闭方法。
注意: 如果将节点流关闭以后再关闭处理流,会抛出IO异常。
如果关闭了处理流,在关闭与之相关的节点流,也可能出现IO异常。
不关闭流的后果:因为打开了流扥与文件已经在应用,此时无法删除你已经打开的文件。另外,占用内存空间,但现在的电脑配置,你在运行过程中这方面(占用内存)也很难体现出来的。严格地说,规范化的编程一般都要记住要关闭输入输出流的。
flush()意思是把缓冲区的内容强制的写出。
因为操作系统的某些机制,为了防止一直不停地磁盘读写,所以有了延迟写入的概念,(注意不要和frush()刷新混淆了)主要用在IO中,即清空缓冲区数据,一般在读写流(stream)的时候,数据是先被读到了内存中,再把数据写到文件中,当你数据读完的时候不代表你的数据已经写完了,因为还有一部分有可能会留在内存这个缓冲区中。这时候如果你调用了close()方法关闭了读写流,那么这部分数据就会丢失,所以应该在关闭读写流之前先flush()。。