天天看點

日常踩坑簡史:最近公司項目接觸到需要從遠端FTP伺服器中解析檔案資料,【FTP工具類】提供FTP伺服器的連接配接, 查找檔案目錄,及讀取檔案内容等操作

前言

這是我畢業後工作生涯的第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;
    }
}
           

繼續閱讀