The Storage Kit: BFile

Derived from: public BStore

Declared in: <storage/File.h>


Overview

The BFile class defines objects that represent files in the file system. Files are containers of data that live in directories. A file can live in only one directory at a time.

BFile inherits from BStore; the basic concepts of how file system objects work are explained in the BStore description. The most important points, applied to BFiles, are these:


BFile Data

BFiles contain "flat" or unstructured data. They're commonly used to store ASCII documents, for example. If you want to associate structured header information with a file (if you want a complementary "resource fork"), you can do one (or more) of the following:


Locating and Creating Files

Most of the functions that locate, create, and otherwise "externally" manipulate files are defined by the BStore and BDirectory classes. The most important of these are:

Defined in BStore:

Defined in BDirectory

  • GetFile() locates a file by name or index (into a directory) and refers a BFile to it.

  • Create() creates a new file in the file system, and refers a BFile to it.

  • Remove() removes a file from the file system.
  • The BFile class itself adds two whole-cloth file manipulation functions:


    Opening and Closing Files

    Before examining or manipulating a file, you have to open the BFile that refers to it by calling the Open() function. The object remains open until the Close() function is called.

    The Open() function takes a single argument that you use to specify the file's "open mode". The constants that represent these modes are:


    Reading and Writing Files

    BFile's Read() and Write() functions are the means by which you examine and modify the data that lies in a file. They operate much as you would expect: For example, the BFile must be open in the appropriate mode, they read or write some number of bytes of data, and successive Read() or Write() calls read or write contiguous sections of the file.

    An important point with regard to Read() and Write() is that they're not virtual. If you create a BFile-derived class because, for example, you want to read in units of longs rather than bytes, you have to create your own reading function (which might invoke Read()) and give it a different name. (This is what the Media Kit's BSoundFile class does: It reads "frames" of sound through the ReadFrames() function).


    Hook Functions

    FileCreated() Invoked when a new file is created. You implement this function in a BFile-derived class to perform class-specific initialization. This initialization can include modification of the new file's BRecord.


    Constructor and Destructor


    BFile()

           BFile(void)

    The BFile constructor creates a new, unreferenced object, and returns a pointer to it. The object won't correspond to an actual file until its record ref is set. You can set the ref directly by calling the SetRef() function, or you can allow the ref to be set as a side effect by passing your BFile object as an argument to any of these functions:

  • BFile::CopyTo()

  • BDirectory::Create()

  • BDirectory::GetFile()

  • ~BFile()

          virtual ~BFile(void)

    Destroys the BFile object; this doesn't remove the file that the object corresponds to (to remove a file, use BDirectory's Remove() function). The object is automatically closed (through a call to Close()) before the object is destroyed.

    See also: Close()


    Member Functions


    Close()

          virtual long Close(void)

    Closes the BFile. The object's BRecord is automatically committed to the database when you call this function.

    You should be aware that Close() is called automatically by the BFile destructor, and by BDirectory's Remove() function.

    The BFile must previously have been opened through an Open() call. If the object isn't open (or, more broadly, if the BFile's ref hasn't been set), Close() returns B_ERROR; otherwise, B_NO_ERROR is returned.

    See also: Open()


    CopyTo()

          long CopyTo(BDirectory *toDir, 
             const char *newName, 
             BFile *newFile,
             store_creation_hook *createHook = NULL, 
             void *createData = NULL,
             copy_status_hook *copyHook = NULL)

    Makes a copy of the BFile's file, moves the copy into the directory given by toDir, names it newName, and returns a new BFile object (by reference in newFile) that refers to the new file.

    The newName argument must be supplied--if you want to copy the file but retain the same name as the original file, pass this_object->Name() as the argument's value. You can also copy a file into the same directory (by passing this_object->Parent() as the toDir argument); in this case, however, you must supply a different name for the copied file.

    The BRecord that's created for the new BFile will conform to the same table as the BRecord of the original BFile (by default, this is the Kit-defined "File" table). Furthermore, the values in the new BRecord are copied from the original file's BRecord (with some obvious changes, such as the file's name, its parent, and so on). The new BRecord is committed just before CopyTo() returns. The CopyTo() function automatically commits the original object's BRecord as well.

    If the new BRecord conforms to a custom table, you may want to modify the new BRecord before it's committed. The two "create" arguments provide this ability:

    For more information on the use of the store creation hook mechanism, see The File Creation Hook .

    The final argument, copyHook is a "copy status hook" function. This function, if supplied, is invoked periodically as the copy operation progresses. The protocol for the hook is

    long copy_status_hook_name(record_ref ref , int size_delta, void *no_op)

    The ref argument is the ref of the file that's being copied from; size_delta is the amount of data that's been copied from the source file into the destination file since the last time the hook function was called; the final argument is currently unused. If the hook function returns a value other than B_NO_ERROR, the copy operation is halted, but the data that's already been copied isn't erased.

    The rules governing the ability to copy a file into a specific directory are the same as those that apply to creating a file in that directory. Again, see the BDirectory::Create() function for more information.

    The target BFile must be closed for the CopyTo() function to work. If the BFile couldn't be copied (for whatever reason) B_ERROR is returned; otherwise, B_NO_ERROR is returned.

    See also: SwitchWith() , BDirectory::Create() , BStore::MoveTo()


    FileCreated()

          virtual long FileCreated(void)

    This is a hook function that's automatically invoked when a new file is created. Specifically, it's invoked by BDirectory's Create() function and BFile's CopyTo() function. You can implement this function in a derived class to perform file-initialization operations. The file that's being created, in the context of the implementation, is referred to by the this pointer. The store creation hook that was passed to Create() or CopyTo() will already have been called and the file's record will have been committed by the time this function is invoked.

    There are no restrictions on the operations that this function may perform; for example, you can implement FileCreated() to open and write the file, or modify and commit the file's record. Keep in mind, however, that the file's record will already have been committed for the first time just before this function is invoked.

    You can stop the file from being created by implementing the function to return a value other than B_NO_ERROR.


    GetTypeAndApp() see SetTypeAndApp()


    Open(), OpenMode(), IsOpen()

          virtual long Open(long mode)
          long OpenMode(void)
    
          bool IsOpen(void)

    The Open() function opens the BFile so its file's data can be read or written (or both). The file remains open until Close() is called.

    The operations you can perform on an open file depend on the mode argument:

    Note that the B_EXCLUSIVE mode doesn't prevent changes to the file that can be performed while the file is closed. For example, some other actor can delete the file (through the command line, Browser, or BDirectory's Remove() function) while your BFile holds the file open in exclusive mode.

    If the BFile's ref hasn't been set, if some other BFile has the file open in B_EXCLUSIVE mode, if the mode argument isn't one of the values listed here, or if, for any other reason, the file couldn't be opened, Open() returns B_ERROR . Upon success, it returns B_NO_ERROR.

    OpenMode() returns the mode that the file was opened with. In addition to the three modes listed above, the function can also return B_FILE_NOT_OPEN if the BFile isn't open.

    IsOpen() returns TRUE if the BFile is open, and FALSE if not.

    See also: Close(), Read(), Write() , Seek()


    Read()

          long Read(void *data, long dataLength)

    Copies (at most) dataLength bytes of data from the file into the data buffer. The function returns the actual number of bytes that were read --this may be less than the amount requested if, for example, you asked for more data than the file actually holds.

    The BFile's data pointer is moved forward by the amount that was read such that a subsequent Read() would begin at the following "unread" byte. Freshly opened, the pointer is set to the first byte in the file; you can reposition the pointer prior to a Read() call through the Seek() function. Keep in mind that the same data pointer is used for reading and writing data.

    For this function to work, the BFile must already be open. If the object isn't open, or if, for any other reason, the file couldn't be read, the function returns B_ERROR .

    See also: Open(), Seek() , Write()


    Seek

          long Seek(long byteOffset, long relativeTo)

    Relocates the BFile's data pointer. The location that you want the pointer to assume is given as a certain number of bytes (byteOffset) relative to one of three positions in the data. These three positions are represented by the following constants (which you pass as the value of relativeTo):

  • B_SEEK_TOP represents the beginning of the file.

  • B_SEEK_MIDDLE represents the pointer's current location.

  • B_SEEK_BOTTOM represents the end of the file.
  • For example, the following moves the pointer five bytes forward from its present position:

       aFile->Seek(5, B_SEEK_MIDDLE)

    If byteOffset is negative, the pointer moves backwards. Here, the pointer is set to five bytes from the end of the file:

       aFile->Seek(-5, B_SEEK_BOTTOM)

    If you seek to a position beyond the end of a file, the file is padded with uninitialized data to make up the difference. For example, the following code doubles the size of aFile:

       aFile->Seek( aFile->Size() * 2, B_SEEK_TOP)

    Keep in mind that the padding is uninitialized; if you want to pad the file with NULLs (for example), you have to write them yourself.

    The function returns the pointer's new location, in bytes, reckoned from the beginning of the file. You can use this fact to get the pointer's current position in the file:

       /* The inquisitive, no-op seek. */
       long currentPosition = aFile->Seek(0, B_SEEK_MIDDLE);

    Seek() is normally followed by a Read() or Write() call. Note that both of these functions move the pointer by the amount that was read or written.

    For the function to succeed, the BFile must already be open; B_ERROR is returned if the object isn't open.

    Warning: Currently, seeking before the beginning of a file isn't illegal. Doing so doesn't affect the size or content of the file, but it does move the pointer to the requested (negative) location. The Seek() function will return this location as a negative number. A subsequent read or write on that location will cause trouble.

    See also: Open(), Read(), Write()


    SetRef()

          virtual long SetRef(record_ref ref)
          virtual long SetRef(BVolume *volume, record_id recID)

    Sets the BFile's ref. The BStore class defines the basic operations of these functions. These versions add a BFile-specific wrinkle: They close the object before setting the ref.

    See also: BStore::SetRef()


    SetTypeAndApp(), GetTypeAndApp()

          long SetTypeAndApp(ulong type, ulong app)
          long GetTypeAndApp(ulong *type, ulong *app)

    These functions set and return, respectively, constants that represent the file's contents (its "type"), and the application that created the file. The Browser uses these constants to display an icon for the file, and to launch the appropriate application when the file is opened.

    If the application that you're designing creates new files, you should set the type and app for these files through SetTypeAndApp() (this information isn't set automatically). The app value must be an application signature. You can retrieve your application's signature through BApplication::GetAppInfo() .

    When the Browser tells an application to open a file, the app can use GetTypeAndApp() to look at the file's type constant to determine how the file should be opened. You can use one of the data type values declared in app/AppDefs.h as the type value, but understand that type needn't be globally declared (as constrasted with app): The type that you set can be privately meaningful to the application.

    If you want to set a file's type so the Browser will take it to be an application, use the value 'BAPP'. The app argument, in this case, is ignored (by the Browser, at least).

    With regard to icons: The Icon World application lets you create the correspondence between an application and its icon, as well as between the file types that the application recognizes and the icon that's displayed for each type. See "Notes on Developing a Be Application" for more information on Icon World.

    Note: In contrast to most of BFile's other functions, SetTypeAndApp() and GetTypeAndApp() operate properly if the BFile is closed. Moreover, the functions are actually more reliable if the object is closed.

    Both functions return B_ERROR if they fail, B_NO_ERROR otherwise. Note that the app value (for SetTypeAndApp()) isn't checked to make sure that it identifies a recognized application.


    Size()

          long Size(void)
          long SetSize(long newSize)

    Size() returns the size of the file's data, in bytes. The BFile needn't be open.

    SetSize() sets the size of the file, in bytes. The BFile must be open and writable.

    The functions return B_ERROR if the BFile's ref hasn't been set, or if the BFile's record has disappeared. In addition, SetSize() returns B_ERROR if the file isn't open in the proper mode; otherwise it returns B_NO_ERROR .


    SwitchWith()

          long SwitchWith(BFile *otherFile)

    Causes the receiving BFile and the argument object to trade data. The files' records are not switched. Both objects must be closed.

    SwitchWith() is provided as an efficient way to create a back-up file for files that your application is writing. Here's how you're supposed to use it:

    Let's say you've written an application that can open, read, and write files. The user uses your app to open a file called "MyText". You application creates and opens a BFile (MyTextFile) that refers to the file. It then allocates a buffer to hold the file's data, and copies the file's data (or as much as it thinks it will need) into the buffer. It also creates a second BFile (tmpFile) as a copy of the original (through CopyTo()) called "tmp". As the user works, your application occasionally writes the current state of the buffer to the tmpFile. When the user tells the application to save, the app closes both files and invokes SwitchWith():

       MyTextFile->SwitchWith(tmpFile)

    Your app then re-opens tmpFile (which now holds the previously saved version that it just got from MyTextFile) and brings it back up to date.

    You could get the same result by calling CopyTo() (copying from the "tmp" file to the original file) every time the user saves, but the SwitchWith() function is much faster.

    See also: CopyTo()


    Write()

           long Write(const void *data, long length)

    Copies length bytes from the data buffer into the object's file. The data is copied starting at the data pointer's current position; the existing data at that position (and extending for length bytes) is overwritten. The size of the file is increased, if necessary, to accommodate the new data. When this function returns, the data pointer will point to the first byte that follows the newly copied data.

    The function returns the number of bytes that were actually written; except in extremely unusual situations, the returned value shouldn't vary from the value you passed as length.

    The object must already be open for this function to succeed. If it isn't open, or if, for any other reason, the data couldn't be written, B_ERROR is returned.

    See also: Open(), Seek() , Read()




    The Be Book, HTML Edition, for Developer Release 8 of the Be Operating System.

    Copyright © 1996 Be, Inc. All rights reserved.

    Be, the Be logo, BeBox, BeOS, BeWare, and GeekPort are trademarks of Be, Inc.

    Last modified September 6, 1996.