File I/O Operations and Management Module.
The imtfile module provides file input/output utilities, format conversion, compression services, and file content provisioning for ImtCore applications.
Overview
This module extends the base ACF file operations (ifile namespace) with specialized functionality:
- Binary file content loading and provision
- File format conversion between compatible formats
- File and folder compression/decompression
- Integration with ACF persistence infrastructure
Architecture
Design Patterns
Provider Pattern:
- IFileProvider abstracts file content loading
- CFileProviderComp provides concrete implementation
- Enables dependency injection for file access
- Facilitates testing with mock providers
Strategy Pattern:
- IFileCompression defines compression algorithm interface
- Multiple compression strategies (ZIP, GZIP, etc.) possible
- Algorithm selection based on file type or user preference
Adapter Pattern:
- CFileFormatConversionComp adapts between document formats
- Uses IFilePersistence for format-specific I/O
- Converts through intermediate working object
- Transparent format translation
Component Pattern (ACF):
- All major classes are ACF components
- Factory-based instantiation
- Reference-based dependency injection
- Configuration through attributes
Core Interfaces
The module provides three primary service interfaces:
File Content Provider:
├─ LoadData(data, filePath) - Load binary file contents
└─ Use cases: Resource loading, data import
│
├─ Handles binary file reading
├─ Error handling and logging
└─ Cross-platform path handling
File Compression Service:
IFileCompression (istd::IPolymorphic)
├─ CompressFile(source, target) - Compress single file
├─ DecompressFile(source, target) - Decompress single file
├─ CompressFolder(source, target, recursive) - Compress directory
└─ DecompressFolder(source, target) - Extract archive
│
└─ Implementations available in
imtzip module
├─ ZIP format support
├─ Recursive folder compression
└─ Preserve file attributes
Format Conversion Service:
├─ ConvertFiles(inputPath, outputPath, params, progress)
├─ Depends on:
│ ├─ IFilePersistence - Format reading/writing
│ └─ IChangeable - Working object for conversion
└─ Pattern: Load → Convert → Save
│
Example: XML → JSON, CSV → SQL, etc.
Core Services
File Content Provider
IFileProvider / CFileProviderComp** - Binary file loading service:
auto fileProvider = CFileProviderComp::CreateInstance();
QByteArray fileData;
QString filePath = "/path/to/resource.dat";
bool success = fileProvider->LoadData(fileData, filePath.toUtf8());
if (success) {
qDebug() << "Loaded" << fileData.size() << "bytes";
}
Use Cases:**
- Loading application resources
- Reading configuration files
- Importing binary data
Reading embedded assets
Features:**
- Cross-platform path handling
- Automatic error logging
- Memory-efficient streaming
- Binary format agnostic
File Compression
IFileCompression** - File and folder compression/decompression interface. Concrete implementations are provided in the imtzip module.
auto compression = CZipCompressionComp::CreateInstance();
compression->CompressFile(
"/path/to/input.txt",
"/path/to/output.zip");
compression->DecompressFile(
"/path/to/archive.zip",
"/path/to/extracted.txt");
compression->CompressFolder(
"/path/to/folder",
"/path/to/archive.zip",
true
);
compression->DecompressFolder(
"/path/to/archive.zip",
"/path/to/output_folder");
Use Cases:**
- Creating backup archives
- Compressing log files
- Packaging application data
- Reducing storage footprint
- Preparing data for transmission
Format Conversion
CFileFormatConversionComp** - Convert between document formats:
auto converter = CFileFormatConversionComp::CreateInstance();
auto xmlPersistence = CXmlPersistenceComp::CreateInstance();
auto jsonPersistence = CJsonPersistenceComp::CreateInstance();
auto document = CDataDocumentComp::CreateInstance();
converter->SetAttribute("Persistence", xmlPersistence.get());
converter->SetAttribute("WorkingObject", document.get());
QString inputPath = "data.xml";
QString outputPath = "data.json";
int result = converter->ConvertFiles(inputPath, outputPath);
if (result == ifileproc::IFileConversion::CS_OK) {
qDebug() << "Conversion successful";
}
Conversion Process:**
- Load source file using IFilePersistence (format A)
- Populate working object (IChangeable)
- Save working object using IFilePersistence (format B)
Report progress if IProgressManager provided
Supported Format Combinations:**
- Any formats with compatible IFilePersistence implementations
- XML ↔ JSON (via imtbase persistence components)
- Binary ↔ Text formats
- Custom formats via persistence plugins
Integration Patterns
Integration with ACF Persistence
Pattern: File Provider with Persistence:**
class CDataLoaderComp : public ACF_COMPONENT(IDataLoader)
{
I_REFERENCE(IFilePersistence, m_persistence)
bool LoadDocument(const QString& filePath) override
{
QByteArray rawData;
if (!m_fileProvider->LoadData(rawData, filePath.toUtf8())) {
return false;
}
QBuffer buffer(&rawData);
buffer.open(QIODevice::ReadOnly);
return m_persistence->LoadFromDevice(m_document, &buffer)
== IFilePersistence::OS_OK;
}
};
Integration with Compression
Pattern: Automatic Archive Creation:**
class CBackupManagerComp : public ACF_COMPONENT(IBackupManager)
{
I_REFERENCE(IFileCompression, m_compression)
bool CreateBackup(const QString& dataDir) override
{
QString timestamp = QDateTime::currentDateTime()
.toString("yyyyMMdd_hhmmss");
QString archivePath = QString("backup_%1.zip").arg(timestamp);
return m_compression->CompressFolder(
dataDir,
archivePath,
true
);
}
bool RestoreBackup(const QString& archivePath,
const QString& targetDir) override
{
return m_compression->DecompressFolder(archivePath, targetDir);
}
};
Integration with Format Conversion
Pattern: Multi-Format Export:**
class CReportExporterComp : public ACF_COMPONENT(IReportExporter)
{
I_REFERENCE(IFileFormatConversion, m_converter)
void ExportReport(IReport* report, const QString& format)
{
QString tempFile = QDir::temp().filePath("report.xml");
SaveReportToXml(report, tempFile);
QString outputFile = QString("report.%1").arg(format);
if (format == "json") {
m_converter->SetAttribute("Persistence", m_jsonPersistence);
m_converter->ConvertFiles(tempFile, outputFile);
}
else if (format == "csv") {
m_converter->SetAttribute("Persistence", m_csvPersistence);
m_converter->ConvertFiles(tempFile, outputFile);
}
}
};
Complete Examples
Resource Loading System
class CResourceManagerComp : public ACF_COMPONENT(IResourceManager)
{
QHash<QString, QByteArray> m_cache;
public:
QByteArray LoadResource(const QString& resourceId)
{
if (m_cache.contains(resourceId)) {
return m_cache[resourceId];
}
QString resourcePath = QString(":/resources/%1").arg(resourceId);
QByteArray resourceData;
if (m_fileProvider->LoadData(resourceData, resourcePath.toUtf8())) {
m_cache[resourceId] = resourceData;
return resourceData;
}
return QByteArray();
}
QPixmap LoadImage(const QString& imageId)
{
QByteArray imageData = LoadResource(imageId);
QPixmap pixmap;
pixmap.loadFromData(imageData);
return pixmap;
}
};
Backup and Restore System
class CApplicationBackupComp : public ACF_COMPONENT(IApplicationBackup)
{
I_REFERENCE(IFileCompression, m_compression)
public:
struct BackupInfo {
QString archivePath;
QDateTime timestamp;
qint64 sizeBytes;
};
bool CreateFullBackup(IProgressManager* progress = nullptr)
{
QString dataDir = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation);
QDir backupDir(dataDir + "/backups");
if (!backupDir.exists()) {
backupDir.mkpath(".");
}
QString timestamp = QDateTime::currentDateTime()
.toString("yyyyMMdd_hhmmss");
QString archivePath = backupDir.filePath(
QString("backup_%1.zip").arg(timestamp));
bool success = m_compression->CompressFolder(
dataDir + "/data",
archivePath,
true
);
if (success && progress) {
progress->SetProgressValue(100);
}
return success;
}
QList<BackupInfo> ListAvailableBackups()
{
QList<BackupInfo> backups;
QString dataDir = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation);
QDir backupDir(dataDir + "/backups");
QStringList archives = backupDir.entryList(
QStringList() << "backup_*.zip",
QDir::Files,
QDir::Time | QDir::Reversed);
for (const QString& archive : archives) {
BackupInfo info;
info.archivePath = backupDir.filePath(archive);
QFileInfo fileInfo(info.archivePath);
info.timestamp = fileInfo.lastModified();
info.sizeBytes = fileInfo.size();
backups.append(info);
}
return backups;
}
bool RestoreBackup(const QString& archivePath)
{
QString dataDir = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation);
QString restoreDir = dataDir + "/restore_temp";
QDir().mkpath(restoreDir);
bool success = m_compression->DecompressFolder(
archivePath,
restoreDir);
if (success) {
MoveRestoredData(restoreDir, dataDir + "/data");
}
QDir(restoreDir).removeRecursively();
return success;
}
};
Document Conversion Pipeline
class CDocumentConverterComp : public ACF_COMPONENT(IDocumentConverter)
{
I_REFERENCE(IFileFormatConversion, m_converter)
public:
enum Format {
FMT_XML,
FMT_JSON,
FMT_CSV,
FMT_BINARY
};
bool ConvertDocument(const QString& inputPath,
Format inputFormat,
const QString& outputPath,
Format outputFormat,
IProgressManager* progress = nullptr)
{
auto sourcePersistence = CreatePersistence(inputFormat);
if (!sourcePersistence) {
return false;
}
auto targetPersistence = CreatePersistence(outputFormat);
if (!targetPersistence) {
return false;
}
auto document = CDataDocument::CreateInstance();
m_converter->SetAttribute("Persistence", sourcePersistence.get());
m_converter->SetAttribute("WorkingObject", document.get());
QString tempPath = outputPath;
int result = m_converter->ConvertFiles(inputPath, tempPath, nullptr, progress);
if (result != ifileproc::IFileConversion::CS_OK) {
return false;
}
m_converter->SetAttribute("Persistence", targetPersistence.get());
result = m_converter->ConvertFiles(tempPath, outputPath, nullptr, progress);
return result == ifileproc::IFileConversion::CS_OK;
}
private:
IFilePersistenceUniquePtr CreatePersistence(Format format)
{
switch (format) {
case FMT_XML:
return CXmlPersistenceComp::CreateInstance();
case FMT_JSON:
return CJsonPersistenceComp::CreateInstance();
case FMT_CSV:
return CCsvPersistenceComp::CreateInstance();
case FMT_BINARY:
return CBinaryPersistenceComp::CreateInstance();
default:
return nullptr;
}
}
};
Best Practices
Error Handling
- Always check return values from LoadData(), CompressFile(), etc.
- Use try-catch blocks when working with file I/O
- Provide meaningful error messages to users
- Log errors using ilog::ILogger for debugging
Performance Considerations
- Cache frequently accessed file contents in memory
- Use streaming for large files instead of loading entirely
- Compress files asynchronously to avoid blocking UI
- Consider file size before loading into memory
Security Best Practices
- Validate file paths to prevent directory traversal
- Check file permissions before accessing
- Sanitize user-provided file paths
- Use appropriate file system APIs for platform security
Integration with Other Modules
With imtzip (Compression):
- Concrete IFileCompression implementations
- ZIP format support
- Archive creation and extraction
With imtcrypt (Encryption):
- Encrypted file storage via CEncryptionBasedPersistenceComp
- Secure file loading with IFileProvider
- Protected backup archives
With imtdb (Database):
- Import/export database content to files
- Backup database to compressed archives
- Load database initialization scripts
With imtbase (Collections):
- File-based collections with IFileProvider
- Bulk file operations on collections
- Resource loading for collection items
References
Related Modules:
- ifile (ACF) - Base file persistence interfaces
- ifileproc (ACF) - File processing interfaces
- imtzip - ZIP compression implementation
- imtcrypt - Encrypted file operations
ACF Interfaces:
- ifile::IFilePersistence - File format persistence
- ifile::IFileNameParam - File path parameter
- ifileproc::IFileConversion - Format conversion
External Documentation: