class io.FileStream

Overview

This class provides high-level asynchronous streaming interface for reading from and writing to files or devices. More…

import "io_base.jncx"
import "io_FileStream.jnc"

class FileStream {
    // fields

    io.FileStreamEvents readonly volatile m_activeEvents;
    std.Error const* readonly volatile m_ioError;
    bool readonly m_isOpen;

    // properties

    uint_t autoget property m_readParallelism;
    size_t autoget property m_readBlockSize;
    size_t autoget property m_readBufferSize;
    size_t autoget property m_writeBufferSize;
    io.FileStreamOptions autoget property m_options;
    uintptr_t const property m_osHandle;
    io.FileKind const property m_kind;

    // construction

    construct();
    destruct();

    // methods

    bool errorcode open(
        string_t name,
        io.FileOpenFlags flags = 0
    );

    void close();
    void unsuspend();
    bool errorcode clear();

    size_t errorcode read(
        void* p,
        size_t size
    );

    size_t errorcode write(
        void const* p,
        size_t size
    );

    long errorcode wait(
        io.FileStreamEvents eventMask,
        void function* handler(io.FileStreamEvents triggeredEvents)
    );

    bool errorcode cancelWait(long handle);

    io.FileStreamEvents blockingWait(
        io.FileStreamEvents eventMask,
        uint_t timeout = -1
    );

    import io.FileStream.FileStreamEvents async asyncWait(io.FileStreamEvents eventMask);

    // aliases

    alias dispose = close;
};

Detailed Documentation

This class provides high-level asynchronous streaming interface for reading from and writing to files or devices.

Besides all the standard methods of io.File (like open, read, write etc) io.FileStream also notifies its clients of events occured on this file stream such as when data has arrived and could be read or when IO error occured. This allows for clean and convenient asynchronous event-driven IO programming.

A typical sequence of steps when working with a file stream looks something like this:

  • Open a file stream with open method;

  • Assign IO event handler with wait method. You would probably also want to schedule your event handler to be run in particular environment(e.g., in a specific thread) and partially apply some syncrhonization ID to discard late events;

  • When io.FileStreamEvents.IncomingData event is fired, read from the file using read method;

  • Write to the file stream using write method;

  • Suspend writing if the return value of write is less than requested;

  • Resume writing on io.FileStreamEvents.WriteBufferReady event;

  • Close the file stream when no longer needed with close method.

Sample code:

class MyDialog {
    // ...

    io.FileStream m_fileStream;
    uint_t m_syncId;

    void open(string_t fileName);
    void close();
    void waitFileStreamEvents();

    void onWriteButtonClicked();

    void onFileStreamEvent(
        uint_t syncId,
        io.FileStreamEvents triggeredEvents
    );
}

MyDialog.open(string_t fileName) {
    bool result = try m_fileStream.open(fileName);
    if (!result) {
        string_t errorString = std.getLastError().m_description;
        // ...
    }

    waitFileStreamEvents();
}

MyDialog.close() {
    m_fileStream.close();
    m_syncId++; // events past this point will be discarded as 'late'
}

MyDialog.waitFileStreamEvent() {
    io.FileStreamEvents eventMask =
        io.FileStreamEvents.IoError |
        io.FileStreamEvents.IncomingData;

    m_fileStream.wait(eventMask, onFileStreamEvent ~(++m_syncId) @
        g_mainThreadScheduler);
}

MyDialog.onWriteButtonClicked() {
    static char data[] = "a quick brown fox jumps over the lazy dog";
    m_fileStream.write(data, sizeof(data));
}

MyDialog.onFileStreamEvent(
    uint_t syncId,
    io.FileStreamEvents triggeredEvents
) {
    if (syncId != m_syncId) // late event
        return;

    if (triggeredEvents & io.FileStreamEvents.IoError) {
        string_t errorString = m_fileStream.m_ioError.m_description;
        // ...
    }

    if (triggeredEvents & io.FileStreamEvents.IncomingData) {
        char buffer[256];
        size_t size = m_fileStream.read(buffer, sizeof(buffer));
        // ...
    }

    waitFileStreamEvents(); // restart wait
}

See also:

io.FileStreamEvents, io.File, io.NamedPipe, io.Mailslot

Fields

bool readonly m_isOpen

Holds the open status for the file stream, i.e. true if opened; false otherwise.

Properties

io.FileKind const property m_kind

Specifies the type of the file stream(regular disk file, serial port etc). For the full list of supported file stream types, refer to io.FileKind.

This field is currently only initialized on Windows. To to detect the type io.FileStream uses WinAPI function GetFileType.

Methods

bool errorcode open(
    string_t name,
    io.FileOpenFlags flags = 0
)

Opens or creates a file stream.

The function accepts two arguments. The first one, name specifies the name of the file/device. The second one, flags, can be used to specify open options. Check io.FileOpenFlags for the complete list of options.

Returns true on success. If the file stream could not be opened, IO error supplied by operating system is set and then the function returns false [1].

void close()

Closes a previously opened file stream, does nothing if the file stream is not opened. This function always succeeds.

Sometimes it may be convenient to use disposable pattern to ensure timely invokation of close [2].

void unsuspend()

Accepted named pipes may initially be suspended (so that the user has a chance to configure reading options such as m_readBlockSize)

Call start to awaken the accepted pipe after it has been configured.

bool errorcode clear()

Clears the file, destroying all its contents. This function is only applicable to regular disk file streams.

Returns true on success. If clear operation is unsuccessful, IO error supplied by the operating system is set and then the function returns false [1].

size_t errorcode read(
    void* p,
    size_t size
)

Attempts to read up to size bytes from the file strean into the buffer pointed to by p.

Returns the actual amount of bytes read on success. If read operation is unsuccessful, IO error supplied by the operating system is set and then the function returns -1 [1].

Normally you would call this function from within your event handler for IncomingData event. If this function is called when there is no incoming data, it blocks until either the data arrives, or the file is closed.

size_t errorcode write(
    void const* p,
    size_t size
)

Attempts to write size bytes from the buffer pointed to by p into the file stream.

Returns the actual amount of bytes written on success. If write operation is unsuccessful, IO error supplied by the operating system is set and then the function returns -1 [1].

If the return value shows less bytes than specified by size argument, you should suspend further transmission until the file stream is ready to accept more data. When this happens, WriteBufferReady event is fired and transmission could be resumed.

Aliases

alias dispose = close

Effectively makes io.FileStream a disposable class [2].


Footnotes