日常踩坑简史:最近公司项目接触到需要从远程FTP服务器中解析文件数据,【FTP工具类】提供FTP服务器的连接, 查找文件目录,及读取文件内容等操作

本文分享了作者在工作第60天接触的一个气象项目经验,详细介绍了如何使用FTP工具类连接服务器,读取Netcdf和Dat文件,并提供了Netcdf和Dat文件的解析方法,包括关键代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

这是我毕业后工作生涯的第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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值