Это мой первый вопрос:
Я пытаюсь прочитать «глобальные атрибуты» из файла NetCDF (используя устаревший API C ++). Под «глобальным атрибутом» я подразумеваю атрибут, который был добавлен в NcFile, а не в NcVar.
Для большинства вещейПример программы netCDF«полезны — но нет примера для» глобальных атрибутов «.
Консультируясь с «netcdfcpp.h», я нахожу несколько вещей:
NcAtt* get_att(NcToken) const;
friend class NcFile;
NcAtt( NcFile*, NcToken);
NcValues* values( void ) const;
ncvalues.h
заголовокМоих навыков кодирования недостаточно, чтобы понять, как я возвращаюсь к строке / int / float, хранящейся как NcValue, в классе NcAtt в NcFile.
В приложении приведен пример кода моей проблемы «NetCDF_test.cpp», критическая часть которого отсутствует в реализации функции «LoadNetCDF».
Код компилируется нормально с помощью: (edit: также «TestFile.nc» создан правильно)
g++ -c NetCDF_test.cpp -o NetCDF_test.o
g++ -o NCTEST NetCDF_test.o -lnetcdf_c++ -lnetcdf
Пример кода:
#include <iostream> // provides screen output (i.e. std::cout<<)
#include <netcdfcpp.h>
struct MyStructure {
std::string MyString;
int MyInt;
float MyFloat;
MyStructure(); // default constructor
int SaveNetCDF(std::string); // Save the struct content to "global attributes" in NetCDF
int LoadNetCDF(std::string); // Load the struct content from "global attributes" in NetCDF
};
MyStructure::MyStructure(void)
{
MyString = "TestString";
MyInt = 123;
MyFloat = 1.23;
}
int MyStructure::SaveNetCDF(std::string OUTPUT_FILENAME)
{
NcError err(NcError::silent_nonfatal);
static const int NC_ERR = 2;
NcFile NetCDF_File(OUTPUT_FILENAME.c_str(), NcFile::Replace);
if(!NetCDF_File.is_valid()) {return NC_ERR;}
if(!(NetCDF_File.add_att("MyString",MyString.c_str()))) {return NC_ERR;}
if(!(NetCDF_File.add_att("MyInt",MyInt))) {return NC_ERR;}
if(!(NetCDF_File.add_att("MyFloat",MyFloat))) {return NC_ERR;}
return 0;
}
int MyStructure::LoadNetCDF(std::string INPUT_FILENAME)
{
NcError err(NcError::silent_nonfatal);
static const int NC_ERR = 2;
NcFile NetCDF_File(INPUT_FILENAME.c_str(), NcFile::ReadOnly);
if(!NetCDF_File.is_valid()) {return NC_ERR;}
// ???? This is where I am stuck.
// How do I read the global attribute from the NetCDF_File ??
return 0;
}int main()
{
std::cout<< "START OF TEST.\n";
MyStructure StructureInstance; // datamembers initialized by constructor
StructureInstance.SaveNetCDF("TestFile.nc");
StructureInstance.MyString = "Change string for sake of testing";
StructureInstance.MyInt = -987;
StructureInstance.MyFloat = -9.87;
StructureInstance.LoadNetCDF("TestFile.nc"); // data members are supposed to be read from file
std::cout<< "Now the data members of StructureInstance should be TestString, 123, and 1.23\n";
std::cout<< StructureInstance.MyString << " ; " << StructureInstance.MyInt << " ; " << StructureInstance.MyFloat <<"\n";
std::cout<< "END OF TEST.\n";
}
Это довольно четко изложено в руководстве пользователя C ++: http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx/Class-NcAtt.html#Class-NcAtt
«Поскольку атрибуты связаны только с открытыми файлами netCDF, для этого класса нет открытых конструкторов. Используйте функции-члены NcFile и NcVar для получения атрибутов netCDF или добавления новых атрибутов».
глобальные атрибуты — это атрибуты файла (в отличие от атрибутов переменной, которые, в общем, являются атрибутами переменной)
NetCDF_File.num_atts () возвращает количество глобальных атрибутов. Методы get_att () (перегруженные различными способами) получат вам атрибут.
советоваться http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx/Class-NcFile.html#Class-NcFile
Большое спасибо Робу Лэтэму за ссылки на комментированное описание NetCDF API (устаревшая версия C ++). С информацией, предоставленной там, я смог понять это:
NcAtt
неотъемлемая форма NcTypedComponent
набор функций-членов для доступа к данным, хранящимся в данном NcAtt
: (int n == n-й элемент)
ncbyte as_ncbyte( int n ) const
char as_char( int n ) const
short as_short( int n ) const
int as_int( int n ) const
nclong as_nclong( int n ) const // deprecated
long as_long( int n ) const
float as_float( int n ) const
double as_double( int n ) const
char* as_string( int n ) const
Но все же конструктор для NcAtt является закрытым, и единственная точка доступа к существующему NcAtt — через функцию-член NcFile. NcVar* get_var(NcToken name) const
— который возвращает только указатель. Следовательно, прямое использование не работает:
int MyInt = MyNcFile.get_att("MyInt").as_int(0); // DOES NOT COMPILE
Однако разыменование указателя, возвращаемого get_att
делает трюк.
int MyInt = (*MyNcFile.get_att("MyInt")).as_int(0); // WORKS
Ради полноты излагаю ниже реализацию MyStructure::LoadNetCDF
для примера кода моего оригинального вопроса.
int MyStructure::LoadNetCDF(std::string INPUT_FILENAME)
{
NcError err(NcError::silent_nonfatal);
static const int NC_ERR = 2;
NcFile NetCDF_File(INPUT_FILENAME.c_str(), NcFile::ReadOnly);
if(!NetCDF_File.is_valid()) {return NC_ERR;}
// NcAtt constructor is private, but one can obtain the pointer to an existing NcAtt
NcAtt* PointerToMyIntNcAtt = NetCDF_File.get_att("MyInt");
// Now, using the dereferencing operator one has access to the member functions that NcAtt inherents from NcTypedComponent
if(!(*PointerToMyIntNcAtt).is_valid()) {return NC_ERR;}
std::cout<< "Is MyInt a valid NcAtt? "<< (*PointerToMyIntNcAtt).is_valid()<<"\n";
// The concise way of writing the access to NetCDF "global attributes"" of type int/float/string
MyInt = (*NetCDF_File.get_att("MyInt")).as_int(0);
MyFloat = (*NetCDF_File.get_att("MyFloat")).as_float(0);
MyString = (*NetCDF_File.get_att("MyString")).as_string(0);
return 0;
}