该指南的发布为当前svn主干提供了功能。那些在以前版本中查找信息的人应该查看发布的文档。
HSSF允许从XLS文件中写入或读取数字、字符串、日期或公式单元格值。在这个版本中,还包括行和列的大小、单元样式(粗体、斜体、边框等),并支持内置和用户定义的数据格式。还有一个基于事件的API来读取XLS文件。它与读/写API有很大的不同,它是为需要更小内存占用的中级开发人员设计的。
写一个新文件#
高水平的API(包:org.apache.poi.ss.usermodel)是大多数人应该使用。使用非常简单。
org.apache.poi.ss.usermodel.Workbook的手册是由创建一个实例。直接创建一个具体的类(org.apache.poi.hssf.usermodel。HSSFWorkbook或org.apache.poi.xssf.usermodel.XSSFWorkbook),或使用方便的工厂类org.apache.poi.ss.usermodel.WorkbookFactory。
从工作簿的现有实例中调用createSheet()来创建表单,创建的表单会自动添加到工作簿的序列中。表单本身并没有表单名称(底部的选项卡);您可以通过调用Workbook.setSheetName(sheetindex,“SheetName”,编码)来设置与表单相关联的名称。对于HSSF,名称可能是8位格式(HSSFWorkbook.ENCODING_COMPRESSED_UNICODE)或Unicode(HSSFWorkbook.ENCODING_UTF_16)。HSSF的默认编码是每字符8比特。对于XSSF,名称将自动处理为unicode。
行是通过将createRow(rowNumber)从一个现有的表实例中创建出来的。只有具有单元格值的行才应该被添加到表中。要设置行的高度,只需在行对象上调用setRowHeight(height)。高度必须用两种方法来表示,即1 / 20。如果您喜欢,还有一个setRowHeightInPoints方法。
单元格是通过从现有的行调用createCell(列,类型)创建的。只有具有值的单元格应该添加到行中。单元格应该将其单元格设置为单元格。CELL_TYPE_NUMERIC或细胞。CELL_TYPE_STRING取决于它们是否包含数字或文本值。单元格还必须具有一个值集,通过使用字符串或double作为参数来调用setCellValue来设置值。单个细胞没有宽度;您必须在表单对象上调用setColumnWidth(colindex,width)(在字符的1 / 256中使用单位)。(你不能在GUI中单独使用它)。
单元格使用CellStyle对象进行样式化,而CellStyle对象又包含对字体对象的引用。这些是通过调用createCellStyle()和createFont()通过工作簿对象创建的。创建对象后,必须设置其参数(颜色、边框等)。为CellStyle调用setFont(fontobj)设置字体。
一旦生成了工作簿,就可以从工作簿的实例中调用write(outputStream)来编写它,将它传递给outputStream(例如,FileOutputStream或ServletOutputStream)。你必须自己关闭OutputStream。HSSF不会为你关闭它。
下面是一些示例代码(摘录和改编自org.apache.poi.hssf.dev.HSSF测试类):
行数:
// 创建一个新的文件
FileOutputStream out = new FileOutputStream("workbook.xls");
// 创建一个新的工作簿
Workbook wb = new HSSFWorkbook();
// 创建一个新的表单
Sheet s = wb.createSheet();
// 声明行对象引用
Row r = null;
//声明单元格引用
Cell c = null;
// 创建3个不同类型的单元格
CellStyle cs = wb.createCellStyle();
CellStyle cs2 = wb.createCellStyle();
CellStyle cs3 = wb.createCellStyle();
DataFormat df = wb.createDataFormat();
// 创建两个字体的对象
Font f = wb.createFont();
Font f2 = wb.createFont();
//设置字体1到12点类型
f.setFontHeightInPoints((short) 12);
//使用蓝色
f.setColor( (short)0xc );
//使用黑色
//arial是默认字体
f.setBoldweight(Font.BOLDWEIGHT_BOLD);
//设置字体2到10点类型
f2.setFontHeightInPoints((short) 10);
//设置红色
f2.setColor( (short)Font.COLOR_RED );
//设置黑色
f2.setBoldweight(Font.BOLDWEIGHT_BOLD);
f2.setStrikeout( true );
//设置单元格风格
cs.setFont(f);
//舍子单元格格式
cs.setDataFormat(df.getFormat("#,##0.0"));
//设置边界
cs2.setBorderBottom(cs2.BORDER_THIN);
//填充w fg填充颜色
cs2.setFillPattern((short) CellStyle.SOLID_FOREGROUND);
//将单元格格式设置为文本,以查看完整列表的DataFormat
cs2.setDataFormat(HSSFDataFormat.getBuiltinFormat("text"));
// 设置字体
cs2.setFont(f2);
// 在Unicode中设置表单名称
wb.setSheetName(0, "\u0422\u0435\u0441\u0442\u043E\u0432\u0430\u044F " +
"\u0421\u0442\u0440\u0430\u043D\u0438\u0447\u043A\u0430" );
//如果是普通ascii
// wb.setSheetName(0, "HSSF Test");
// create a sheet with 30 rows (0-29)
int rownum;
for (rownum = (short) 0; rownum < 30; rownum++)
{
// 创建一行
r = s.createRow(rownum);
//每隔一行
if ((rownum % 2) == 0)
{
// make the row height bigger (in twips - 1/20 of a point)
r.setHeight((short) 0x249);
}
//r.setRowNum(( short ) rownum);
// create 10 cells (0-9) (the += 2 becomes apparent later
for (short cellnum = (short) 0; cellnum < 10; cellnum += 2)
{
// create a numeric cell
c = r.createCell(cellnum);
// 演示一下
c.setCellValue(rownum * 10000 + cellnum
+ (((double) rownum / 1000)
+ ((double) cellnum / 10000)));
String cellValue;
// create a string cell (see why += 2 in the
c = r.createCell((short) (cellnum + 1));
// on every other row
if ((rownum % 2) == 0)
{
// set this cell to the first cell style we defined
c.setCellStyle(cs);
// set the cell's string value to "Test"
c.setCellValue( "Test" );
}
else
{
c.setCellStyle(cs2);
// set the cell's string value to "\u0422\u0435\u0441\u0442"
c.setCellValue( "\u0422\u0435\u0441\u0442" );
}
// make this column a bit wider使这一列宽一些
s.setColumnWidth((short) (cellnum + 1), (short) ((50 * 8) / ((double) 1 / 20)));
}
}
//draw a thick black border on the row at the bottom using BLANKS在底部的行上画一个厚实的黑色边框,使用空格
// advance 2 rows提前2行
rownum++;
rownum++;
r = s.createRow(rownum);
// define the third style to be the default定义第三种样式为缺省值
// except with a thick black border at the bottom除了底部有一条粗黑的边
cs3.setBorderBottom(cs3.BORDER_THICK);
//create 50 cells创建50个单元格
for (short cellnum = (short) 0; cellnum < 50; cellnum++)
{
//create a blank type cell (no value)
c = r.createCell(cellnum);
// set it to the thick black border style将其设置为粗黑的边框样式
c.setCellStyle(cs3);
}
//end draw thick black border最后画出厚实的黑边
// demonstrate adding/naming and deleting a sheet
// create a sheet, set its title then delete it
s = wb.createSheet();
wb.setSheetName(1, "DeletedSheet");
wb.removeSheetAt(1);
//end deleted sheet
// write the workbook to the output stream将工作簿写入输出流
// close our file (don't blow out our file handles关闭文件
wb.write(out);
out.close();
读取或修改现有文件在文件中阅读同样简单。在一个文件中读取,创建一个新的org . apache.poifs。文件系统,在打开的InputStream中传递,比如XLS的FileInputStream,到构造函数。org.apache.poi.hssf.usermodel构造一个新实例。HSSFWorkbook将文件系统实例传递给构造函数。通过它们的评估方法(workbook.getSheet(sheetNum)、sheet.getRow(rownum)等),您可以访问所有的高级模型对象。修改你读过的文件很简单。您通过一个评估器方法来检索对象,通过父对象的remove方法(sheet.removeRow(hssfrow))删除该对象,并创建与创建新xls时一样的对象。当您完成修改单元格时,只需调用workbook.write(outputstream),就像上面做的那样。一个例子中可以看到org.apache.poi.hssf.usermodel.examples.HSSFReadWrite。事件API比用户API更新。它是为那些愿意学习少量底层API结构的中级开发人员设计的。它使用起来相对简单,但需要对Excel文件的部分(或愿意学习)有一个基本的了解。所提供的优势是,您可以读取具有相对较小内存占用的XLS。基本事件API需要注意的一件重要事情是,它只触发事件,而这些事件实际上存储在文件中。对于XLS文件格式,对于那些还没有被编辑的东西,在文件中根本不存在是很常见的。这意味着在记录流中很可能存在明显的“空白”,您可能需要在此工作,或者使用事件API的记录感知扩展。你使用这个API构建org.apache.poi.hssf.eventmodel.HSSFRequest的实例。一个类创建支持org.apache.poi.hssf.eventmodel登记。HSSFListener接口使用hss频率。addListener(yourlistener recordsid)。recordsid应该是静态参考号码(如BOFRecord.sid)包含在org.apache.poi.hssf.record类。诀窍是你必须知道这些记录是什么。或者你可以叫HSSFRequest.addListenerForAllRecords(mylistener)。为了了解这些记录,您可以在org . apache.poi.hssf中读取所有的javadoc。记录包或你可以破解org.apache.poi.hssf.dev.EFHSSF副本和适应您的需要。TODO:更好的记录文档。一旦你注册你的听众在HSSFRequest对象可以构造org.apache.poi.poifs.filesystem的实例。文件系统(参见POIFS howto)并将其传递给您的XLS文件inputstream。您可以通过HSSFEventFactory向HSSFEventFactory的实例传递这个请求,以及您构造的请求。processWorkbookEvents(请求、文件系统)方法,或者你可以得到一个实例的DocumentInputStream Filesystem.createDocumentInputStream(“工作手册”)并将其传递给HSSFEventFactory。processEvents(请求,inputStream)。一旦您进行了这个调用,您所构造的侦听器就会接收到它们的processRecord(记录)方法,并在每个记录中记录它们,直到文件完全被读取为止。public class EventExample
implements HSSFListener
{
private SSTRecord sstrec;
/**
* This method listens for incoming records and handles them as required.
* @param record The record that was found while reading.
*/
public void processRecord(Record record)
{
switch (record.getSid())
{
// the BOFRecord can represent either the beginning of a sheet or the workbook
case BOFRecord.sid:
BOFRecord bof = (BOFRecord) record;
if (bof.getType() == bof.TYPE_WORKBOOK)
{
System.out.println("Encountered workbook");
// assigned to the class level member
} else if (bof.getType() == bof.TYPE_WORKSHEET)
{
System.out.println("Encountered sheet reference");
}
break;
case BoundSheetRecord.sid:
BoundSheetRecord bsr = (BoundSheetRecord) record;
System.out.println("New sheet named: " + bsr.getSheetname());
break;
case RowRecord.sid:
RowRecord rowrec = (RowRecord) record;
System.out.println("Row found, first column at "
+ rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
break;
case NumberRecord.sid:
NumberRecord numrec = (NumberRecord) record;
System.out.println("Cell found with value " + numrec.getValue()
+ " at row " + numrec.getRow() + " and column " + numrec.getColumn());
break;
// SSTRecords store a array of unique strings used in Excel.
case SSTRecord.sid:
sstrec = (SSTRecord) record;
for (int k = 0; k < sstrec.getNumUniqueStrings(); k++)
{
System.out.println("String table value " + k + " = " + sstrec.getString(k));
}
break;
case LabelSSTRecord.sid:
LabelSSTRecord lrec = (LabelSSTRecord) record;
System.out.println("String cell found with value "
+ sstrec.getString(lrec.getSSTIndex()));
break;
}
}
/**
* Read an excel file and spit out what we find.
*
* @param args Expect one argument that is the file to read.
* @throws IOException When there is an error processing the file.
*/
public static void main(String[] args) throws IOException
{
// create a new file input stream with the input file specified
// at the command line
FileInputStream fin = new FileInputStream(args[0]);
// create a new org.apache.poi.poifs.filesystem.Filesystem
POIFSFileSystem poifs = new POIFSFileSystem(fin);
// get the Workbook (excel part) stream in a InputStream
InputStream din = poifs.createDocumentInputStream("Workbook");
// construct out HSSFRequest object
HSSFRequest req = new HSSFRequest();
// lazy listen for ALL records with the listener shown above
req.addListenerForAllRecords(new EventExample());
// create our event factory
HSSFEventFactory factory = new HSSFEventFactory();
// process our events based on the document input stream
factory.processEvents(req, din);
// once all the events are processed close our file input stream
fin.close();
// and our document input stream (don't want to leak these!)
din.close();
System.out.println("done.");
}
}这是对正常事件API的扩展。有了这个,您的监听器就会被调用额外的假记录。这些虚拟记录应该提醒您记录文件中不存在的记录(如尚未编辑的单元格),并允许您处理这些记录。你的HSSFListener将被调用三个虚拟记录:org.apache.poi.hssf.eventusermodel.dummyrecord.MissingRowDummyRecord这在行记录阶段(通常发生在单元格记录之前)调用,并指出给定行的行记录不在文件中。org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord这在细胞记录阶段被调用。当遇到一个单元记录时,它会被调用,这将在它与前一个记录之间留下一个空白。你可以在真正的细胞记录之前得到这些。org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord这是在给定行的最后一个单元格之后调用的。它表示没有更多的单元格,也告诉你有多少个单元格。对于没有单元格的行,这将是您获得的唯一记录。要使用记录清楚事件API,您应该创建一个org.apache.poi.hssf.eventusermodel。你HSSFListener MissingRecordAwareHSSFListener,通过它。然后,注册MissingRecordAwareHSSFListener事件模型,正常开始。这个API的一个例子是编写一个CSV输出器,它总是输出最少的列数,即使文件不包含一些行或单元格。它可以发现在/ src / / src /org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra例子。java,可以在命令行中调用,也可以在自己的代码中调用。最新版本总是可以从subversion中获得。在版本3.0.3之前的POI版本中,这段代码一直存在于scratchpad部分。如果您使用的是这些旧版本的POI,您将需要在类路径中包含scratchpad jar,或者从subversion签出中构建。如果内存占用是一个问题,那么对于XSSF,您可以获取底层XML数据,并自己处理它。这是为那些愿意学习低层次结构的中级开发人员设计的。xlsx文件,以及在java中处理XML的人。它使用起来相对简单,但需要对文件结构有基本的了解。所提供的优势是您可以读取一个内存占用相对较小的XLSX文件。基本事件API需要注意的一件重要事情是,它只触发事件,而这些事件实际上存储在文件中。对于XLSX文件格式,在文件中根本不存在的东西是很常见的。这意味着在记录流中很可能存在明显的“空白”,您需要对此进行处理。你使用这个API构建org.apache.poi.xssf.eventmodel.XSSFReader的实例。这将可选地在共享的字符串表和样式上提供一个漂亮的接口。它提供了从文件的其余部分获取原始xml数据的方法,然后将这些数据传递给SAX。这个例子展示了如何获取一个已知的表单,或者在文件中的所有页。它是基于中的示例svn src / / src /org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java例子import java.io.InputStream;
import java.util.Iterator;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
public class ExampleEventUserModel {
public void processOneSheet(String filename) throws Exception {
OPCPackage pkg = OPCPackage.open(filename);
XSSFReader r = new XSSFReader( pkg );
SharedStringsTable sst = r.getSharedStringsTable();
XMLReader parser = fetchSheetParser(sst);
// To look up the Sheet Name / Sheet Order / rID,
// you need to process the core Workbook stream.
// Normally it's of the form rId# or rSheet#
InputStream sheet2 = r.getSheet("rId2");
InputSource sheetSource = new InputSource(sheet2);
parser.parse(sheetSource);
sheet2.close();
}
public void processAllSheets(String filename) throws Exception {
OPCPackage pkg = OPCPackage.open(filename);
XSSFReader r = new XSSFReader( pkg );
SharedStringsTable sst = r.getSharedStringsTable();
XMLReader parser = fetchSheetParser(sst);
Iterator<InputStream> sheets = r.getSheetsData();
while(sheets.hasNext()) {
System.out.println("Processing new sheet:\n");
InputStream sheet = sheets.next();
InputSource sheetSource = new InputSource(sheet);
parser.parse(sheetSource);
sheet.close();
System.out.println("");
}
}
public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException {
XMLReader parser =
XMLReaderFactory.createXMLReader(
"org.apache.xerces.parsers.SAXParser"
);
ContentHandler handler = new SheetHandler(sst);
parser.setContentHandler(handler);
return parser;
}
/**
* See org.xml.sax.helpers.DefaultHandler javadocs
*/
private static class SheetHandler extends DefaultHandler {
private SharedStringsTable sst;
private String lastContents;
private boolean nextIsString;
private SheetHandler(SharedStringsTable sst) {
this.sst = sst;
}
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
// c => cell
if(name.equals("c")) {
// Print the cell reference
System.out.print(attributes.getValue("r") + " - ");
// Figure out if the value is an index in the SST
String cellType = attributes.getValue("t");
if(cellType != null && cellType.equals("s")) {
nextIsString = true;
} else {
nextIsString = false;
}
}
// Clear contents cache
lastContents = "";
}
public void endElement(String uri, String localName, String name)
throws SAXException {
// Process the last contents as required.
// Do now, as characters() may be called more than once
if(nextIsString) {
int idx = Integer.parseInt(lastContents);
lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
nextIsString = false;
}
// v => contents of a cell
// Output after we've seen the string contents
if(name.equals("v")) {
System.out.println(lastContents);
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
lastContents += new String(ch, start, length);
}
}
public static void main(String[] args) throws Exception {
ExampleEventUserModel example = new ExampleEventUserModel();
example.processOneSheet(args[0]);
example.processAllSheets(args[0]);
}
}SXSSF(包:org.apache.poi.xssf.streaming)是一种API-compatible流扩展的XSSF时使用非常大的电子表格制作,和堆空间是有限的。SXSSF通过限制进入滑动窗口内的行来实现其低内存占用,而XSSF可以访问文档中的所有行。在窗口中不再出现的旧行变得不可访问,因为它们被写到磁盘上。您可以指定在工作簿窗口大小建设时间通过新的SXSSFWorkbook(int windowSize)或通过SXSSFSheet #你可以设置每张setRandomAccessWindowSize(int windowSize)当一个新行通过createRow()创建时,未刷新记录的总数将超过指定的窗口大小,那么具有最低索引值的行将被刷新,并且不能通过getRow()访问。默认窗口大小为100,由SXSSFWorkbook.DEFAULT_WINDOW_SIZE定义。窗口大小为- 1表示访问不受限制。在这种情况下,所有未被调用flushRows()的记录都可以随机访问。请注意,通过调用dispose方法,SXSSF会分配您必须经常清理的临时文件。SXSSFWorkbook默认使用内联字符串而不是共享的字符串表。这是非常有效的,因为没有文档内容需要保存在内存中,但是也可以生成与一些客户机不兼容的文档。在共享的字符串中,文档中的所有唯一字符串都必须保存在内存中。根据文档内容,可以使用比使用共享字符串禁用的更多的资源。请注意,仍然有一些东西仍然可能消耗大量的内存,这是基于您正在使用的特性,例如合并区域、超链接、注释、……仍然只存储在内存中,因此可能需要大量的内存。在决定是否启用共享字符串之前,请仔细检查内存预算和兼容性需求。下面的示例使用100行窗口编写了一个表。当行数达到101时,与rownum = 0的行被刷新到磁盘并从内存中删除,当rownum达到102时,与rownum = 1的行被刷新等。import junit.framework.Assert;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
public static void main(String[] args) throws Throwable {
SXSSFWorkbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
Sheet sh = wb.createSheet();
for(int rownum = 0; rownum < 1000; rownum++){
Row row = sh.createRow(rownum);
for(int cellnum = 0; cellnum < 10; cellnum++){
Cell cell = row.createCell(cellnum);
String address = new CellReference(cell).formatAsString();
cell.setCellValue(address);
}
}
// Rows with rownum < 900 are flushed and not accessible
for(int rownum = 0; rownum < 900; rownum++){
Assert.assertNull(sh.getRow(rownum));
}
// ther last 100 rows are still in memory
for(int rownum = 900; rownum < 1000; rownum++){
Assert.assertNotNull(sh.getRow(rownum));
}
FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
wb.write(out);
out.close();
// dispose of temporary files backing this workbook on disk
wb.dispose();
}The next example turns off auto-flushing (windowSize=-1) and the code manually controls how portions of data are written to diskimport org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
public static void main(String[] args) throws Throwable {
SXSSFWorkbook wb = new SXSSFWorkbook(-1); // turn off auto-flushing and accumulate all rows in memory
Sheet sh = wb.createSheet();
for(int rownum = 0; rownum < 1000; rownum++){
Row row = sh.createRow(rownum);
for(int cellnum = 0; cellnum < 10; cellnum++){
Cell cell = row.createCell(cellnum);
String address = new CellReference(cell).formatAsString();
cell.setCellValue(address);
}
// manually control how rows are flushed to disk
if(rownum % 100 == 0) {
((SXSSFSheet)sh).flushRows(100); // retain 100 last rows and flush all others
// ((SXSSFSheet)sh).flushRows() is a shortcut for ((SXSSFSheet)sh).flushRows(0),
// this method flushes all rows
}
}
FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
wb.write(out);
out.close();
// dispose of temporary files backing this workbook on disk
wb.dispose();
}
SXSSF在临时文件(每个表的临时文件)中刷新表数据,这些临时文件的大小可以增长到非常大的值。例如,对于20 MB的csv数据,temp xml的大小超过了1gb。如果temp文件的大小是一个问题,您可以告诉SXSSF使用gzip压缩:
SXSSFWorkbook wb = new SXSSFWorkbook();
wb.setCompressTempFiles(true); // temp files will be gzipped如果您希望从某些XML生成一个XLS文件,那么可以编写自己的XML处理代码,然后使用用户API来编写文档。另一种选择是使用蚕茧。在Cocoon中,有一个HSSF序列化器,它以XML(在gnumeric格式)中获取,并为您输出一个XLS文件。HSSF有许多工具可以帮助开发人员使用HSSF调试/开发一些东西(更多的是XLS文件)。我们已经讨论了测试HSSF读/写/修改功能的应用程序;现在我们要讲一下BiffViewer。在HSSF的早期开发过程中,我们决定知道在记录中什么是错误的,什么是错误的,等等在可用的工具中几乎是不可能的。所以我们开发了BiffViewer。你可以找到在org.apache.poi.hssf.dev.BiffViewer。它有两个基本的函数和一个导数。第一个是“biffview”。为此,您运行它(假设您的类路径中有所有的设置,并且您知道您所做的事情足以让您考虑这一点),并将xls文件作为参数。它将提供所有已知记录的列表,其中包含它们的数据和一个没有数据的未被理解的记录列表(因为它不知道如何解释它们)。这个清单对一些事情很有用。首先,您可以查看这些值,并了解准英语中哪些是错误的。第二,您可以将输出发送到一个文件并进行比较。第二个函数是“大的freakin转储文件”,只需传递一个文件和一个匹配“bfd”的第二个参数。这将会是文件的一个大的hexdump。最后,还有“混合”模式,它与常规的biffview一样,只包括某些记录的十六进制转储。要使用它,只需传递一个文件,而第二个参数与“on”完全匹配。在下一个发布周期中,我们还会有一个称为公式查看器的东西。这个类已经在那里了,但是还不是很有用。当它做某件事时,我们会记录它。