CFileMan
The CFileMan
class provides file management
functionality, but unlike the corresponding functionality provided by class
RFs
, CFileMan
can operate on files and
directories located throughout a directory hierarchy.
CFileMan
lets you:
copy files
move files
delete files
rename files
delete directories and their contained files and sub-directories
set and clear file attributes.
The functions provided by the class accept the use of wildcards, and means that some operations may take time to complete. The class, however, provides both synchronous and asynchronous variants.
All of the file manipulation functions except Rename()
can
operate recursively, and all can operate non-recursively. When operating
recursively, these functions will act on all matching files located throughout
the source directory's hierarchy. When operating non-recursively, these
functions act upon files contained in the single top level source directory
only. Recursion is set or unset using the switch parameter to these functions.
Typically, a CFileMan
operation can result in a
number of file/directory manipulation operations, especially if wild cards are
used. Some operations, such as copying files, can take a (relatively) long
time, especially if such files are large.
Symbian OS provides a file notification observer interface that you can
implement to provide notification of events resulting from
CFileMan
operations. The interface is defined by the
MFileManObserver
class, and you provide an implementation
for the functions:
Symbian OS calls the notification functions before or after each file
or directory entry has been processed, or during a file copy or move operation.
You can use the notification to provide information about the state of the
operation, such as error codes, the names of the target and destination files,
and the number of bytes transferred during a copy operation. This information
is available to your implementation by calling the public functions in
CFileMan
and its base class
CFileBase
:
You can also use the notification function to cancel, retry or continue
processing a file or directory, or to abort the whole operation, by returning a
suitable MFileManObserver::TControl
value.
This mechanism provides a way for an application to provide feedback, or to give control over such operations to an end-user through its user interface.
The following example code shows how you might use this. It is not a
complete example, but it gives you an idea of what's possible. The example
attempts to copy all files from directory C:\path1
to
c:\path2
synchronously.
You would need to elaborate on this to make it part of a real
application, and you would probably need the use of active objects, especially
if using the asynchronous versions of the CFileMan
functions.
...
_LIT(KSourcePath,"C:\\path1\\*.*");
_LIT(KDestinationPath,"C:\\path2");
// Connect session
RFs fsSession;
User::LeaveIfError(fsSession.Connect());
// Create file management object
CFileMan* fileMan = CFileMan::NewL(fsSession);
CleanupStack::PushL(fileMan);
// Create file management notification object and set to observe
TFileCopyProgressMonitor fileCopyProgressMonitor(*fileMan);
fileMan->SetObserver(&fileCopyProgressMonitor);
// Do copy (here synchronously)
fileMan->Copy(KSourcePath,KDestinationPath);
// Clean up
CleanupStack::PopAndDestroy();
// close file server session
fsSession.Close();
...
class TFileCopyProgressMonitor : public MFileManObserver
{
public :
TFileCopyProgressMonitor(CFileMan& aFileMan);
public : // implement the interface
TControl NotifyFileManStarted();
TControl NotifyFileManOperation();
TControl NotifyFileManEnded();
public :
CFileMan& iFileMan;
}
TFileCopyProgressMonitor::TFileCopyProgressMonitor(CFileMan& aFileMan)
:iFileMan(aFileMan)
{
}
// Called when a copy operation started
MFileManObserver::TControl TFileCopyProgressMonitor::NotifyFileManStarted()
{
TFileName& aFile
// Get name of file we are copying.
// you might want to do something with this, such as display in a UI,
// or save in a data member of this object for later use.
iFileMan.GetCurrentSource(aFile);
// Allow the operation to continue.
return EContinue;
}
// Called while a copy operation is in progress
MFileManObserver::TControl TFileCopyProgressMonitor::NotifyFileManOperation()
{
TInt bytesTransferred;
// number of bytes copied so far for the file.
bytesbytesTransferred = iFileMan.BytesTransferredByCopyStep();
// Allow the operation to continue.
// You would choose to do something different; for example, you could
// return ECancel to cancel the operation if you had a reason to do so,
return EContinue;
}
// Called when a copy operation is complete
MFileManObserver::TControl TFileCopyProgressMonitor::NotifyFileManEnded()
{
TInt lasterror;
// Allow operations to continue if all is well.
lasterror = iFileMan.GetLastError();
if (lasterror == KErrNone)
{
return EContinue;
}
// Operation has not completed properly, so you might want to get
// more information, and proceed accordingly.
TFileManError filemanerror;
filemanerror = iFileMan.GetMoreInfoAboutError();
if (filemanerror==ESrcOpenFailed)
{
...
return EAbort;
}
if (filemanerror==ETrgOpenFailed)
{
...
return EAbort;
}
... // you might want to check for other conditions etc.
}
This code fragment shows a use of the
CFileMan::Attribs()
functions.
_LIT(KDirText,"\\TopDir\\");
...
fileMan.Attribs(KDirText,KEntryAttHidden|KEntryAttReadOnly,
KEntryAttArchive,TTime(0),CFileMan::ERecurse);
...
This sets the hidden and read-only attributes, and clears the archive
attribute for all files located in the hierarchy below \TopDir\
.
The time of their last modification will be unchanged.
If you use CFileMan::Move()
, be aware that the
behaviour of this operation is sensitive to the presence (or absence) of a
trailing backslash ("\") character on the end of the source path:
if there is a trailing backslash ("\") character, then the operation moves the content of the last directory level only.
if there is no trailing backslash ("\") character, then the
operation moves both the last directory level and its content, but note that
you also need to specify CFileMan::ERecurse
in the
switches passed to the function.
For example, if the directory level "b" contains the files
F1
, F2
and F3
, then:
CFileMan fm;
...
fm->Move(_L("C:\a\b\"), _L("C:\x\y\"), CFileMan::ERecurse);
results in files F1
, F2
and
F3
being moved from C:\a\b
to C:\x\y
,
leaving the path C:\a\b
unchanged, except that it no longer
contains the files F1
, F2
and F3
.
If there is no trailing backslash character, for example:
CFileMan fm;
...
fm->Move(_L("C:\a\b"), _L("C:\x\y\"), CFileMan::ERecurse);
then both the directory level "b" and its contents are moved. This
means that there is no longer a directory "b" under C:\\a
. Instead
there is a new directory structure C:\x\y\b
and the files
F1
, F2
and F3
now exist under
C:\x\y\b
. Also if "b" contains subdirectories, then these are also
moved along with "b".
If you use CFileMan::Copy()
, the behaviour of
this function does not depend on the presence or absence of a
trailing backslash ("\") character on the end of the source path. This pattern
of behaviour is in contrast to that of
CFileMan::Move()
. You can only copy the content of the
source path. You cannot request that the last directory level plus its content
be copied to the target path, by adding a trailing backslash ("\") character
onto the end of the source path. This means that both of the following copy
operations produce identical results:
CFileMan fm;
...
fm->Copy(_L("C:\a\b\"), _L("C:\x\y\"), CFileMan::ERecurse);
fm->Copy(_L("C:\a\b"), _L("C:\x\y\"), CFileMan::ERecurse);
It is possible to pass KNullDesC
, the null (or
empty) descriptor, to the CFileMan::Delete()
functions as
the path name. Although you might expect these functions to treat this as a
null request, i.e. to delete nothing, they interpret the null descriptor as the
string \*.*
.