C# 读写nc格式文件


发现C#没有一个很好用的库来处理nc文件,找资料花了不少时间,记录一下使用方法。两种方式,前者更纯净一些,但也太底层了,使用很麻烦; 后者封装的比较好,代码简洁,但生成出来的文件有默认生成的内容(自己还在摸索中)。

前提

都需要nuget安装SDSLite库,然后再把附件中的几个dll文件与程序放一起。
参考:
参考文档 Introduction to Scientific DataSet

方法1

1.1 写文件

 public static void write_nc_test()
 {
     //创建文件
     string filename = "newFile.nc";
     int ncid, status;
     status = NetCDF.nc_create(filename, CreateMode.NC_WRITE, out ncid);

     //定义维度(dimensions)
     int dim1_id, dim2_id;
     int dim1_len = 5;
     int dim2_len = 6;
     IntPtr dim1_len_intp = new IntPtr(dim1_len);
     IntPtr dim2_len_intp = new IntPtr(dim2_len);
     status = NetCDF.nc_def_dim(ncid, "dim1", dim1_len_intp, out dim1_id);
     status = NetCDF.nc_def_dim(ncid, "dim2", dim2_len_intp, out dim2_id);

     //定义变量
     int varid;
     int[] dimids = new int[] { dim1_id, dim2_id };
     status = NetCDF.nc_def_var(ncid, "Q", NcType.NC_FLOAT, dimids, out varid);

     //关闭定义模式
     status = NetCDF.nc_enddef(ncid);

     //向变量中存入数据
     float[] data = new float[dim1_len * dim2_len];
     for (int i = 0; i < data.Length; i++)
     {
         data[i] = (float)((i + 1) * 1.0);
     }
     System.IntPtr start_intp = new IntPtr(0);
     System.IntPtr[] start = new IntPtr[] { start_intp, start_intp };
     System.IntPtr[] count = new IntPtr[] { dim1_len_intp, dim2_len_intp };
     status = NetCDF.nc_put_vara_float(ncid, varid, start, count, data);

     //关闭文件
     status = NetCDF.nc_close(ncid);
 }

1.2 读文件

注意:原始读取出来的数是一维的,还需要二次处理

 public static void read_nc_test()
 {
     //打开文件
     string filename = "newFile.nc";  //"etp.nc";
     int ncid, status;
     status = NetCDFInterop.NetCDF.nc_open(filename, CreateMode.NC_NOWRITE, out ncid);
     if (status != 0) { Console.WriteLine("无法打开文件"); return; }

     //文件里有几个变量
     int nvars;
     int[] varids = new int[6];
     status = NetCDFInterop.NetCDF.nc_inq_varids(ncid, out nvars, varids);

     //各变量的信息
     string varName = "";
     NcType nctype;
     int ndims, natts;
     int[] nd = new int[4];
     for (int i = 0; i < nvars; i++)
     {
         status = NetCDFInterop.NetCDF.nc_inq_var(ncid, varids[0], out varName, out nctype, out ndims, nd, out natts);
         Console.WriteLine("变量{0}是:{1}", i + 1, varName);
     }

     // 查询数据长度
     int dim1_id, dim2_id;
     IntPtr dim1_len_ptr, dim2_len_ptr;
     NetCDFInterop.NetCDF.nc_inq_dimid(ncid, "dim1", out dim1_id);
     NetCDFInterop.NetCDF.nc_inq_dimlen(ncid, dim1_id, out dim1_len_ptr);
     NetCDFInterop.NetCDF.nc_inq_dimid(ncid, "dim2", out dim2_id);
     NetCDFInterop.NetCDF.nc_inq_dimlen(ncid, dim2_id, out dim2_len_ptr);

     //查询数据  (只能查询出一维数组,还需要二次处理)
     System.IntPtr start_intp = new IntPtr(0);
     System.IntPtr[] start = new IntPtr[] { start_intp, start_intp };
     System.IntPtr[] count = new IntPtr[] { dim1_len_ptr, dim2_len_ptr };
     float[] data = new float[dim1_len_ptr.ToInt32() * dim2_len_ptr.ToInt32()];
     status = NetCDFInterop.NetCDF.nc_get_vara_float(ncid, varids[0], start, count, data);
     
     // 对一维数组的处理

     //关闭文件
     NetCDFInterop.NetCDF.nc_close(ncid);
 }

方法2

using Microsoft.Research.Science.Data;
using Microsoft.Research.Science.Data.Imperative;

2.1 写文件

public static void write_nc(string nc_file)
{
    using (DataSet ds = DataSet.Open($"msds:nc?file={nc_file}&openMode=create"))
    {
        double[] data = new double[10];
        ds.AddVariable<double>("DATA", data, "x");
        //ds.Add<double[]>("Data","x");  //或者可以用这两行
        //ds.PutData<double[]>("Data", data);
    }
}

2.2 读文件

语法非常简洁!

public static void read_nc(string nc_file)
{
    using (DataSet ds = DataSet.Open($"msds:nc?file={nc_file}&openMode=readOnly"))
    {
        var data = ds.GetData<float[,]>("Data");  
        //Console.WriteLine(ds);
        //Console.WriteLine("name:" + ds.Variables[0].Name);
        //Console.WriteLine(ds.Metadata["comment"]);
    }
}

踩坑记录

如果显示如下错误,把 msvcr100.dll 也放到程序目录里,或者安装Visual C++ Redistributable。

Unhandled exception. Microsoft.Research.Science.Data.DataSetCreateException: Failed to create DataSet instance from uri msds:nc?file=par.nc&openMode=readOnly: Unable to load DLL ‘netcdf’ or one of its dependencies: 找不到指定的模块。 (0x8007007E)
—> System.DllNotFoundException: Unable to load DLL ‘netcdf’ or one of its dependencies: 找不到指定的模块。 (0x8007007E)

写入全局属性

// 全局属性  (要在nc_enddef之前;varid是-1)
status = NetCDF.nc_put_att_text(ncid, -1, "Date", "2021/1/1");
if (status != 0)
    throw new Exception("写入属性失败: " + NetCDF.nc_strerror(status));
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值