简介
最近一个朋友让我帮他处理一个excel文档,功能是从excel表中的找到第一个sheet中每个点(经纬度)在第二个地理位置中最近的3个点。给个两点的经纬度可以求出这两点之间的距离,主要是如何读写excel,幸运的是Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
POI的主要结构:
HSSF - 提供读写Microsoft Excel格式档案的功能。
XSSF - 提供读写Microsoft Excel OOXML格式档案的功能。
HWPF - 提供读写Microsoft Word格式档案的功能。
HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
HDGF - 提供读写Microsoft Visio格式档案的功能。使用方式
Apache POI官网上提供了详细的使用说明文档,具体接口如下图所示。
我们可以从QuickGuide中快速的学会如何使用POI。
首先新建一个java工程,将POI的jar包都导入到项目里面,目录结构如下图:
因为功能比较简单,我也就没有划分为多个java文件,下面是主要的功能Test类,实现了从Excel不同的sheet中读取数据并将数据写会Excel中
package sxd.learn.java;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
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.usermodel.WorkbookFactory;
public class Test {
public static void main(String[] args) {
new Test().run(args[0]);
}
public void run(String filePath) {
Workbook wb = null;
try {
InputStream inp = new FileInputStream(filePath);
wb = WorkbookFactory.create(inp);
} catch (EncryptedDocumentException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
System.out.println("文件未找到!");
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
}
List<BSPoint> listSheet2 = readBSPointFromSheet2(wb);
Sheet sheet1 = wb.getSheetAt(0);
int NUM = sheet1.getLastRowNum();
float progress = 0.0f;
for (int rowNum = 1; rowNum <= NUM; rowNum++) {
Row row = sheet1.getRow(rowNum);
double lon1 = row.getCell(2).getNumericCellValue();
double lat1 = row.getCell(3).getNumericCellValue();
List<Dis> disList = new ArrayList<Dis>();
for (BSPoint point : listSheet2) {
double lon2 = point.getLon();
double lat2 = point.getLat();
double dis = Utils.Distance(lon1, lat1, lon2, lat2);
if(dis != 0)
disList.add(new Dis(dis,
point.getName()));
Collections.sort(disList); //排序
}
/**
* 计算出的数据写入到该行的指定位置(没有实际写到文件中)
*/
writeExcel(row, disList);
progress = (float)(rowNum*1.0 / NUM) * 100;
// Utils.updateProgress(String.valueOf(progress).length());
Utils.showProgress(progress);
// System.out.printf("第%d列,%.2f已经处理完成...", rowNum + 1, (rowNum*1.0 / NUM) * 100);
}
/*
* 写到文件中
* 只有关闭输出流,才能将更改写入到Excel中
*/
try {
FileOutputStream fileOut = new FileOutputStream(filePath);
wb.write(fileOut);
fileOut.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 从sheet2中取出所有的4G基站的位置数据
*/
public List<BSPoint> readBSPointFromSheet2(Workbook wb) {
List<BSPoint> list = new ArrayList<BSPoint>();
Sheet sheet2 = wb.getSheetAt(1);
for (int rowNum = 1; rowNum <= sheet2.getLastRowNum(); rowNum++) {
Row row = sheet2.getRow(rowNum);
list.add(new BSPoint(rowNum, row.getCell(1).getStringCellValue(),
row.getCell(2).getNumericCellValue(), row.getCell(3)
.getNumericCellValue()));
}
return list;
}
public void writeExcel(Row row, List<Dis> disList) {
Cell cellDis = row.getCell(4);
Cell cellName = row.getCell(5);
if (cellDis == null) {
cellDis = row.createCell(4);
cellName = row.createCell(5);
}
cellDis.setCellType(Cell.CELL_TYPE_NUMERIC);
cellName.setCellType(Cell.CELL_TYPE_STRING);
cellDis.setCellValue(disList.get(0).getDis());
cellName.setCellValue(disList.get(0).getName());
cellDis = row.getCell(6);
cellName = row.getCell(7);
if (cellDis == null){
cellDis = row.createCell(6);
cellName = row.createCell(7);
}
cellDis.setCellType(Cell.CELL_TYPE_NUMERIC);
cellName.setCellType(Cell.CELL_TYPE_STRING);
cellDis.setCellValue(disList.get(1).getDis());
cellName.setCellValue(disList.get(1).getName());
cellDis = row.getCell(8);
cellName = row.getCell(9);
if (cellDis == null){
cellDis = row.createCell(8);
cellName = row.createCell(9);
}
cellDis.setCellType(Cell.CELL_TYPE_NUMERIC);
cellName.setCellType(Cell.CELL_TYPE_STRING);
cellDis.setCellValue(disList.get(2).getDis());
cellName.setCellValue(disList.get(2).getName());
}
class BSPoint {
private Integer id; // 行
private double lon; // 经度
private double lat; // 纬度
private String name; // 基站名
public BSPoint(Integer id, String name, double lon, double lat) {
this.id = id;
this.name = name;
this.lon = lon;
this.lat = lat;
}
public Integer getId() {
return id;
}
public double getLon() {
return lon;
}
public double getLat() {
return lat;
}
public String getName() {
return name;
}
}
class Dis implements Comparable<Dis> {
private double dis;
private String name;
public Dis(double dis, String name) {
this.dis = dis;
this.name = name;
}
public double getDis() {
return dis;
}
public String getName() {
return name;
}
@Override
public int compareTo(Dis o) {
// TODO Auto-generated method stub
return this.dis > o.dis ? 1 : -1;
}
}
}
值得注意的是Excel的写入完成是在关闭输出流后!!!
下面的是Utils类,计算两个经纬度之间的距离。
package sxd.learn.java;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class Utils {
/**
* 计算地球上任意两点(经纬度)距离
*
* @param long1
* 第一点经度
* @param lat1
* 第一点纬度
* @param long2
* 第二点经度
* @param lat2
* 第二点纬度
* @return 返回距离 单位:米
*/
public static double Distance(double long1, double lat1, double long2,
double lat2) {
double a, b, R;
R = 6378137; // 地球半径
lat1 = lat1 * Math.PI / 180.0;
lat2 = lat2 * Math.PI / 180.0;
a = lat1 - lat2;
b = (long1 - long2) * Math.PI / 180.0;
double d;
double sa2, sb2;
sa2 = Math.sin(a / 2.0);
sb2 = Math.sin(b / 2.0);
d = 2
* R
* Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1)
* Math.cos(lat2) * sb2 * sb2));
return d;
}
public static void showProgress(float value) {
System.out.printf("<<<%.2f%%>>>\n", value);
}
public static void updateProgress(int num) {
for (int i = 0; i < num; i++) {
System.out.print("\b");
}
}
public static void removeDuplicate(List list) {
HashSet h = new HashSet(list);
list.clear();
list.addAll(h);
}
public static void removeDuplicateWithOrder(List list) {
Set set = new HashSet();
List newList = new ArrayList();
for (Iterator iter = list.iterator(); iter.hasNext();) {
Object element = iter.next();
if (set.add(element))
newList.add(element);
}
list.clear();
list.addAll(newList);
}
}