import ballerina/io;
function getFileCharacterChannel (string filePath, string permission, string encoding) returns
io:CharacterChannel {
    io:ByteChannel channel = io:openFile(filePath, permission);
    var result = io:createCharacterChannel(channel, encoding);
    match result {
        io:CharacterChannel charChannel => {
            return charChannel;
        }
        io:IOError err => {
            throw err;
        }
    }
}
function readCharacters (io:CharacterChannel channel, int numberOfChars) returns string {
    var result = channel.readCharacters(numberOfChars);    match result {
        string characters => {
            return characters;
         }
        io:IOError err => {
            throw err;
        }
    }
}
function writeCharacters (io:CharacterChannel channel, string content, int startOffset) {
    var result = channel.writeCharacters(content, startOffset);
    match result {
      int numberOfCharsWritten =>{
          io:println(" No of characters written : " + numberOfCharsWritten);
       }
      io:IOError err => {
          throw err;
      }
    }
}
function process (io:CharacterChannel sourceChannel,
                  io:CharacterChannel destinationChannel) {
    string greetingText;
    string name;
    try {
        string intermediateCharacterString = " my name is ";
        greetingText = readCharacters(sourceChannel, 5);
        name = readCharacters(sourceChannel, 15);
        writeCharacters(destinationChannel, greetingText, 0);
        writeCharacters(destinationChannel, intermediateCharacterString, 0);
        writeCharacters(destinationChannel, name, 1);
    } catch (error err) {
        throw err;
    }
}function main (string[] args) {
    var sourceChannel = getFileCharacterChannel("./files/sample.txt", "r", "UTF-8");
    var destinationChannel = getFileCharacterChannel("./files/sampleResponse.txt", "w", "UTF-8");
    try {
        io:println("Started to process the file.");
        process(sourceChannel, destinationChannel);
        io:println("File processing complete.");
    } catch (error err) {
        io:println("error occurred while processing chars " + err.message);
    } finally {
        _ = sourceChannel.closeCharacterChannel();
        _ = destinationChannel.closeCharacterChannel();
    }
}

Character I/O

This demonstrates how characters could be read and written through I/O APIs.

import ballerina/io;
function getFileCharacterChannel (string filePath, string permission, string encoding) returns
io:CharacterChannel {

This function returns a CharacterChannel from a given file location, according to the permissions and encoding that you specify.

    io:ByteChannel channel = io:openFile(filePath, permission);

First, get the ByteChannel representation of the file.

    var result = io:createCharacterChannel(channel, encoding);
    match result {
        io:CharacterChannel charChannel => {
            return charChannel;
        }
        io:IOError err => {
            throw err;
        }
    }
}

Then, create an instance of the CharacterChannel from the ByteChannel to read content as text.

function readCharacters (io:CharacterChannel channel, int numberOfChars) returns string {

This function reads characters from ‘channel’, which is an instance of CharacterChannel.

    var result = channel.readCharacters(numberOfChars);

This is how the characters are read.

    match result {
        string characters => {
            return characters;
         }
        io:IOError err => {
            throw err;
        }
    }
}
function writeCharacters (io:CharacterChannel channel, string content, int startOffset) {

This function wrties characters to ‘channel’

    var result = channel.writeCharacters(content, startOffset);
    match result {
      int numberOfCharsWritten =>{
          io:println(" No of characters written : " + numberOfCharsWritten);
       }
      io:IOError err => {
          throw err;
      }
    }
}

This is how the characters are written.

function process (io:CharacterChannel sourceChannel,
                  io:CharacterChannel destinationChannel) {
    string greetingText;
    string name;
    try {

This function reads content from a file, appends the additional string, and writes the content.

        string intermediateCharacterString = " my name is ";

Here is the string that is appended in-between.

        greetingText = readCharacters(sourceChannel, 5);

The first five characters in the source file contain the greeting.

        name = readCharacters(sourceChannel, 15);

This is a request for the next set of characters in the file.

        writeCharacters(destinationChannel, greetingText, 0);

Here is how the greeting is written to the destination file.

        writeCharacters(destinationChannel, intermediateCharacterString, 0);

Here is how the intermediate string is appended to the file.

        writeCharacters(destinationChannel, name, 1);
    } catch (error err) {
        throw err;
    }
}

Here is how the remaining characters are written to the file, leaving an offset.

function main (string[] args) {
    var sourceChannel = getFileCharacterChannel("./files/sample.txt", "r", "UTF-8");
    var destinationChannel = getFileCharacterChannel("./files/sampleResponse.txt", "w", "UTF-8");
    try {
        io:println("Started to process the file.");
        process(sourceChannel, destinationChannel);
        io:println("File processing complete.");
    } catch (error err) {
        io:println("error occurred while processing chars " + err.message);
    } finally {
        _ = sourceChannel.closeCharacterChannel();
        _ = destinationChannel.closeCharacterChannel();
    }
}

Close the created connections.

$ ballerina run character-i-o.bal
Started to process the file.
File processing complete.