NetCDF简介 NetCDF(network Common Data Format),即网络通用数据格式。最早是由美国国家科学委员会资助之计划–Unidata –所发展,其用意是在Unidata计划中不同的应用项目下,提供一种可以通用的数据存取方式,数据的形状包括单点的观测值、时间序列、规则排列的网格、以及人造卫星或雷达之影像档案。 NetCDF 可简单的视为一种存取接口,任何使用 NetCDF 存取格式的档案就可称为 NetCDF 档案;至于 NetCDF 这套软件的功能,在于提供C、Fortran、C++、Perl、或其它语言I/O的链接库,以让程序发展者可以读写数据文件,其本身具有说明的能力、并且可以跨越平台和机器的限制。每一个NetCDF档案可以含括多维度的、具有名称的变量,包括长短的整数、单倍与双倍精度的实数、字符等,且每一个变量都有其自我介绍的数据,包括量度的单位、全名及意义等文字说明,在此摘要性的檔头之后,才是真正的数据本身。 NetCDF接口是一种多维的数据分布系统,由这个接口所产生的档案,具有多维的数据格式,当你需要其中的某一笔数据时,程序将不会从第一笔数据读到你所需要的数据处,而是由 NetCDF 软件直接存取那一个数据。如此一来将会大量的降低模式运算时数据存取的时间。但也就是因为这样, NetCDF 所需要的空间是很大的,因为他多了很多的自解释的申明。

 

 NetCDF文件结构

   

对NETCDF文件的操作主要有读和写两个方面,在了解这两个方面内容之前,首先需要了解NETCDF文件的结构,NETCDF文件主要是Dimensions, Variables, Attributes, Data 四个部分组成的:

Dimensions主要是多维资料的结构,如经度、纬度、时间等

Variables各种变量,像温度等 Attributes一些辅助记忆的说明,如变量的单位等

Data主要资料部分

 

下面是NETCDF文件基本结构图(箭头指向为可操作的对象)

NETCDF文件基本结构图根据NETCDF文件的这种特殊的结构,所使用的NcFile类中包含了NcDim, NcVar, NcAtt几个类的对象作为成员,分别对应了上面的Dimensions, Variables, Attributes部分。

NetCDF文件的读写  

1.1     建工程文件用

vc6建立一个工程,使用动态链接库netcdf,然后把文件netcdfcpp.h netcdfcpp.cpp ,ncvalues.h ncvalues.cpp,ncconfig.h包含到工程中。

1.2     NETCDF文件的读取

首先,定义一个NcFile类的对象,用NcFile类的构造函数直接对其初始化 NcFile(const char * path, FileMode = ReadOnly , … … );

path为文件的存储路径,FileMode为文件的打开方式,除了ReadOnly还有Write, New, Replace 等方式我们只是读文件可以选择ReadOnly,其他方式后面会介绍到,其他参数可以使用默认值,例如: NcFile nc("G://File.nc", NcFile::ReadOnly);

使用nc.is_valid()来判断文件打开是否成功,以便进行下一步对NETCDF文件数据进行读取。  

NETCDF文件主要是Dimensions, Variables, Attributes, Data 四个部分组成的,下面读出文件各个部分的内容。   

    Dimensions:  

可以使用NETCDF 的成员函数num_dims()获得文件中的Dimensions的个数,然后用NcFile类的另一个成员函数get_dim(int id),或get_dim(NcToken name)—参数可以是id号(int),也可以是dim名字(NcToken),获得每一个文件的Dimensions,用NcDim类的成员函数id(),name(),size()可以依次读出每一个Dimensions的id号,名称,和size。

例如:  

  for (int i=0;i<nc.num_dims()-1;i++)   

 { 

          String.Format(String+"dimid=%d   name=%s length=%d/n",nc.get_dim(i)->id(),

          nc.get_dim(i)->name(),nc.get_dim(i)->size());   

}    

利用一个for循环,依据dim的id号可以一次读出所有dim的信息    

     Variables:       

      同理用NETCDF 的成员函数num_vars()可以获得文件中Variables数量,用NcFile类get_var(int id)或 get_var(NcToken name)可以读出每一个文件中的Variables,也可以读出id,name这些信息,所不同的是,Variables还可以用num_dims()读出其所包含的Dimensions的个数,Variables还可以用get_dim(int id)读出其包含的Dimensions的相关信息,同时文件的Data信息也是通过Variables来操作的。

       Data的读出:            

         首先,我们要根据Variables包含的每一个Dimensions的size计算出数据的大小,定义一个相应大小的数组,用来存放数据。                    

         然后,用Variables的get(TYPE *array,long *num)第一个参数是刚才定义的存放数据的数组,第二个参数是自定义的一维数组,数组的元素用来存放每一维的size.一般用于多维数据。

例如:

             float rhs[50];

             long array[3];

             array[0]=1;

             array[1]=5;

             array[2]=10;

              nc.get_var("rh")->get(rhs,array);

              还可以用Variables的get( TYPE* vals,long edge0=0,long edge1=0,long edge2=0,long edge3=0,long edge4=0) const 第一个参数是存放数据的数组,后面的参数分别记录第1,2,3,4,5维的size,默认值为0,

例如:

                    int n=nc.get_dim("lat")->size();

                    int lats[5];

                   nc.get_var("lat")->get(lats,n);

                    for (i=0;i<5;i++)

                   {  

                          String.Format(String+"    %d",lats[i]);

                    }

            如果Variables中还包含说明的Attributes,可以使用函数get_att(int id),参数为Attributes的id,读出其Attributes。

例如:

             String.Format("/natt:/n%s:%s/n",nc.get_var(0)->get_att(0)->name(),

                 nc.get_var(0)->get_att(0)->as_string(0));

       Attributes:

           Attributes可分为两种一种是整个文件的说明,即global attributes可以通过NcFile类的get_att(int id)函数来获得,参数为id号,

例如:

    String.Format(String+"/n%s: %s",nc.get_att(0)->name(),nc.get_att(0)->as_string(0));

还有一种是的说明,可以通过在Variables说明的方法获得,从读出的信息主要包括名称和相应的内容,可以通过name()和as_Type(long id),Type根据Attributes数据的类型来确定,如as_string(long id),as_int(long id)等,as_Type(long id)函数主要是用来取出每个Variables的内容。例子在Variables后面。          

       Data:           

  通过Variables我们已经把数据读出。

 1.3     NETCDF文件的写入

和读文件时一样,首先要定义一个NcFile类的对象,

如:

 NcFile nc("G://File.nc", NcFile:: Replace);

用nc.is_valid()来判断文件打开是否成功,文件的打开方式我们可以选择New建立一个新的文件,用这种方式如果文件已经存在会返回错误,也可以用Write和Replace。选择Replace,如果文件已存在原文件就会被覆盖掉。用Write时文件必须已经存在,写入文件的数据会加在文件已存在数据的后面。

     首先,建立一个NETCDF文件,需要写入的数据和刚才读出的数据是一样的,有Dimensions, Variables, Attributes, Data;

 Dimensions:

用NcFile类的add_dim(NcToken name,long dimsize)成员函数加入Dimensions,如果size 为unlimited用NcFile类的add_dim(NcToken name)函数,NcFile类会自动把其size处理为unlimited。

例如:

 nc.add_dim("lat",5);

nc.add_dim("time");//size 为unlimited时  

Variables:

用NcFile类的add_var(NcToken name,NcType type,type dim1,type dim2,… …)成员函数加入Variables,dim1,…,dimn,为Variables中包含的Dimensions。

 例如:

 nc.add_var("lat",ncInt,nc.get_dim(0));//一个dim时

 nc.add_var("rh",ncFloat,nc.get_dim("time"),

 nc.get_dim("lat"),nc.get_dim("lon"));//多个dim时

 Attributes:

整个文件的Attributes用NcFile的add_att(NcToken attname,Type value)函数Type根据加入Attributes的类型来判断;Variables可以用其成员函数add_att(attname, Type value)加入。

例如:

      //写入文件的主要参数

     nc.add_att("sourse","Fictional Model Output");

     //写入单个变量的参数

     nc.get_var(0)->add_att("long_name","Temperature");

   Data:

先定义一个数组,把要写入文件的数据写入数组,用 Variables的函数put(TYPE *arr,const long *count)TYPE 为数据类型或Variable的函数put( TYPE* vals,long edge0=0,long edge1=0,long edge2=0,long edge3=0,long edge4=0) const,第一个参数是存放数据的数组,后面的参数分别记录第1,2,3,4,5维的size,默认值为0,例如:

    int lats[5]={20,30,40,50,60};                             //lat

    nc.get_var("lat")->put(lats,5);

     float rhss[50];     for (int i=0;i<1;i++)

        for (int j=0;j<5;j++)

            for (int k=0;k<10;k++)

            {

                rhss[i*5*10+j*10+k]= (float)(i*5*10+j*10+k+1)/100; 

            }

     long count[3];                   //由于rh有多个dim,要定义一个一维数组

     count[0] = 1;                    //来说明其每一维的size

     count[1] = 5;

     count[2] = 10;

     nc.get_var("rh")->put(rhss,count);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

netcdf入门

作者:laomai

审核者: ybb

转载时请注明出处: http://blog.csdn.net/laomai

最近在做一个和数据采集有关的项目,里面用到了netcdf库,大致看了一下,这里把心得写出来,供后来者参考。一、概述  NetCDF全称为network Common Data Format,中文译法为“网络通用数据格式”,

对程序员来说,它和zip、jpeg、bmp文件格式类似,都是一种文件格式的标准。netcdf文件开始的目的是用于存储气象科学中的数据,现在已经成为许多数据采集软件的生成文件的格式。  

 从数学上来说,netcdf存储的数据就是一个多自变量的单值函数。用公式来说就是f(x,y,z,…)=value, 函数的自变量x,y,z等在netcdf中叫做维(dimension)或坐标轴(axix),函数值value在netcdf中叫做变量(Variables).而自变量和函数值在物理学上的一些性质,比如计量单位(量纲)、物理学名称等等在netcdf中就叫属性(Attributes).

二、netcdf的下载

 netcdf的是官方网站为http://www.unidata.ucar.edu/software/netcdf/。

 在本文中,我们主要讨论在windows平台上使用netcdf软件库。我们将要从这个网站上下载如下资源

⑴netcdf的源代码,目前的地址为 

ftp://ftp.unidata.ucar.edu/pub/netcdf/netcdf-4/netcdf-beta.tar.gz

⑵netcdf的在windows平台预编译好的dll,地址为 

ftp://ftp.unidata.ucar.edu/pub/netcdf/contrib/win32/netcdf-3.6.1-win32.zip 

解压后里面有如下东西 

netcdf.dll  为编译好的dll 

ncgen.exe  为生成netcdf文件的工具 

ncdump.exe 为读取netcdf文件的工具 

netcdf.lib 和 netcdf.exp在编程时会用到,后面会讲。

⑶netcdf的相关文档,包括 

①netcdf的用户手册,下载地址为http://www.unidata.ucar.edu/software/netcdf/docs/netcdf.pdf  

②netcdf的入门教程, 下载地址为http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial.pdf 

③netcdf的c接口api手册,下载地址为http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c.pdf 

下面我们来看netcdf文件的具体内容。

三、netcdf文件的内容

一个netcdf文件的结构包括以下对象:

1、变量(Variables)  

 变量对应着真实的物理数据。比如我们家里的电表,每个时刻显示的读数表示用户的到该时刻的耗电量。这个读数值就可以用netcdf里的变量来表示。它是一个以时间为自变量(或者说自变量个数为一维)的单值函数。再比如在气象学中要作出一个气压图,就是“东经xx度,北纬yy度的点的大气压值为多少帕”,这是一个二维单值函数,两维分别是经度和纬度。函数值为大气压。

   从上面的例子可以看出,netcdf中的变量就是一个N维数组,数组的维数就是实际问题中的自变量个数,数组的值就是观测得到的物理值。变量(数组值)在netcdf中的存储类型有六种,ascii字符(char) ,字节(byte), 短整型(short), 整型(int), 浮点(float), 双精度(double). 显然这些类型和c中的类型一致,搞C的朋友应该很快就能明白。

2、维(dimension)  

 一个维对应着函数中的某个自变量,或者说函数图象中的一个坐标轴,在线性代数中就是一个N维向量的一个分量(这也是维这个名称的由来)。在netcdf中,一个维具有一个名字和范围(或者说长度,也就是数学上所说的定义域,可以是离散的点集合或者连续的区间)。在netcdf中,维的长度基本都是有限的,最多只能有一个具有无限长度的维。

3、属性(Attribute)  

属性对变量值和维的具体物理含义的注释或者说解释。因为变量和维在netcdf中都只是无量纲的数字,要想让人们明白这些数字的具体含义,就得靠属性这个对象了。

   在netcdf中,属性由一个属性名和一个属性值(一般为字符串)组成。比如,在某个cdl文件(cdl文件的具体格式在下一节中讲述)中有这样的代码段 

  temperature:units = "celsius" ; 

      前面的temperature是一个已经定义好的变量(Variable),即温度,冒号后面的units就是属性名,表示物理单位,=后面的就是units这个属性的值,为“celsius” ,即摄氏度,整个一行代码的意思就是温度这个物理量的单位为celsius,很好理解。

三、CDL结构

   CDL全称为network Common data form Description Language,它是用来描述netcdf文件的结构的一种语法格式。它包括前面所说的三种netcdf对象(变量、维、属性)的具体定义。看一个具体例子(这个例子cdl文件是从netcdf教程中的2.1 节The simple xy Example摘出来的)

 netcdf simple_xy {

dimensions:

x = 6 ;

y = 12 ;

variables:int data(x, y) ;

data:

data =

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,

12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,

24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,

36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,

48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,

60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71 ;

}

上面的代码定义了一个符合netcdf格式的结构simple_xy, 

 这个结构包括三个部分

1、维的定义,以dimensions:关键字开头

   dimensions:

 x = 6 ;

 y = 12 ; 

定义了两个轴(或者说两维),名字分别为x和y,x轴的长度(准确的说是坐标点的个数)为6, y轴的长度为12。

2、变量的定义:以variables:开头

 variables:

  int data(x, y); 

 定义了一个以x轴和y轴为自变量的函数data,数学公式就是f(x,y)=data;  注意维出现的顺序是有序的,它决定data段中的具体赋值结果.

3、数据的定义,以data:开头

 data:

data =

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,

12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,

24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,

36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,

48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,

60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71 ;

这个段数据用数学的函数公式f(x,y)=data来看,就是 

 x=0,y=0时,data = 0;

     x=0,y=1时,data = 1;

               x=5,y=11是,data=71

;要注意的是,

1、赋值顺序:

我们给出的是c格式的cdl文件,因此这里的赋值顺序和c语言中的一致,也就是通常所说的“行式赋值”,而fortran语言中则是“列式赋值”,因此在fortran格式的cdl文件中,data段的数值顺序和这里正好行列互换。     

2、自变量的默认取值和坐标变量 

  如果只给出维的长度,那么维的值默认从0开始,然后自动加1,到(长度-1)停止,   很多情况下我们要自己给出每个点的坐标值,这时就需要用到netcdf里的坐标变量   "coordinate varibles":增加一个和只和维相关的一元函数(自变量)并给出它的取值范围。  

比如下面的cdl文件(摘自netcdf教程中的2.2 The sfc pres temp Example)

   netcdf sfc_pres_temp {

 dimensions: latitude = 6 ;        //纬度轴

 longitude = 12 ;      //经度轴 

variables:

 float latitude(latitude) ;    //坐标变量,存储具体纬度

 latitude:units = "degrees_north" ;

 float longitude(longitude) ;  //坐标变量,存储具体纬度

 longitude:units = "degrees_east" ; 

float pressure(latitude, longitude) ;   //某个点(经度和纬度的交点)的大气压值

 pressure:units = "hPa" ;           //大气压的单位为

 float temperature(latitude, longitude) ; //某个点(经度和纬度的交点)的温度值

 temperature:units = "celsius" ;    //温度的单位为 

data:

 latitude = 25, 30, 35, 40, 45, 50 ; 

longitude = -125, -120, -115, -110, -105, -100, -95, -90, -85, -80, -75, -70 ; 

pressure = 

900, 906, 912, 918, 924, 930, 936, 942, 948, 954, 960, 966,

901, 907, 913, 919, 925, 931, 937, 943, 949, 955, 961, 967, 

902, 908, 914, 920, 926, 932, 938, 944, 950, 956, 962, 968, 

903, 909, 915, 921, 927, 933, 939, 945, 951, 957, 963, 969, 

904, 910, 916, 922, 928, 934, 940, 946, 952, 958, 964, 970, 

905, 911, 917, 923, 929, 935, 941, 947, 953, 959, 965, 971 ; 

temperature = 

9, 10.5, 12, 13.5, 15, 16.5, 18, 19.5, 21, 22.5, 24, 25.5, 

9.25, 10.75, 12.25, 13.75, 15.25, 16.75, 18.25, 19.75, 21.25, 22.75, 24.25, 25.75, 

9.5, 11, 12.5, 14, 15.5, 17, 18.5, 20, 21.5, 23, 24.5, 26, 

9.75, 11.25, 12.75, 14.25, 15.75, 17.25, 18.75, 20.25, 21.75, 23.25, 24.75, 26.25, 

10, 11.5, 13, 14.5, 16, 17.5, 19, 20.5, 22, 23.5, 25, 26.5, 

10.25, 11.75, 13.25, 14.75, 16.25, 17.75, 19.25, 20.75, 22.25, 23.75, 25.25 

对于上面的数据,就是

 latitude = 25,longitude = -125时,pressure = 900,temperature =  9; 

latitude = 25,longitude = -120时,pressure = 906,temperature =  10.5; 

以此类推。 

 

四、netcdf文件的读写  

“学以致用” ,前面讲的都是netcdf的基本知识,都是为了本节的核心问题——读写netcdf格式的文件做铺垫之用,下面我们就来看看如何建立一个netcdf格式文件,以及如何再读出它的内容。

1、在命令行下读写netcdf文件 

⑴建立一个simple_xy.cdl文件,内容就是上一节“CDL结构”中的第一个例子。 

⑵用ncgen.exe工具(下载地址见前面的第二节)建立netcdf文件   

     ①将ncgen所在目录加到系统path变量中或者直接将ncgen.exe拷到simple_xy.cdl所在目录下   

     ②执行ncgen -o simple_xy.nc simple_xy.cdl生成netcdf格式文件simple_xy.nc 

⑶生成的simple_xy.nc是一个二进制文件,要想从这个文件中还原出数据信息,就要用ncdump工具

     ①将ncdump所在目录加到系统path变量中或者直接将ncdump.exe拷到simple_xy.nc所在目录下

     ②在命令行下执行ncdump simple_xy.nc,这时屏幕的输出和simple_xy.cdl内容完全一样。说明     我们的文件读写操作都是正确的。 

2、编程读写netcdf文件

 前面我们知道如何手工去建立和读取netddf文件,下面我们来看看如何在程序中用代码实现netcdf文件的建立和分析。我的编程环境为win2000+vc6.0 并安装了vc sp6补丁包。例子代码选自netcdf教程中的2.1节The simple xy Example

⑴将netcdf的源代码解压。我们将用到里面的libsrc/netcdf.h头文件

⑵在vc6中建立一个空的win32控制台项目.名字为SimpleXyWrite,这个项目用来建立netcdf文件

⑶把如下文件拷贝到项目目录中

    ①netcdf源代码中的libsrc/netcdf.h头文件

    ②netcdf源代码中的examples/C/simple_xy_wr.c文件,并改名为simple_xy_wr.cpp

    ③netcdf预编译包中的netcdf.dll文件和 netcdf.lib文件

⑷把netcdf.h文件和simple_xy_wr.cpp加入到项目的文件列表中

  (具体菜单操作project->add to project->files)

⑸把netcdf.lib加入到项目的lib列表中

 (具体菜单操作project->add to project->settings->Link->object/library modules)

⑹编译并运行这个项目,会在项目目录下生成一个simple_xy.nc文件,其内容和我们手工生成的文件内容完全一样。

simple_xy_wr.c文件是建立netcdf文件的c代码,而examples/C/simple_xy_rd.c文件则是分析netcdf文件的代码,读者可以用和刚才类似的步骤在vc6中编译这个文件。运行时把把刚才生成的simple_xy.nc拷贝到项目的目录下,如果文件格式没错误,会提示

*** SUCCESS reading example file simple_xy.nc!

然后退出。

3、用ncgen命令自动生成c代码 

给定了simple_xy.cdl文件后,可以用 

 ncgen -c  simple_xy.cdl 

 命令直接在屏幕上输出c代码. 

 不过,这个办法只限于cdl的数据比较简单时才可以采用。对于真正的项目,

 是需要我们自己去编写代码的。

  五、小结

 通过以上内容的介绍,相信读者对netcdf已经有了大致的了解。总体来说,netcdf的核心内容就是通过cdl描述文法来建立一个netcdf格式文件。抓住了这一点,读者再继续深入看netcdf的其他资料时,应该就没什么太大的难度了。如是,作者的目的也就达到了。

六、附录

为便于读者对照,现本文中用到的几个文件的内容在此列出

1、simple_xy.cdl文件的内容

netcdf simple_xy {

dimensions:

x = 6 ;

y = 12 ;

variables:

int data(x, y) ;

data:

data =

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,

12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,

24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,

36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,

48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,

60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71 ;

}

2、simple_xy-wr.c文件的内容

/* This is part of the netCDF package.

   Copyright 2006 University Corporation for Atmospheric Research/Unidata. 

  See COPYRIGHT file for conditions of use.

 

   This is a very simple example which writes a 2D array of

   sample data. To handle this in netCDF we create two shared

   dimensions, "x" and "y", and a netCDF variable, called "data".

 

   This example demonstrates the netCDF C API. This is part of the

   netCDF tutorial, which can be found at:

   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial  

   Full documentation of the netCDF C API can be found at:  

  http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

 

   $Id: simple_xy_wr.c,v 1.12 2007/02/14 20:59:21 ed Exp $

*/

#include <stdlib.h>

#include <stdio.h>

#include <netcdf.h>

/* This is the name of the data file we will create. */

#define FILE_NAME "simple_xy.nc"

/* We are writing 2D data, a 6 x 12 grid. */

#define NDIMS 2

#define NX 6

#define NY 12

/* Handle errors by printing an error message and exiting with a * non-zero status. */

#define ERRCODE 2

#define ERR(e)

 {printf("Error: %s/n", nc_strerror(e)); exit(ERRCODE);}

int

main()

{

   /* When we create netCDF variables and dimensions, we get back an

    * ID for each one. */

   int ncid, x_dimid, y_dimid, varid;

   int dimids[NDIMS];

   /* This is the data array we will write. It will be filled with a

    * progression of numbers for this example. */

   int data_out[NX][NY];

   /* Loop indexes, and error handling. */

   int x, y, retval;

   /* Create some pretend data. If this wasn't an example program, we

    * would have some real data to write, for example, model

    * output. */

   for (x = 0; x < NX; x++)

      for (y = 0; y < NY; y++)

  data_out[x][y] = x * NY + y;

   /* Always check the return code of every netCDF function call. In

    * this example program, any retval which is not equal to NC_NOERR

    * (0) will cause the program to print an error message and exit

    * with a non-zero return code. */

   /* Create the file. The NC_CLOBBER parameter tells netCDF to

    * overwrite this file, if it already exists.*/

   if ((retval = nc_create(FILE_NAME, NC_CLOBBER, &ncid)))

      ERR(retval);

   /* Define the dimensions. NetCDF will hand back an ID for each. */

   if ((retval = nc_def_dim(ncid, "x", NX, &x_dimid)))

      ERR(retval);

   if ((retval = nc_def_dim(ncid, "y", NY, &y_dimid)))

      ERR(retval);

   /* The dimids array is used to pass the IDs of the dimensions of

    * the variable. */

   dimids[0] = x_dimid;

   dimids[1] = y_dimid;

   /* Define the variable. The type of the variable in this case is 

   * NC_INT (4-byte integer). */

   if ((retval = nc_def_var(ncid, "data", NC_INT, NDIMS,

        dimids, &varid)))

      ERR(retval);

   /* End define mode. This tells netCDF we are done defining

    * metadata. */

   if ((retval = nc_enddef(ncid)))

      ERR(retval);

   /* Write the pretend data to the file. Although netCDF supports 

    * reading and writing subsets of data, in this case we write all

    * the data in one operation. */

   if ((retval = nc_put_var_int(ncid, varid, &data_out[0][0])))

      ERR(retval);

   /* Close the file. This frees up any internal netCDF resources

    * associated with the file, and flushes any buffers. */

   if ((retval = nc_close(ncid)))

      ERR(retval);

   printf("*** SUCCESS writing example file simple_xy.nc!/n");

   return 0;

}

3、simple_xy_rd.c文件的内容

/* This is part of the netCDF package.

   Copyright 2006 University Corporation for Atmospheric Research/Unidata.

   See COPYRIGHT file for conditions of use.

   This is a simple example which reads a small dummy array, which was

   written by simple_xy_wr.c. This is intended to illustrate the use

   of the netCDF C API.

   This program is part of the netCDF tutorial:

   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

   Full documentation of the netCDF C API can be found at:   

  http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

   $Id: simple_xy_rd.c,v 1.9 2006/08/17 23:00:55 russ Exp $

*/

#include <stdlib.h>

#include <stdio.h>

#include <netcdf.h>

/* This is the name of the data file we will read. */

#define FILE_NAME "simple_xy.nc"

/* We are reading 2D data, a 6 x 12 grid. */

#define NX 6

#define NY 12

/* Handle errors by printing an error message and exiting with a 

* non-zero status. */

#define ERRCODE 2

#define ERR(e)

{printf("Error: %s/n", nc_strerror(e)); exit(ERRCODE);}

 

int

main()

{

   /* This will be the netCDF ID for the file and data variable. */

   int ncid, varid;

   int data_in[NX][NY];

   /* Loop indexes, and error handling. */

   int x, y, retval;

   /* Open the file. NC_NOWRITE tells netCDF we want read-only access

    * to the file.*/

   if ((retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)))

      ERR(retval);

   /* Get the varid of the data variable, based on its name. */

   if ((retval = nc_inq_varid(ncid, "data", &varid)))

      ERR(retval);

   /* Read the data. */

   if ((retval = nc_get_var_int(ncid, varid, &data_in[0][0])))

      ERR(retval);

   /* Check the data. */

   for (x = 0; x < NX; x++)

      for (y = 0; y < NY; y++)

  if (data_in[x][y] != x * NY + y)

     return ERRCODE;

   /* Close the file, freeing all resources. */

   if ((retval = nc_close(ncid)))

      ERR(retval);

   printf("*** SUCCESS reading example file %s!/n", FILE_NAME);

   return 0;

}