#include "TFileMerger.h"
#include "TUrl.h"
#include "TFile.h"
#include "TUUID.h"
#include "TSystem.h"
#include "TH1.h"
#include "TChain.h"
#include "TKey.h"
#include "THashList.h"
#include "TObjString.h"
#include "TClass.h"
#include "TMethodCall.h"
#include "Riostream.h"
ClassImp(TFileMerger)
TFileMerger::TFileMerger(Bool_t isLocal) : fOutputFile(0), fFastMethod(kTRUE),
fNoTrees(kFALSE)
{
fFileList = new TList;
fFileList->SetOwner(kTRUE);
fMergeList = new TList;
fMergeList->SetOwner(kTRUE);
fLocal = isLocal;
}
TFileMerger::~TFileMerger()
{
if (fFileList)
delete fFileList;
if (fMergeList)
delete fMergeList;
if (fOutputFile)
delete fOutputFile;
}
void TFileMerger::Reset()
{
fFileList->Clear();
fMergeList->Clear();
}
Bool_t TFileMerger::AddFile(const char *url)
{
TFile *newfile;
TUUID uuid;
TString localcopy = Form("file:%s/", gSystem->TempDirectory());
localcopy += "ROOTMERGE-";
localcopy += uuid.AsString();
localcopy += ".root";
if (fLocal) {
if (!TFile::Cp(url, localcopy)) {
Error("AddFile", "cannot get a local copy of file %s", url);
return kFALSE;
}
newfile = TFile::Open(localcopy, "READ");
} else {
newfile = TFile::Open(url, "READ");
}
if (!newfile) {
if (fLocal)
Error("AddFile", "cannot open local copy %s of URL %s",
localcopy.Data(), url);
else
Error("AddFile", "cannot open file %s", url);
return kFALSE;
} else {
fFileList->Add(newfile);
if (!fMergeList)
fMergeList = new TList;
TObjString *urlObj = new TObjString(url);
fMergeList->Add(urlObj);
return kTRUE;
}
}
Bool_t TFileMerger::OutputFile(const char *outputfile)
{
if (fOutputFile)
delete fOutputFile;
fOutputFilename = outputfile;
TUUID uuid;
TString localcopy = Form("file:%s/", gSystem->TempDirectory());
localcopy += "ROOTMERGED-";
localcopy += uuid.AsString();
localcopy += ".root";
fOutputFile = TFile::Open(localcopy, "RECREATE");
fOutputFilename1 = localcopy;
if (!fOutputFile) {
Error("OutputFile", "cannot open the MERGER output file %s", localcopy.Data());
return kFALSE;
}
return kTRUE;
}
void TFileMerger::PrintFiles(Option_t *options)
{
fFileList->Print(options);
}
Bool_t TFileMerger::Merge()
{
if (!fOutputFile) {
Info("Merge", "will merge the results to the file "
"FileMerger.root\nin your working directory, "
"since you didn't specify a merge filename");
if (!OutputFile("FileMerger.root")) {
return kFALSE;
}
}
Bool_t result = MergeRecursive(fOutputFile, fFileList,0);
if (!result) {
Error("Merge", "error during merge of your ROOT files");
} else {
TFile::Cp(fOutputFilename1, fOutputFilename);
}
TString path(fOutputFile->GetPath());
path = path(0, path.Index(':',0));
gSystem->Unlink(path);
fOutputFile = 0;
TIter next(fFileList);
TFile *file;
while ((file = (TFile*) next())) {
file->Close();
if(fLocal) {
TString p(file->GetPath());
p = p(0, p.Index(':',0));
gSystem->Unlink(p);
}
}
return result;
}
Bool_t TFileMerger::MergeRecursive(TDirectory *target, TList *sourcelist, Int_t isdir)
{
TString path( (char*)strstr( target->GetPath(), ":" ) );
path.Remove( 0, 2 );
Bool_t addDirStat = TH1::AddDirectoryStatus();
TH1::AddDirectory(kFALSE);
TDirectory *first_source = (TDirectory*)sourcelist->First();
THashList allNames;
while (first_source) {
TDirectory *current_sourcedir = first_source->GetDirectory(path);
if (!current_sourcedir) {
first_source = (TDirectory*)sourcelist->After(first_source);
continue;
}
TChain *globChain = 0;
TIter nextkey( current_sourcedir->GetListOfKeys() );
TKey *key, *oldkey=0;
while ( (key = (TKey*)nextkey())) {
if (current_sourcedir == target) break;
if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
if (!strcmp(key->GetClassName(),"TProcessID")) {key->ReadObj(); continue;}
if (allNames.FindObject(key->GetName())) continue;
allNames.Add(new TObjString(key->GetName()));
current_sourcedir->cd();
TObject *obj = key->ReadObj();
if ( obj->IsA()->InheritsFrom( "TH1" ) ) {
TH1 *h1 = (TH1*)obj;
TList listH;
TFile *nextsource = (TFile*)sourcelist->After( first_source );
while ( nextsource ) {
TDirectory *ndir = nextsource->GetDirectory(path);
if (ndir) {
ndir->cd();
TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName());
if (key2) {
TObject *hobj = key2->ReadObj();
hobj->ResetBit(kMustCleanup);
listH.Add(hobj);
h1->Merge(&listH);
listH.Delete();
}
}
nextsource = (TFile*)sourcelist->After( nextsource );
}
} else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {
if (!fNoTrees) {
TString obj_name;
if (path.Length()) {
obj_name = path + "/" + obj->GetName();
} else {
obj_name = obj->GetName();
}
globChain = new TChain(obj_name);
globChain->Add(first_source->GetName());
TFile *nextsource = (TFile*)sourcelist->After( first_source );
while ( nextsource ) {
TFile *curf = TFile::Open(nextsource->GetName());
if (curf) {
Bool_t mustAdd = kFALSE;
if (curf->FindKey(obj_name)) {
mustAdd = kTRUE;
} else {
TObject *aobj = curf->Get(obj_name);
if (aobj) { mustAdd = kTRUE; delete aobj;}
}
if (mustAdd) {
globChain->Add(nextsource->GetName());
}
}
delete curf;
nextsource = (TFile*)sourcelist->After( nextsource );
}
}
} else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
target->cd();
TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
MergeRecursive( newdir, sourcelist,1);
} else {
TMethodCall callEnv;
if (obj->IsA())
callEnv.InitWithPrototype(obj->IsA(), "Merge", "TCollection*");
if (callEnv.IsValid()) {
TList* tomerge = new TList;
TFile *nextsource = (TFile*)sourcelist->After(first_source);
while (nextsource) {
nextsource->cd(path);
TObject *newobj = gDirectory->Get(obj->GetName());
if (newobj) {
tomerge->Add(newobj);
}
nextsource = (TFile*)sourcelist->After(nextsource);
}
callEnv.SetParam((Long_t) tomerge);
callEnv.Execute(obj);
delete tomerge;
} else {
target->cd();
obj->Write();
TFile *nextsource = (TFile*)sourcelist->After(first_source);
while (nextsource) {
nextsource->cd(path);
TObject *newobj = gDirectory->Get(obj->GetName());
if (newobj) {
target->cd();
newobj->Write();
}
nextsource = (TFile*)sourcelist->After(nextsource);
}
Warning("MergeRecursive", "object type without Merge function will be added unmerged, name: %s title: %s",
obj->GetName(), obj->GetTitle());
TH1::AddDirectory(addDirStat);
return kTRUE;
}
}
if ( obj ) {
target->cd();
if(obj->IsA()->InheritsFrom( "TDirectory" )) {
} else if(obj->IsA()->InheritsFrom( "TTree" )) {
if (!fNoTrees) {
globChain->ls();
if (fFastMethod) globChain->Merge(target->GetFile(),0,"keep fast");
else globChain->Merge(target->GetFile(),0,"keep");
delete globChain;
}
} else if (obj->IsA()->InheritsFrom( "TCollection" )) {
obj->Write( key->GetName(), TObject::kSingleKey );
} else {
obj->Write( key->GetName() );
}
}
oldkey = key;
}
first_source = (TDirectory*)sourcelist->After(first_source);
}
target->SaveSelf(kTRUE);
if (!isdir) sourcelist->Remove(sourcelist->First());
TH1::AddDirectory(addDirStat);
return kTRUE;
}
Last change: Wed Jun 25 08:39:04 2008
Last generated: 2008-06-25 08:39
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.