簡介
最近一個朋友讓我幫他處理一個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);
}
}