HyperFile Manual
HyperFile is a class to read and write data to a file on disk. This class is for example used to store Cinema 4D scenes, but can also be used to create individual files storing Cinema 4D data types. A HyperFile can not be used to create arbitrary files (like e.g. text files) as all data stored in a HyperFile is prefixed with a value header describing the stored data, see BaseFile Manual on Byte Access instead.
HyperFile class makes many things easier compared to BaseFile class (e.g. one does not need to care about byte order), while sacrificing some of the power of the low-level functions provided there (no byte access possible, no repositioning of the read/write pointer). Most advantageous compared to BaseFile is the file versioning and chunk handling.
A HyperFile is always read (and also written) from the beginning of the file and the handling of the read/write pointer is handled completely internally. In theory replacing of parts of the data in a HyperFile is possible, but definitely not recommended, as good knowledge of the internal structure is needed to not corrupt the file.
Throughout this page the code snippets use a helper function
PrintFileError()
.
This looks like so:
// Small helper function used in HyperFile code snippets below. // Depending on verbose parameter a file error (if any) will also be decoded to a human readable string. // Can also be used, when there's no HyperFile (e.g. HyperFile allocation failed), then only the filename will be used. // It returns true, if there was no error, otherwise false. // In this way it can be used in snippets to directly return from the calling function. static maxon::Result<void> PrintFileError( const Filename & fn, const HyperFile * const file, const maxon::String & errText, Bool verbose = false ); static maxon::Result<void> PrintFileError( const Filename & fn, const HyperFile * const file, const maxon::String & errText, Bool verbose /*= false*/ ) { if (!file) return maxon::NullptrError( MAXON_SOURCE_LOCATION );A HyperFile argument is typically provided in NodeData::Read() and NodeData::Write() functions. See NodeData::Read() / NodeData::Write() Manual .
HyperFile objects are created with the usual tools, see Entity Creation and Destruction Manual (Classic) .
After allocating a HyperFile object HyperFile::Open() needs to be called to bind it to a file in the filesystem (either an existing or a new one).
The following functions are used to store data in a "BaseContainer"-like fashion, where one does not need to worry about the size of datatypes or positioning the read/write pointer.
// Let user select a target directory. if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::DIRECTORY , "Select a directory..." _s)) return maxon::OK ; fn += Filename { "myhyperfile.dat" }; AutoAlloc<HyperFile> hf; if (!hf) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Create a HyperFile with the purpose of writing into it. // BEWARE: FILEOPEN_WRITE will create a new file, any existing file will be overwritten. const Int32 ident = 42; // Set an ID for the new file, use a/the plugin ID to define a unique file type. if (!hf-> Open (ident, fn, FILEOPEN::WRITE , FILEDIALOG::ANY )) return PrintFileError(fn, hf, "Failed to create HyperFile" _s);
// Write some data into the new HyperFile. // Note: The order of data being written needs to be the same, when reading. if (!hf-> WriteInt32 (12345678)) return PrintFileError(fn, hf, "Failed to write an Int32 into HyperFile" _s); if (!hf-> WriteString ( "Hello World!" _s)) return PrintFileError(fn, hf, "Failed to write a String into HyperFile" _s);
// Finally close the HyperFile. // Note: Actually not needed, as the file will be closed on destruction of the HyperFile object. hf-> 关闭 ();
All of the following read/write functions automatically take care of the read/write pointer (i.e. advancing it by the correct amount of bytes depending on the access type) and are able to detect access with wrong data type. Internally this is achieved by not only writing the actual data to the file, but also an additional value header preceding each data, specifying the type and also (where needed) the amount of data.
// Note: The file created via the "HyperFile Create" example is expected in this example. Filename fn;
// Let user select a file. if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::LOAD , "Select the file from the HyperFile Create or Append command..." _s)) return maxon::OK ; AutoAlloc<HyperFile> hf; if (!hf) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Open a HyperFile with the purpose of reading data from it. const Int32 ident = 42; // The ID of the file (-type) that's supposed to be opened. if (!hf-> Open (ident, fn, FILEOPEN::READ , FILEDIALOG::ANY )) return PrintFileError(fn, hf, "Failed to open the HyperFile for reading" _s);
// Read data from file. // Note: The order needs to be the same as on write. Int32 value; if (!hf-> ReadInt32 (&value)) return PrintFileError(fn, hf, "Failed to read an Int32 from HyperFile" _s); if (value != 12345678) return PrintFileError(fn, hf, "This is not the expected HyperFile" _s); ApplicationOutput ( "Int32 read from HyperFile: @" _s, value); maxon::String myText; if (!hf-> ReadString (&myText)) return PrintFileError(fn, hf, "Failed to read a String from HyperFile" _s); ApplicationOutput ( "String read from HyperFile: @" _s, myText);
As mentioned in the beginning, data/values get stored inside the HyperFile as a pair consisting of a describing header followed by the actual data. With the following functions the type of the next value can be detected (see HYPERFILEVALUE_... defines below) and the value may also be skipped (i.e. continue reading with the next value). Usually this is not needed, but can be helpful if for example writing a loop reading arbitrary values.
另请参阅 Primitive Data Types Manual (Classic) on Char .
另请参阅 String Manual (Classic) .
另请参阅 Filename Manual .
另请参阅 Primitive Data Types Manual (Classic) on Bool .
另请参阅 Primitive Data Types Manual (Classic) on 整数 .
另请参阅 Primitive Data Types Manual (Classic) on Float .
另请参阅 Vector Manual (Classic) .
另请参阅 Matrix Manual (Classic) .
These functions can be used with standard C arrays:
// This example reads a C array from a HyperFile. Float64 arrFloat[4] = { 0.0 }; const Int arrSize = sizeof (arrFloat) / sizeof ( Float64 ); if (!hf-> ReadArray (arrFloat, HYPERFILEARRAY::REAL , sizeof ( Float64 ), arrSize)) return PrintFileError(fn, hf, "Failed to read array (Float64) from HyperFile" _s); ApplicationOutput ( "Array (Float64) read from HyperFile:" _s); for ( Int32 idx = 0; idx < arrSize; ++idx) { ApplicationOutput ( " @" , arrFloat[idx]); }// This example writes a standard C array to a HyperFile. const Float64 arrFloat[4] = { 42.0, PI , LIMIT<Float64>::MAX , ( Float64 )1.0 / ( Float64 )255.0 }; // just an example array with four Float64 values const Int arrSize = sizeof (arrFloat) / sizeof ( Float64 ); if (!hf-> WriteArray (arrFloat, HYPERFILEARRAY::REAL , sizeof ( Float64 ), arrSize)) return PrintFileError(fn, hf, "Failed to write an array (Float64) into HyperFile" _s);
And also with maxon::BaseArray :
// This example reads a BaseArray from a HyperFile. maxon::BaseArray<Int64> arrInt; arrInt. Resize (4) iferr_return ; // Make sure, the BaseArray has enough space to hold the data to be read (otherwise read entry by entry and Append()). DebugAssert (arrInt. GetCount () < LIMIT<Int32>::MAX ); // Read array's count parameter is only Int32.// A BaseArray stores data in a continguous memory block, the start address is returned by BaseArray::GetFirst(). if (!hf-> ReadArray (arrInt. GetFirst (), HYPERFILEARRAY::LLONG , sizeof ( Int64 ), ( Int32 )arrInt. GetCount ())) return PrintFileError(fn, hf, "Failed to read BaseArray<Int64> from HyperFile" _s); ApplicationOutput ( "BaseArray<Int64> read from HyperFile:" _s); for ( auto val : arrInt) { ApplicationOutput ( " @" , val); }
// This example writes a BaseArray to a HyperFile. maxon::BaseArray<Int64> arrInt; // just an example BaseArray with arbitrary values arrInt. Append (42) iferr_return ; arrInt. Append (1984) iferr_return ; arrInt. Append (2001) iferr_return ; arrInt. Append ( LIMIT<Int64>::MAX ) iferr_return ;
// A BaseArray stores data in a continguous memory block, the start address is returned by BaseArray::GetFirst(). if (!hf-> WriteArray (arrInt. GetFirst (), HYPERFILEARRAY::LLONG , sizeof ( Int64 ), ( Int32 )arrInt. GetCount ())) return PrintFileError(fn, hf, "Failed to write a BaseArray (Int64) into HyperFile" _s);
另请参阅 GeData Manual .
另请参阅 BaseContainer Manual .
另请参阅 BaseTime 手册 .
另请参阅 BaseBitmap Manual .
// This example reads some arbitrary data (in this case the struct stored earlier on) from a HyperFile.
void * data; Int size = 0; if (!hf-> ReadMemory (&data, &size)) return PrintFileError(fn, hf, "Failed to read memory (myStructure) from HyperFile" _s); myStructure* const myData = static_cast< myStructure* > (data); // Interpret the read data as struct. ApplicationOutput ( "Memory (myStructure, size: @ ) read from HyperFile:" _s, size); ApplicationOutput ( " @" , myData->myFloat); ApplicationOutput ( " @" , myData->myInt); ApplicationOutput ( " @" , myData->myBool);Chunks provide means to group or organize several values. This can be useful if for example different versions of a plugin store different sets of parameters, so a parameter set no longer understood can be skipped.
Actually not part of the HyperFile class, these convenience functions can be used to read or write a complete GeListNode from/into a single HyperFile referenced by Filename .
// Let user select a directory to save to. if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::LOAD , "Select a file created by HyperFile ReadHyperFile example..." _s)) return maxon::OK ; AutoAlloc<BaseObject> op { Onull }; if (!op) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION ); maxon::String errString = "" _s; if ( ReadHyperFile (doc, op, fn, 123456, &errString) != FILEERROR::NONE ) // Note: ident has to match in WriteHyperFile(), get a unique plugin ID! return PrintFileError(fn, nullptr , "Failed to write object " _s + maxon::String (op-> GetName ()) + " to file (" _s + errString + "): " _s); doc-> InsertObject (op.Release(), nullptr , nullptr ); // Note: Usage of Release(), when inserting the AutoAlloc'ed object into the scene.
// Let user select a directory to save to. if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::DIRECTORY , "Select a path for saving..." _s)) return maxon::OK ; fn += Filename { maxon::String (op-> GetName ()) + ".myobj" _s };
// Write the object to the HyperFile. if ( WriteHyperFile (doc, op, fn, 123456) != FILEERROR::NONE ) // Note: ident has to match in ReadHyperFile(), get a unique plugin ID! return PrintFileError(fn, nullptr , "Failed to write object " _s + maxon::String { op-> GetName () } + " to file: " _s); ApplicationOutput ( "Successfully saved to file: " _s + maxon::String { fn. GetString () });