About
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:
- Using Cinema 4D data types and accompanying read/write functions, see Read and Write below
- Using low-level byte access, see Byte Access below
Throughout this page the code snippets use a helper function PrintFileError()
.
This looks like so:
{
if (verbose)
{
return FileErrorToString(
file);
}
else
{
{
else
}
}
}
Definition: c4d_file.h:346
Manages file and path names.
Definition: c4d_file.h:94
Definition: string.h:1237
maxon::Bool Bool
Definition: ge_sys_math.h:51
maxon::Int Int
Definition: ge_sys_math.h:60
return OK
Definition: apibase.h:2735
FILEERROR
Definition: ge_prepass.h:3990
@ UNKNOWN_VALUE
Unknown value detected.
@ OUTOFMEMORY
Not enough memory.
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:67
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:204
const char const char const char * file
Definition: object.h:439
- Note
- To delete a file see GeFKill() and the accompanying File Functions Manual.
Allocation/Deallocation
BaseFile objects are created with the usual tools, see Entity Creation and Destruction Manual (Classic).
Opening and Closing
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).
- BaseFile::Open(): Opens a file, several flags influence the mode, initial position of read/write pointer, error reporting behavior and certain system specific options.
- Parameter "mode":
- FILEOPEN::READ : The file is opened for reading, only. Read/write pointer is set to start of file. This is the default mode, if none gets specified.
- FILEOPEN::WRITE : The file is opened for writing, only. Read/write pointer is set to start of file. Any existing file will be overwritten.
- FILEOPEN::READWRITE : The file is opened for read and write access. Read/write pointer is set to start of file.
- FILEOPEN::APPEND : The file is opened for writing, only. Read/write pointer is set to end of file.
- Parameter "error_dialog":
- FILEDIALOG::NONE : No dialog will be shown on error. To be used if working with files in a context, where no dialogs are allowed, or to implement a custom error notification for users.
- FILEDIALOG::ANY : A dialog will be shown on every file error.
- FILEDIALOG::IGNOREOPEN : A dialog will be shown on every file error, except if the file does not exist. This is the default option.
- Parameter (byte-)"order":
- The byte order comes into play, if for example numeric values wider than a byte get read or stored (e.g. ReadInt32() and WriteInt32()). Usually you don't have to care much about this. When dealing with your own files, just make sure to use the same byte order on writing and reading. When handling arbitrary 3rd party file types, the byte order usually gets specified in the format documentation. The byte order can also be changed after opening the file using BaseFile::SetOrder().
- BYTEORDER::V_MOTOROLA : Big endian byte order.
- BYTEORDER::V_INTEL : Little endian byte order.
- Parameter (file-)"type":
- This parameter is only relevant for OSX and defines the type of file created.
- Parameter (file-)"creator":
- This parameter is only relevant for OSX and should be left at its default in most cases.
- BaseFile::Close(): Closes a file. In most cases this is not needed, as the file will be automatically closed, when the BaseFile object gets destroyed.
Read and Write
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.
A Typical Write Access
- Allocate a BaseFile object with BaseFile::Alloc() (or of course AutoAlloc).
- Open a file using BaseFile::Open(), either creating a new one or opening an existing one.
- Simply write data into the file, see below. Cinema 4D will take care of the read/write pointer automatically.
- Close the file using BaseFile::Close(). This step is actually optional, as the file will also be closed when the BaseFile object gets destroyed.
- Note
- The order of write accesses will determine the order of read accesses (the order will need to be the same).
return PrintFileError(fn,
file,
"Failed to create file"_s);
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);
Definition: ge_autoptr.h:37
Bool FileSelect(FILESELECTTYPE type, FILESELECT flags, const maxon::String &title, const maxon::String &force_suffix=maxon::String())
@ V_INTEL
Intel, little endian.
@ ANY
Show an error dialog for any error.
@ DIRECTORY
Folder selection dialog.
#define MACCREATOR_CINEMA
Standard Mac creator code for Cinema 4D.
Definition: ge_prepass.h:31
#define MACTYPE_CINEMA
Standard Mac type code for Cinema 4D.
Definition: ge_prepass.h:30
return PrintFileError(fn,
file,
"Failed to open the file for appending"_s);
if (!
file->WriteVector64(
Vector(10.0, 20.0, 30.0)))
return PrintFileError(fn,
file,
"Failed to write a vector into file"_s);
@ APPEND
Open an existing file for writing and set the position to the end of that file.
A Typical Read Access
- Allocate a BaseFile object with BaseFile::Alloc() (or of course AutoAlloc).
- Open an existing file using BaseFile::Open().
- Simply read data from the file in the same order it got written before, see below. Cinema 4D will take care of the read/write pointer automatically.
- Close the file using BaseFile::Close(). This step is actually optional, as the file will also be closed when the BaseFile object gets destroyed.
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 order of read accesses has to match the order of write accesses.
-
These functions can not be used to read data from an arbitrary file, but only from files created by Cinema 4D, when data got written by the respective write functions.
-
It is not recommended to mix these functions with the byte access functions (see Byte Access).
return PrintFileError(fn,
file,
"Failed to open the file for reading"_s);
return PrintFileError(fn,
file,
"Failed to read an Int32 from file"_s);
return PrintFileError(fn,
file,
"This is not the expected file"_s);
if (!
file->ReadString(&myText))
return PrintFileError(fn,
file,
"Failed to read from string into file"_s);
if (!
file->ReadVector64(&vec))
return PrintFileError(fn,
file,
"Failed to read Vector from file (maybe the append example hasn't been executed)"_s);
PyObject * value
Definition: abstract.h:715
maxon::Int32 Int32
Definition: ge_sys_math.h:56
@ READ
Open the file for reading.
Char
See also Primitive Data Types Manual (Classic) on Char.
String
See also String Manual (Classic).
Filename
See also Filename Manual.
Bool
See also Primitive Data Types Manual (Classic) on Bool.
Integer
See also Primitive Data Types Manual (Classic) on Integer.
Float
See also Primitive Data Types Manual (Classic) on Float.
Vector
See also Vector Manual (Classic).
Matrix
See also Matrix Manual (Classic).
Byte Access
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:
- Warning
- The byte sequences read or written are not platform independent. For example, when reading the four bytes of an Int32, one will need to know, if the most or the least significant byte is first.
static const Char testBytes[] = {
'Q',
'C',
'4',
'D',
'C',
'4',
'D' };
const Int32 numBytes =
sizeof(testBytes);
return PrintFileError(fn,
file,
"Failed to open the file for reading"_s);
Char readBytes[numBytes];
const Bool justTry =
false;
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));
for (
Int32 idxByte = 0; idxByte < numBytes; ++idxByte)
{
if (readBytes[idxByte] != testBytes[idxByte])
{
ok = false;
break;
}
}
if (ok)
else
maxon::Char Char
Definition: ge_sys_math.h:52
return PrintFileError(fn,
file,
"Failed to open the file for writing"_s);
const Int numBytes =
text.GetLength();
return PrintFileError(fn,
file,
"Failed to write "_s + maxon::String::IntToString(numBytes) +
" bytes to file"_s);
MAXON_ATTRIBUTE_FORCE_INLINE const T * GetFirst() const
Definition: basearray.h:1175
PyObject * text
Definition: pycore_traceback.h:70
#define iferr_return
Definition: resultbase.h:1524
return PrintFileError(fn,
file,
"Failed to open the file for reading/writing"_s);
return PrintFileError(fn,
file,
"Failed to seek position 3"_s);
if (!
file->ReadBytes(word,
sizeof(word) - 1,
false))
return PrintFileError(fn,
file,
"Failed to read six bytes"_s);
word[6] = 0;
return PrintFileError(fn,
file,
"Failed to seek end of file"_s);
if (!
file->WriteBytes(word,
sizeof(word)))
return PrintFileError(fn,
file,
"Failed to append bytes to the end of file"_s);
@ READWRITE
Open the file for both reading and writing.
@ START
The position is given relative to the start of the file.
- BaseFile::ReadBytes(): Reads a block of bytes from the file. By default throwing an error, if there are less bytes in the file than requested.
- BaseFile::TryReadBytes(): Reads a block of bytes from the file, without throwing an error, if there are less bytes in the file than requested. Basically the same as BaseFile::ReadBytes(data, len, true).
- BaseFile::WriteBytes(): Writes a block of bytes to the file.
- BaseFile::GetPosition(): Returns the current position of the read/write pointer.
- BaseFile::Seek(): Sets the read/write pointer to another position.
- Note
- It is possible to seek beyond the end of a file. When writing to this position, the skipped parts of the file will be filled with zeroes. A read from such position will end up in an error.
Utility
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.
return PrintFileError(fn,
file,
"Failed to open the file for reading"_s);
switch (fileLocation)
{
break;
break;
break;
}
maxon::Int64 Int64
Definition: ge_sys_math.h:58
LOCATION
Definition: ge_prepass.h:4030
@ IPCONNECTION
Target is IP connection.
@ MEMORY
Target is a memory location.
Further Reading