NPOI组件
一个Excel导出类的实现过程(三):NPOI组件
NPOI组件强大高效,这里只使用它完成我们的Excel写入功能,需要更多内容则请自行搜索。
IWorkbook:工作簿对象,可以由NPOI.HSSF.UserModel.HSSFWorkbook实例化得来,Write(Stream stream)如其意;
ISheet:工作表对象,可以由IWorkbook实例的CreateSheet()方法创建;
IRow:行对象,可以由ISheet实例的Create()方法创建;
ICell:单元格对象,可以由IRow实例的CreateCell()方法创建。
先处理翻页问题,10版Excel最多支持1048576行,03版Excel最多支持65536行。只处理03版Excel,除去表头,翻页算法如下:
IWorkbook workbook = new HSSFWorkbook();
ISheet sheet = null;
const Int32 RowPerSheet = 65535;
for (Int32 r = 0; r < records.Count; r++)
{
if ((r % RowPerSheet) == 0)
{
Int32 sheetIndex = (Int32)((Double)r / RowPerSheet) + 1;
sheet = workbook.CreateSheet("Sheet" + sheetIndex);
for (Int32 i = 0; i < headers.Count; i++)
{
Console.Write(headers[i].PrintName);
Console.Write("\t");
}
Console.WriteLine();
}
//注意CreateRow(Int32 rownum)中参数rownum虽然从第0行开始,但因为表头存在,每次得往下一行
IRow row = sheet.CreateRow(r % RowPerSheet + 1);
for (Int32 i = 0; i < props.Length; i++)
{
//拿row干活儿了...
}
}
注意引用NPOI.SS.UserModel和NPOI.HSSF.UserModel命名空间,现在我们有Row,那么创建单元格写入内容就容易了。
考虑到导出一个65536行的工作表,看的人会抓狂,于是封装导出方法到ExcelHelper类,提供行数属性及导出方法,同时将Header类设置为其内部类(这个不是必须的,但重命名一下可能没错),实现如下:
public class ExcelHelper
{
public class Header
{
public String Name { get; private set; }
public String PrintName { get; private set; }
public Header(String name)
: this(name, name)
{
}
public Header(String name, String printName)
{
Name = name;
PrintName = printName;
}
}
private const Int32 MaxRowPerSheet = 65535;
private Int32 rowPerSheet = 1000;
public Int32 RowPerSheet
{
get { return rowPerSheet; }
set
{
if (value < 0 || value > MaxRowPerSheet)
{
throw new ArgumentOutOfRangeException("RowPerSheet");
}
else
{
rowPerSheet = value;
}
}
}
public IWorkbook Export<T>(IList<T> records)
{
if (records == null)
throw new ArgumentNullException("records");
String[] headers = typeof(T).GetProperties().Select(p => p.Name).ToArray();
return Export<T>(records, headers);
}
public IWorkbook Export<T>(IList<T> records, IList<String> headers)
{
if (records == null)
throw new ArgumentNullException("records");
if (headers == null || headers.Count == 0)
throw new ArgumentNullException("headers");
Header[] newHeaders = typeof(T).GetProperties().Select(p => new Header(p.Name)).ToArray();
return Export<T>(records, newHeaders);
}
public IWorkbook Export<T>(IList<T> records, IList<Header> headers)
{
if (records == null)
throw new ArgumentNullException("records");
if (headers == null || headers.Count == 0)
throw new ArgumentNullException("headers");
PropertyInfo[] props = new PropertyInfo[headers.Count];
for (int i = 0; i < headers.Count; i++)
{
props[i] = typeof(T).GetProperty(headers[i].Name); //注意属性数组仍然可以有元素为null
}
IWorkbook workbook = new HSSFWorkbook();
ISheet sheet = null;
IRow row = null;
for (int r = 0; r < records.Count; r++)
{
if ((r % RowPerSheet) == 0)
{
Int32 sheetIndex = (Int32)((Double)r / RowPerSheet) + 1;
sheet = workbook.CreateSheet("Sheet" + sheetIndex);
row = sheet.CreateRow(0);
for (int i = 0; i < headers.Count; i++)
{
row.CreateCell(i).SetCellValue(headers[i].PrintName);
}
Console.WriteLine();
}
//注意CreateRow(Int32 rownum)中参数rownum虽然从第0行开始,但因为表头存在,每次得往下一行
row = sheet.CreateRow(r % RowPerSheet + 1);
for (int i = 0; i < props.Length; i++)
{
if (props[i] != null) //注意null检查
{
Object value = props[i].GetValue(records[r], null);
if (value != null)
{
row.CreateCell(i).SetCellValue(value.ToString());
}
}
}
}
for (Int32 i = 0; i < workbook.NumberOfSheets; i++)
{
sheet = workbook.GetSheetAt(i);
for (Int32 h = 0; h < headers.Count; h++)
{
sheet.AutoSizeColumn(h); //每列宽度自适应
}
}
return workbook;
}
}
客户端调用如下:
static void Main(string[] args)
{
List<Person> persons = new List<Person>();
//persons.Add(new Person { ID = 1, Name = "Rattz", Birth = new DateTime(1980, 10, 1), Salary = 20.2D });
//persons.Add(new Person { ID = 2, Name = "Mike", Birth = new DateTime(1988, 2, 15), Salary = 20.2D });
Int32 records = 201;
for (Int32 i = 0; i < records; i++)
{
persons.Add(new Person { ID = i, Name = "name" + i, Birth = new DateTime(1980, 10, 1), Salary = 20.2D });
}
List<ExcelHelper.Header> headers = new List<ExcelHelper.Header>();
headers.Add(new ExcelHelper.Header("ID"));
headers.Add(new ExcelHelper.Header("Name", "名称"));
headers.Add(new ExcelHelper.Header("Birth", "生日"));
headers.Add(new ExcelHelper.Header("Salary", "薪水"));
ExcelHelper excelHelper = new ExcelHelper();
excelHelper.RowPerSheet = 100;
IWorkbook workbook = excelHelper.Export<Person>(persons, headers);
String path = @"d:\1.xls";
using (FileStream stream = File.Open(path, FileMode.OpenOrCreate))
{
workbook.Write(stream);
}
}
至此功能已完成,但细节待完善,观察“生日”列所有值都是1980-10-01 0,这是单元格值设置语句row.CreateCell(i).SetCellValue(value.ToString())过于简单的缘故,后续一篇继续,读者也可以参考NPOI组件的ICell属性与方法自行完成。
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did45699