Using files

Using files in jolie is very simple. There standard library file provides a set of useful operations for managing files. In this tutorial we show:

  • how to read from a file;
  • how to write to a file;
  • how to send the content of a file from a service to another.

Reading a file

In this simple example, whose code can be checked at this link, we show how to read the content of a file and print out it on the console. In the following we present a jolie script which reads from file test.txt and prints its content on the console using println@console.

from file import File from console import Console service Example { embed Console as console embed File as file main { readFile@file( { filename = "test.txt"} )( response ) println@console( response )() } }

Note that it is important to import jolie from file import Fileand embed jolie embed File as file the into the service from the standard library then it is sufficient to use operation readFile@file for reading from the file. The operation readFile@file requires the filename. The content is then stored into variable response and it can be easily printed out using println@console.

Writing a file

As for the reading of a file, writing a file uses the standard library file and in particular we exploit the operation writeFile@file. In the following we show a script which creates a file called test.txt and writes the string this is a test message. The full code of the example may be consulted at this link

from file import File service Example{ embed File as file main { writeFile@file( { filename = "test.txt" content = "this is a test message" } )() } }

Note that the operation writeFile@file requires at least two parameters: the filename and the content of the file.

Communicating the content of a file

Now, let's step forward creating a simple system where a server receives the content from a source file read by the client, and appends it to a receiving file. The full example can be checked at this link. The example uses the following file structure

. +-- ServerInterface.ol +-- server.ol +-- client.ol

The interface of the server follows can be found in ServerInterface.ol:

interface ServerInterface { RequestResponse: setFileContent( string )( void ) }

Note that it is very simple and it just defines a single operation which is able to receive a string.The code of the server is :

from .ServerInterface import ServerInterface from file import File constants { FILENAME = "received.txt" } service ExampleServer { embed File as file inputPort server { Location: "socket://localhost:9000" Protocol: sodep Interfaces: ServerInterface } execution:concurrent main { setFileContent( request )( response ) { writeFile@file( { filename = FILENAME content = request append = 1 } )() } } }

The server is waiting to receive a message on operation setFileContent, once received it appends the message into the file received.txt. Note that the appending capability is enabled setting the parameter append of the operation writeFile@file to 1.

On the other hand, the client reads a content from a file and sends it to the server:

from .ServerInterface import ServerInterface from file import File service ExampleClient{ embed File as file outputPort server { Location: "socket://localhost:9000" Protocol: sodep Interfaces: ServerInterface } main { readFile@file( {filename = "source.txt"} )( content ) setFileContent@server( content )() } }

Communicating raw contents

Let's now concluding this tutorial showing how to manage also binary files. So far indeed, we dealt only with text files where their content is always managed as a string. In general, we could require to manage any kind of files. In the following we show hot to read, communicate and write the binary content of a file. We propose the same scenario of the section above where there is a client which reads from a file and sends its content to a server, but we show how to deal with binary files. The full code of the example may be consulted at this link. Like in previous example the following file structure is used.

. +-- ServerInterface.ol +-- server.ol +-- client.ol

The interface of the server changes as it follows:

type SetFileRequest: void { .content: raw } interface ServerInterface { RequestResponse: setFile( SetFileRequest )( void ) }

Note that the request type of operation setFile has a subnode called .content whose native type is set to raw. raw is the native type used in jolie messages for sending binaries. Let us now see how the client works:

from .ServerInterface import ServerInterface from file import File constants { FILENAME = "received.pdf" } service ExampleServer { embed File as file inputPort server { Location: "socket://localhost:9000" Protocol: sodep Interfaces: ServerInterface } execution: concurrent main { setFile( request )( response ) { writeFile@file( { .filename = FILENAME; .content = request.content; .format = "binary" })() } } }

Note that the approach is the same of that we used for string contents with the difference that we specify also the parameter format="binary" for the operation readFile@file. Such a parameter enables jolie to interpreting the content of the file as a stream fo bytes which are represented as the native type raw. It is worth noting that the content of the reading is directly stored into the variable rq.content, this is why we just send variable rq with operation setFile.

On the server side the code is:

from .ServerInterface import ServerInterface from file import File service ExampleClient{ embed File as file outputPort server { Location: "socket://localhost:9000" Protocol: sodep Interfaces: ServerInterface } main { readFile@file( { filename = "source.pdf" format = "binary" } )( rq.content ) setFile@server( rq )() } }

Also in this case we enable the usage of binaries setting the parameter format="binary" for operation writeFile. Note that in this example the file read is a PDF file.