前言
这是我毕业后工作生涯的第60天,最近接触到公司给气象局做的一个项目,我被分配到气象数据解析以及抽取模块的开发,由于涉及到气象数据的特殊性,具体是什么我就不在此赘述。而我需要做的工作是解析气象局FTP服务器上的Netcdf文件和Dat文件并提取有用数据。现将各个工具类以及问题记录一下。
应用场景
- 通过FTP连接需要获取获得指定目录下指定文件夹下的文件
- 通过FTP连接读取指定文件内容
FTP工具类:
package com.zjzy.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* FTP工具类
* @author hungkuei
*/
@Slf4j
public class FTPUtil {
/**
* 连接FTP服务器
* @param ftpHost
* @param ftpPort
* @param username
* @param password
* @return
*/
public static FTPClient connectFtpServer(String ftpHost, Integer ftpPort, String username, String password){
FTPClient ftpClient = null;
try{
ftpClient = new FTPClient();
ftpClient.connect(ftpHost, ftpPort);
ftpClient.login(username, password);
/**
* 特别提醒:connect(ftpHost, ftpPort) --> login(username, password) --> xxxx
* 一定是按照以上执行顺序设置FTP连接属性,不然会读不到文件,切记切记
* ^_^这里是我踩的坑,本地测试都很顺利,部署到服务其上就会报数据文件不存在^_^
*/
ftpClient.enterLocalPassiveMode();
ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setRemoteVerificationEnabled(false);
if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
ftpClient.disconnect();
log.info("FTP服务器拒绝连接!");
}else{
log.info("FTP服务器登录成功");
}
}catch (Exception e){
log.info("创建FTP连接失败");
e.printStackTrace();
}
return ftpClient;
}
/**
* @throws IOException function:关闭连接
*/
public static boolean closeServer(FTPClient ftpClient) {
if (ftpClient.isConnected()) {
try {
ftpClient.logout();
ftpClient.disconnect();
return true;
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 获取指定目录下指定文件名的文件
* @param ftpClient
* @param ftpPath
* @return
*/
public static List<FTPFile> getNetCdfFileFromFTP(FTPClient ftpClient, String ftpPath){
// 获得指定目录下指定文件夹下的文件
FTPFile[] ftpFiles = null;
List<FTPFile> ftpFileList = new ArrayList<>();
try {
boolean b = ftpClient.changeWorkingDirectory(ftpPath);
if (b){
log.info("开始从路径:"+ ftpPath + "读取指定格式文件");
}
if (ftpFiles != null){
for (int i = 0; i < ftpFiles.length; i++) {
FTPFile ftpFile = ftpFiles[i];
/**
* 根据实践需求自行修改
*/
if (ftpFile.isFile() && ftpFile.getName().substring(ftpFile.getName().indexOf("P")).equals("Pr01.nc")){
ftpFileList.add(ftpFile);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return ftpFileList;
}
/**
* 获取指定文件流并返回
* @param ftpClient
* @param ftpPath
* @param fileName
* @return
*/
public static InputStream getDatFileStreamFromFTP(FTPClient ftpClient, String ftpPath, String fileName){
InputStream ins = null;
try {
boolean b = ftpClient.changeWorkingDirectory(ftpPath);
if (b){
log.info("开始从路径:"+ ftpPath + "读取文件:" + fileName);
}
ins = ftpClient.retrieveFileStream(fileName);
return ins;
} catch (IOException e) {
e.printStackTrace();
}
return ins;
}
}
Netcdf文件解析工具类:
package com.zjzy.util;
import lombok.extern.slf4j.Slf4j;
import ucar.ma2.Array;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.NCdumpW;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class NetCdfUtil {
public static Map<String, Array> readNetCdfFile(String filePath, String sectionSpec){
String[] split = sectionSpec.split(",");
NetcdfFile netcdfFile = null;
Map<String, Array> map = new HashMap<>();
try{
netcdfFile = NetcdfFile.open(filePath);
Variable latVar = netcdfFile.findVariable("lat");
if (latVar == null){
System.out.println("Cant find Variable latitude");
return null;
}
System.out.println();
Variable lonVar = netcdfFile.findVariable("lon");
if (lonVar == null){
System.out.println("Cant find Variable lonitude");
return null;
}
Array latArray = latVar.read(split[0]);
map.put("lat", latArray);
Array lonArray = lonVar.read(split[1]);
map.put("lon", lonArray);
System.out.println(NCdumpW.printArray(latArray, "lat", null));
System.out.println(NCdumpW.printArray(lonArray, "lon", null));
Variable rainfall = netcdfFile.findVariable("Pr01");
if (rainfall == null){
return null;
}
Array rains = rainfall.read(sectionSpec);
map.put("rains", rains);
System.out.println(NCdumpW.printArray(rains,"Pr01",null));
} catch (IOException e) {
log.info("trying to read " + "Pr01", e);
} catch (InvalidRangeException e) {
log.info("invalid Range for " + "Pr01", e);
}
return map;
}
}
DAT文件解析工具:
package com.zjzy.util;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class DatFileUtil {
/**
* 全省经纬度范围
* 真实数据我改掉了
*/
private static Double maxLat = 00.00;
private static Double minLat = 00.00;
private static Double maxLon = 00.00;
private static Double minLon = 2500.0043;
/**
* xxx经纬度范围
*/
private static Double deqingMaxLat = 00.00;
private static Double deqingMinLat = 00.00;
private static Double deqingMaxLon = 00.00;
private static Double deqingMinLon = 00.00;
public static Map<String, Object> readDatFile(InputStream ins) {
BufferedReader br = null;
br = new BufferedReader(new InputStreamReader(ins));
Map<String, Object> data = new HashMap<>();
int index = 0;
String line;
try {
br.readLine();
br.readLine();
br.readLine();
List<List<Double>> datas = new ArrayList<>();
while ((line = br.readLine()) != null) {
if (index >= (deqingMinLon*100 - minLon*100) && index < (deqingMaxLon*100 - minLon*100)){
String[] strs = line.split(" ");
List<Double> doubles = new ArrayList<>();
for (int i = (int) (deqingMinLat*100 - minLat*100) + 1; i < (deqingMaxLat*100 - minLat*100) + 1; i++) {
if ("".equals(strs[i])) {
continue;
}
double d = Double.parseDouble(strs[i]);
doubles.add(d);
}
datas.add(doubles);
}
index++;
}
data.put("data", datas);
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
}