×
Namespaces

Variants
Actions

Fundamentals of Symbian C++/File Server

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata
Article
Created: hamishwillee (10 Jan 2011)
Last edited: hamishwillee (16 Dec 2011)

The file server handles all aspects of managing files and directories on the phone’s storage devices, and provides a consistent interface across ROM, RAM, Flash memory, removable media and even remote file systems accessed over HTTP. The file server process executable is EFILE.EXE, and its client-side interface is implemented in a DLL called EFSRV.DLL:

The Symbian File server architecture

The client-side handle to the file server is implemented by the RFs class, which derives from RSessionBase and is used to manipulate drives, directories and files.

Handles to individual files and directories are implemented by the RFile and RDir class respectively. They are implemented as sub-sessions so that a client can have multiple files and directories open in the context of a single thread without the overhead of multiple RFs session objects.

Contents

File Server Session

In order to use the file server, a caller must first create a file server session, represented by an instance of the RFs class.

Initialization and Cleanup

The file server session is initialized by calling Connect(), which returns an error code. The client is responsible for closing a connected file server session. If the session is a local variable, the client should use the cleanup stack to ensure that it is closed if a leave occurs.

RFs fs;
 
User::LeaveIfError(fs.Connect()); // Connect the session
 
CleanupClosePushL(fs); // Closes fs if a leave occurs
 
... // Use the file server
 
CleanupStack::PopAndDestroy(&fs); // Close the session

Using the Session

The file server session can be used for a large number of file system operations, including:

  • Open, create, delete and rename files and directories
  • Set directory and file attributes
  • Asynchronous notification of changes to files or directories
  • Information about drives and volumes
  • Adding and removing file system plug-ins

File

The RFile class is a sub-session of an RFs client session to the file server. An RFile object represents access to a named, individual file.

Initialization and Cleanup

There are four ways to initialize an RFile object:

RFile::Open() Open an existing file by name, returning KErrNotFound if the file does not exist or KErrAccessDenied if another client already has the file open for exclusive reading or writing.

Other common return values are KErrPathNotfound, KErrPermissionDenied (if the process doesn’t have the rights to access a file) and KErrBadName if the filename is not well formed.

RFile::Create() Create and open a new file with the name supplied; KErrAlreadyExists is returned if the named file already exists.
RFile::Replace() If a file with the name supplied does not exist, create a new one, otherwise delete the existing one and replace it with a new empty one.
RFile::Temp() Open a new temporary file and assigns a unique name to it.

A common pattern is to call Open() to attempt to open an existing file, without replacing any of its data, and to then call Create() if it does not yet exist.

RFile logFile;
 
TInt err=logFile.Open(fsSession,fileName,shareMode);
 
if (err==KErrNotFound) // file does not exist - create it
{
err=logFile.Create(fsSession,fileName,shareMode);
}

As with the file server session, the client is responsible for closing an open file by calling RFile::Close(), and should use the cleanup stack to ensure that local RFile objects are closed in the event of a leave.

File Mode

All four initialization functions take a TUint bitmask parameter containing a set of TFileMode values; these represent the access mode and share mode in which the file is to be opened.

The access mode indicates whether the file is opened only for reading (EFileRead) or for reading and writing (EFileWrite). This is OR-ed with the share mode, which indicates whether other RFile objects can access the file and if so, whether their access should be read-only or not.

Reading and Writing Binary Data

RFile provides Read() and Write() functions. Data is written into the file from a non-modifiable 8-bit descriptor (const TDesC8&) and read from the file into a modifiable 8-bit descriptor (TDes&).

// Open file server connection
 
RFs fs;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs);
 
// Open Example.ini file
_LIT(KExample,"c:\\Example.ini");RFile file;
User::LeaveIfError(file.Open(fs, KExample, EFileShareExclusive|EFileWrite));
CleanupClosePushL(fs);
 
// Write to the file
_LIT8(KWriteData,"Hello world");
User::LeaveIfError(file.Write(KWriteData));
 
// Read from the file
TBuf8<5> readBuf;
User::LeaveIfError(file.Read(readBuf));
// readBuf contains "Hello"
 
CleanupStack::PopandDestroy(2, &fs);

RFile provides overloads of Read() and Write():

  • Read/write a specified number of bytes
  • Read/write from/to a specified offset in the file
  • Read/write a specified number of bytes from/to a specified file offset
  • Asynchronous variants of all of them.

Reading and Writing 16-bit Descriptors

{icode|RFile} does not provide functions to read or write 16-bit descriptor data. The best way to do this is to use a read or write stream.

Sharing Files

Opened RFile objects can be passed between processes:

  • TransferToServer() and AdoptFromClient() enable a client to pass a file to a server
  • TransferToClient() and AdoptFromServer() enable a server to pass a file to a client
  • TransferToProcess() and AdoptFromCreator() enable one process to pass a file to another process.

See the Symbian Developer Library for details of how to share files.

File Names

Files on Symbian OS are identified by a file name specification that may be up to 256 characters in length. As in DOS, a file specification consists of:

  • A device, or drive, such as c:
  • A path, such as \Document\Unfiled\, where the directory names are separated by backslashes (\)
  • A file name
  • An optional file name extension, separated from the file name by a period (.).

Subject to the overall limitation of 256 characters, a directory name, file name or extension may be of any length. The RFs::IsValidName() method returns a boolean value to indicate whether a path name is valid.

The Symbian platform file system supports up to 26 drives, from a: to z:. This usually includes one or more read-only drives, the internal non-volatile read/write drive, and one or more removable nonvolatile read/write drives.

The internal persistent read/write drive can is returned by a call to RFs::GetSystemDriveChar: clients must not assume that it is the c: drive.

The file system preserves the case of file and directory names, but all operations on those names are case-independent. This means that there cannot be two or more files in the same directory with names that differ only in the case of some of their letters.

Filenames can be manipulated using the TParse class. TParse is initialized with a full file specification (for example, z:\resource\apps\myapp.rsc) and its accessors provide access to drive, path, file, extension components.

File Server Good Practice

A full file specification can be represented with a TFileName object: this is a TBuf16<256>. Since it is a large object (512 bytes), it should – if possible – not be allocated on the stack.

Connections to the file server consume kernel resources and a significant footprint in the file server process, so it is good practice to store and re-use file server connections if possible, and to design APIs that take file server sessions, and files, as parameters instead of filenames. Additionally, applications that use Symbian’s CONE (Control Environment) framework always have access to a connected file server session via CCoeEnv::FsSession().

You should aim to minimize the number of individual read/write requests that you make by buffering. For example, reading a file a byte at a time is very inefficient: prefer to read larger sections of it into a client-side buffer and then iterate through that. This is particularly relevant for porting code, since POSIX buffers reads and writes client side, which makes single-byte reads and writes much faster.

In connection to this, the Symbian file server by default guarantees that when write functions complete (on return for synchronous variants or TRequestStatus completion for asynchronous variants) every byte is committed to disk. This is very different to Linux, which may keep it in a memory cache.


Licence icon cc-by-sa 3.0-88x31.png© 2010 Symbian Foundation Limited. This document is licensed under the Creative Commons Attribution-Share Alike 2.0 license. See http://creativecommons.org/licenses/by-sa/2.0/legalcode for the full terms of the license.
Note that this content was originally hosted on the Symbian Foundation developer wiki.

This page was last modified on 16 December 2011, at 07:28.
94 page views in the last 30 days.
×