BaseFile Manual
BaseFile is a class to create arbitrary files and/or read and write data from and to files. In addition to functions reading and writing Cinema 4D data types, there are functions to do low-level byte accesses and to retrieve basic information on files.
Internally a BaseFile object keeps track of a read/write pointer, basically the position of the file, where data is read from with the next read access or written to with the next write access. The initial position of this read/write pointer depends on the mode used to open the file.
In general there are two fundamentally different ways to work with BaseFile :
Throughout this page the code snippets use a helper function
PrintFileError()
.
This looks like so:
// Small helper function used in BaseFile 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 BaseFile * const file, const maxon::String & errText, Bool verbose = false ); static maxon::Result<void> PrintFileError( const Filename & fn, const BaseFile * const file, const maxon::String & errText, Bool verbose /*= false*/ ) { if (file == nullptr ) return maxon::NullptrError( MAXON_SOURCE_LOCATION );BaseFile objects are created with the usual tools, see Entity Creation and Destruction Manual (Classic) .
After allocating a BaseFile object, BaseFile::Open() needs to be called to bind it to a file in the filesystem (either an existing or a new one).
Most commonly 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. Filename fn; if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::DIRECTORY , "Select a directory..." _s)) return maxon::OK ; fn += Filename { "myfile.dat" }; AutoAlloc<BaseFile> file; if (file == nullptr ) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Create the file with the purpose of writing into it. // BEWARE: FILEOPEN_WRITE will create a new file, any existing file will be overwritten. if (!file-> Open (fn, FILEOPEN::WRITE , FILEDIALOG::ANY , BYTEORDER::V_INTEL , MACTYPE_CINEMA , MACCREATOR_CINEMA )) return PrintFileError(fn, file, "Failed to create file" _s);
// Write some data into the new file. // Note: The order of data being written needs to be the same, when reading. if (!file-> WriteInt32 (12345678)) return PrintFileError(fn, file, "Failed to write an Int32 into file" _s); if (!file-> WriteString ( "Hello World!" _s)) return PrintFileError(fn, file, "Failed to write a String into file" _s);
// Finally close the file. // Actually not needed, as the file will be closed on destruction of the BaseFile object. file-> 关闭 ();
// This example demonstrates appending typed data to a file.
// Note: The file created via the "BaseFile Create" example is expected in this example. // BEWARE: This code will append data to the file, so be careful, when choosing one.
// Let user select a file. Filename fn; if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::LOAD , "Select the file from the BaseFile Create command..." _s)) return maxon::OK ; AutoAlloc<BaseFile> file; if (file == nullptr ) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Open a file with the purpose of appending some data to it. if (!file-> Open (fn, FILEOPEN::APPEND , FILEDIALOG::ANY , BYTEORDER::V_INTEL , MACTYPE_CINEMA , MACCREATOR_CINEMA )) return PrintFileError(fn, file, "Failed to open the file for appending" _s);
// Write some more data into the file. // Note: The order of data being written needs to be the same, when reading. if (!file-> WriteVector64 ( 向量 (10.0, 20.0, 30.0))) return PrintFileError(fn, file, "Failed to write a vector into file" _s);
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 "BaseFile Create" or "BaseFile Append" examples is expected in this example.
// Let user select a file. Filename fn; if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::LOAD , "Select the file from the BaseFile Create or Append command..." _s)) return maxon::OK ; AutoAlloc<BaseFile> file; if (file == nullptr ) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Open a file with the purpose of reading data from it. if (!file-> Open (fn, FILEOPEN::READ , FILEDIALOG::ANY , BYTEORDER::V_INTEL , MACTYPE_CINEMA , MACCREATOR_CINEMA )) return PrintFileError(fn, file, "Failed to open the file for reading" _s);
// Read data from file. // Note: The order needs to be the same as on write. Int32 value; if (!file-> ReadInt32 (&value)) return PrintFileError(fn, file, "Failed to read an Int32 from file" _s); if (value != 12345678) return PrintFileError(fn, file, "This is not the expected file" _s); ApplicationOutput ( "Int32 read from file: @" _s, value); maxon::String myText; if (!file-> ReadString (&myText)) return PrintFileError(fn, file, "Failed to read from string into file" _s); ApplicationOutput ( "String read from file: @" _s, myText); 向量 vec; if (!file-> ReadVector64 (&vec)) return PrintFileError(fn, file, "Failed to read Vector from file (maybe the append example hasn't been executed)" _s); ApplicationOutput ( "Vector read from file: @" _s, vec);
另请参阅 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) .
This is used to read or write files of arbitrary type/structure. For example, if a pure ASCII text file is supposed to be created, the above functions won't work, because no matter what is done (e.g. WriteString(), WriteChar()), there will always be the value headers prepended to the actual data. In such cases the byte access functions may be helpful.
A typical read or write looks like this:
// Typical first bytes of a Cinema 4D scene file (.c4d), just used as an example here. Nobody should rely on this! static const Char testBytes[] = { 'Q' , 'C' , '4' , 'D' , 'C' , '4' , 'D' }; const Int32 numBytes = sizeof (testBytes); Filename fn;
// Let user select a file if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::LOAD , "Select a C4D scene file..." _s)) return maxon::OK ; AutoAlloc<BaseFile> file; if (file == nullptr ) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Open a file with the purpose of reading data from it. if (!file-> Open (fn, FILEOPEN::READ , FILEDIALOG::ANY , BYTEORDER::V_INTEL , MACTYPE_CINEMA , MACCREATOR_CINEMA )) return PrintFileError(fn, file, "Failed to open the file for reading" _s);
// Read data from file. Char readBytes[numBytes]; const Bool justTry = false ; // Throw an error, if the file is smaller than the number of requested bytes. if (!file-> ReadBytes (&readBytes, sizeof (readBytes), justTry)) return PrintFileError(fn, file, maxon::String ( "Failed to read @ bytes from file" _s + maxon::String::IntToString(numBytes) + " bytes from file" _s));
// Compare the read bytes. Bool ok = true ; for ( Int32 idxByte = 0; idxByte < numBytes; ++idxByte) { if (readBytes[idxByte] != testBytes[idxByte]) { ok = false ; break ; } } if (ok) ApplicationOutput ( "The file seems to be a C4D scene file." ); else ApplicationOutput ( "The file does not seem to be a C4D scene file." );
// This example demonstrates writing raw bytes to a file. const maxon::String text = "The quick brown cube jumps over the sphere." _s;
// Let user select a directory. Filename fn; if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::DIRECTORY , "Select a directory for a new file..." _s)) return maxon::OK ; fn += Filename ( "myTextFile.txt" _s); AutoAlloc<BaseFile> file; if (file == nullptr ) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Open a file with the purpose of writing data to it. if (!file-> Open (fn, FILEOPEN::WRITE , FILEDIALOG::ANY , BYTEORDER::V_INTEL , MACTYPE_CINEMA , MACCREATOR_CINEMA )) return PrintFileError(fn, file, "Failed to open the file for writing" _s);
// Get a byte representation of the string (commented lines for classic String). //const Int32 numBytes = text.GetCStringLen(); const Int numBytes = text.GetLength(); //Char* cText = text.GetCStringCopy(); //maxon::Block<Char> textBuffer[numBytes]; //text.GetCStringBlock(&textBuffer); maxon::BaseArray<Char> cText = text.GetCString() iferr_return ; if (!cText. GetFirst ()) return maxon::UnexpectedError( MAXON_SOURCE_LOCATION , "Error: Failed to get C string" _s);
// Write data to file if (!file-> WriteBytes (cText. GetFirst (), numBytes)) return PrintFileError(fn, file, "Failed to write " _s + maxon::String::IntToString(numBytes) + " bytes to file" _s);
//DeleteMem(cText); // Don't forget to free the memory of the C string.
// This example demonstrates seeking a position in a file.
// Let user select a file. Filename fn; if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::LOAD , "Select the file from BaseFile Write example..." _s)) return maxon::OK ; AutoAlloc<BaseFile> file; if (file == nullptr ) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Open a file with the purpose of reading/writing data from/to it. if (!file-> Open (fn, FILEOPEN::READWRITE , FILEDIALOG::ANY , BYTEORDER::V_INTEL , MACTYPE_CINEMA , MACCREATOR_CINEMA )) return PrintFileError(fn, file, "Failed to open the file for reading/writing" _s);
// Prove: After opening position is zero. // Note: This is different, if the file is opened with FILEOPEN::APPEND. ApplicationOutput ( "File opened with FILEOPEN_READWRITE, position: @" _s, file-> GetPosition ());
// Change read/write position. // Assuming the file from the BaseFile Write (RAW) example is used, skipping three bytes should point to the space before "quick". if (!file-> Seek (3)) return PrintFileError(fn, file, "Failed to seek position 3" _s); ApplicationOutput ( "Reading from position: @" _s, file-> GetPosition ());
// Read a few bytes // Assuming the file from the BaseFile Write (RAW) example is used, reading six bytes should read " quick" (including preceding space). Char word[7]; // Have buffer one byte larger than needed. if (!file-> ReadBytes (word, sizeof (word) - 1, false )) return PrintFileError(fn, file, "Failed to read six bytes" _s); word[6] = 0; // Assure zero terminated string.
// Now, change position to the end of the file in order to append the word just read. if (!file-> Seek (file-> GetLength (), FILESEEK::START )) // using absolute position in file return PrintFileError(fn, file, "Failed to seek end of file" _s); ApplicationOutput ( "Writing \"@\"to end of file, position: @" _s, word, file-> GetPosition ());
// Write the read word at the end of the file. if (!file-> WriteBytes (word, sizeof (word))) return PrintFileError(fn, file, "Failed to append bytes to the end of file" _s);
These utility functions provide some information on the file. Especially BaseFile::GetError() is frequently used to get information, what went wrong, if an error occured with one of the above functions.
// Let user select a file. Filename fn; if (!fn. FileSelect ( FILESELECTTYPE::ANYTHING , FILESELECT::LOAD , "Select a C4D scene file..." _s)) return maxon::OK ; AutoAlloc<BaseFile> file; if (file == nullptr ) return maxon::OutOfMemoryError( MAXON_SOURCE_LOCATION );
// Open the file if (!file-> Open (fn, FILEOPEN::READ , FILEDIALOG::ANY , BYTEORDER::V_INTEL , MACTYPE_CINEMA , MACCREATOR_CINEMA )) return PrintFileError(fn, file, "Failed to open the file for reading" _s);
// Print some infos about the file. const Int64 fileSize = file-> GetLength (); const LOCATION fileLocation = file-> GetLocation (); ApplicationOutput ( "File size: @bytes" _s, fileSize); switch (fileLocation) { case LOCATION::DISK : ApplicationOutput ( "File is located on disk" _s); break ; case LOCATION::IPCONNECTION : ApplicationOutput ( "File is located on a network device" _s); // Note: This is a special case, that can't occur in this situation. break ; case LOCATION::MEMORY : ApplicationOutput ( "File is located in memory" _s); // Note: This is a special case, see MemoryFileStruct manuals and examples. break ; }