Input Output (IO)

Often one wants to store the results of their program runs. This is done by saving the data to a file or database. We will focus on storing to files.

To acheive this we will use the input output (here after abreviated IO) capabilites of Julia.

You have actually been using a type of output through out the previous modules. Printing to the console is a form of io, e.g. ```println(“hello world”)````

There is a corresponding way to read user input from the console however it doesn’t work in these Jupyter notebook so you need to run it in a regular julia file. Copy and paste the following lines of code into a julia file and run it locally. (Or run module-4-hello-input.jl)

print("Please Tell Me Your Name and Press Enter: ")
a = readline() #This line reads the text from the user in the console after they click the enter key. 
println("hello $(a)")

File IO

One of the most common type of IO is reading and writing to a file. There are many formats that we can store data on a file. Some common human readable formats:

  • Plain Txt (.txt extension)

  • Comma Separated Values (.csv extension)

  • Javascript Object Notation (.json extension)

We will show examples of reading and writing to all of these.

Writing to Plain Text

The first step is to create an object called an IOStream that points to the file we want to write to. Julia provides us the function open() to do this. The function takes two arguments:

  • The path of the file

  • a character code signifying what we are going to do with the file

    • r

      • read

    • w

      • write and overwrite exiting data in the file (truncate)

    • a

      • write and append to the end

    • r+

      • read, write

    • w+

      • read, write, create (a file that doesn’t exist yet), truncate truncate

    • a+

      • read, write, create, append

Next to write to the file we use the function write(). The first argument passed to write is our IOStream, the second is the text we want to write.

Finally you must close the IOStream (Otherwise other processes on the computer won’t be able to use it, i.e. you won’t be able to open it).

io = open("hello_output.txt", "w+"); 
write(io, "Hello File Output")
close(io)

After running the above code you should be able to open the file hello_output.txt and see its contents.

Now lets write other text to it using write and see that the data clears and puts in the new text.

io = open("hello_output.txt", "w+"); 
write(io, "Different Text \n") #the \n means create a new line after this text
close(io)

Now lets append instead:

io = open("hello_output.txt", "a"); 
write(io, "A second line of text \n")
close(io)

To make that \n more clear lets do one more append without it and see the result. (You can run this code over and over and it will keep writing on the same line.)

io = open("hello_output.txt", "a"); 
write(io, "A third line ")
write(io, "of text. ")
close(io)

Reading from Plain Text

Now we will read from a text file: hello_file_input.txt. The process is basically the same, but we will use the function readline() instead of write.

io = open("./hello_file_input.txt", "r"); 
our_input = readline(io) #reads one line from the file
close(io)

println(our_input)
line 1

Text files usually have more than one line, so we want a way to read all of the text. There are two ways of doing this. There are reasons for doing one or the other.

  • Use the readlines() function which returns all of the lines in an array of strings.

    • You know you want all the lines, the file is small enough that it doesn’t matter to get them all at once

  • Loop using the readline() funtion until the read method gives you an end of file message using the eof() function.

    • You are searching for specific text so you don’t need the whole file and can stop once you’ve found what you want, the file is too large to put into memory all at once, i.e. the file has more data than your computer has RAM ~16 GB.

Loop Read

io = open("./hello_file_input_multiline.txt", "r"); 
while !eof(io) # while the iostream has not reached the end of the file
    our_input = readline(io) #reads one line at a timee
    println(our_input)
    if our_input == "line 4"
        break # stop at line 4
    end
end
close(io)
line 1
line 2
line 3
line 4

readlines()

io = open("./hello_file_input_multiline.txt", "r"); 
our_input = readlines(io) #reads one line at a timee
for input in our_input
    println(input)
end 

close(io)
line 1
line 2
line 3
line 4
line 5

Comma Separated Lists

Comma separated lists are a convenient way to store tabular data (e.g. tables, matrices, spreadsheets). The following table

——-

——-

——

——-

—-

hello

table

text

here

is

some

stuff

1

4

3

8

8

8

8

8

would be represented as:

hello,table,text,here,is

some,stuff,1,4,3

8,8,8,8,8

You can see an example file here: example.csv

You can also open this file in Excel. You can also export excel files to csv. Export data to a text file by saving it

You can convert an Excel worksheet to a text file by using the Save As command: Detailed Instructions

  • Go to File > Save As.

  • Click Browse.

  • In the Save As dialog box, under Save as type box, choose the text file format for the worksheet; for example, click Text (Tab delimited) or CSV (Comma delimited).

There is also a vs-code extension to modify CSV files. Name: Edit csv VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=janisdd.vscode-edit-csv

Reading from CSV

Csv files are actually just text files, you don’t have to name them csv for this to work, you could have a text file with comma separated data, so we will read from them and write to them in the same way.

io = open("./example.csv", "r"); 
our_input = readlines(io) #reads one line at a time
for input in our_input
    println(input)
end 

close(io)
row1,row2,row3,row4,row5
39.765,61.974,49.116,98.257,39.836
17.807,63.734,77.89,42.989,34.118
60.773,78.374,30.569,81.741,25.595
93.595,80.359,8.917,13.898,63.927
32.753,51.49,21.208,71.139,86.566
40.095,33.315,35.285,64.109,63.314
22.353,56.237,53.043,26.098,66.377
3.748,86.25,43.815,13.613,95.699
86.384,70.958,36.108,34.371,67.863
21.923,96.298,7.348,52.789,53.525
94.17,41.767,84.59,8.32,27.025
56.678,98.974,47.716,8.437,99.16
82.14,38.983,10.205,90.33,11.064
70.442,76.169,43.986,96.74,92.048
51.474,96.682,73.766,61.426,43.427

What if we want to get the values from the csv and use them individually, for example putting them in a matrix and printing the matrix in a nice fasion using the display() function.

readline() and readlines() return a string or an array of strings representing the rows respectively. So we need to take two steps, take each row and split it into individual items and then put them in the correct place in the matrix. For this first example we will assume we know the size of the matrix up front.

io = open("./example.csv", "r"); 
our_input = readlines(io) #reads one line at a time
csv_values = zeros(15,5)
row = 1
for input in our_input[2:end] # for each skipping the first row (header) row
    row_values = split(input, ",")
    column = 1
    for value in row_values
        numerical_value = parse(Float64, value) # convert the string to a Float64
        csv_values[row,column] = numerical_value # put it in the matrix
        column += 1 # increment our column position in the row 
    end
    row += 1 #now that we have done all of the columns for the row, increment to the next row
end 
close(io)

display(csv_values)
15×5 Matrix{Float64}:
 39.765  61.974  49.116  98.257  39.836
 17.807  63.734  77.89   42.989  34.118
 60.773  78.374  30.569  81.741  25.595
 93.595  80.359   8.917  13.898  63.927
 32.753  51.49   21.208  71.139  86.566
 40.095  33.315  35.285  64.109  63.314
 22.353  56.237  53.043  26.098  66.377
  3.748  86.25   43.815  13.613  95.699
 86.384  70.958  36.108  34.371  67.863
 21.923  96.298   7.348  52.789  53.525
 94.17   41.767  84.59    8.32   27.025
 56.678  98.974  47.716   8.437  99.16
 82.14   38.983  10.205  90.33   11.064
 70.442  76.169  43.986  96.74   92.048
 51.474  96.682  73.766  61.426  43.427

I have also attached an example that does not assume it knows the amount of data in the csv. csv_print.jl In it I use the package CSV.jl and DataFrames.jl packages which handles all the CSV parsing for us.

Writing CSV

Here is a not very efficient but illustrative way of how to create a csv file

io = open("./write_to_csv.csv", "w+"); 
data = [1 2 3; 4 5 6; 7 8 9]
for i in 1:3
    for j in 1:3
        csv_text = "$(data[i,j])"
        if j != 3 #don't use comma if there
            csv_text =  csv_text * "," #concatenates the strings 
        end
        write(io, csv_text)
    end
    write(io, "\n") # add new line
end
close(io)

Again the better way to do this is using CSV.jl

using Tables, CSV
io = open("./write_to_csv_with_package.csv", "w+"); 
data = [1 2 3; 4 5 6; 7 8 9]
table  = Tables.table(data)
CSV.write(io, table)
close(io)

JSON (Javascript Object Notation)

JSON is a way of storing “object” data in a file that is human readable. Each property is denoted by a “NAME_OF_PROPERTY” then a : then the value for that property. Properties can be lists. The items which are comma separated and surrounded by []. You can read and write to JSON files using the JSON.jl package.

A simple example of a javascript object for a simple struct:

mutable struct Bike 
    weight :: Float64
    make :: String
    x_position :: Int
    y_position :: Int

end
{
    "weight" : 10.39,
    "make"  : "Trek",
    "x_position" : 10,
    "y_position" : -2
}

Here is a more complex example that is an export of the bike simulation, with arrays of data.

{
  "bikes": [
    {
      "bike_attributes": {
        "make": "Make1",
        "model": "Model1",
        "weight": 15.04,
        "drag_coefficient": 0.746
      },
      "x_position": 0,
      "y_position": 3
    },
    {
      "bike_attributes": {
        "make": "Make1",
        "model": "Model1",
        "weight": 19.4,
        "drag_coefficient": 0.597
      },
      "x_position": 2,
      "y_position": 99
    }
  ],
  "current_time": 5,
  "timed_bike_positions": [
    [
      [1, 1, 1, 0],
      [1, 1, 2, 3]
    ],
    [
      [1, 2, 1, 2],
      [100, 99, 99, 99]
    ]
  ],
  "simulation_run_time": 4
}

Note: The above JSON has been “pretty printed” so it is easier to read. The white spacing and multiple lines are not strictly necessary.

JSON parse method will return what is called a Dictionary. It is an object that has the ability to look up items in it by name using the following syntax:

my_dict = Dict()
my_dict["value"] = "hello"
my_dict["some_other_property"] = 1.23

println(my_dict["value"])
println(my_dict["some_other_property"])
hello
1.23

JSON Example Code

using JSON 

mutable struct Bike 
    weight :: Float64
    make :: String
    x_position :: Int
    y_position :: Int

end

our_json_object = JSON.parsefile("simulation_example.json") 
display("all bikes")
display(our_json_object["bikes"])
display("bike 1 x position")
display(our_json_object["bikes"][1]["x_position"])

bike = Bike(10, "TREK", 3, -3)
io = open("example_json_output.json", "w+")
JSON.print(io, bike)
close(io)
"all bikes"
2-element Vector{Any}:
 Dict{String, Any}("y_position" => 3, "bike_attributes" => Dict{String, Any}("make" => "Make1", "weight" => 15.04, "model" => "Model1", "drag_coefficient" => 0.746), "x_position" => 0)
 Dict{String, Any}("y_position" => 99, "bike_attributes" => Dict{String, Any}("make" => "Make1", "weight" => 19.4, "model" => "Model1", "drag_coefficient" => 0.597), "x_position" => 2)
"bike 1 x position"
0

Exercises

Main Exercise

Create your own program. You can do anything you want as long as it fulfils of the following criteria.

Required:

  • A written problem description of what the code does and how it fulfils the requirements (1-2 paragraphs)

  • Can take in multiple inputs and give correct different outputs

  • Do some sort of math

  • Multiple Functions (use guidance in previous modules on separation of concerns)

    • Unit test(s) proving that it does what is supposed to (doesn’t have to unit test the whole thing but tests your function)

2/3 of your choice

  • Reads from a file/writes to a file

  • Matrix algebra

  • Models some data using object oriented concepts

Some suggestions for inspiration:

  • Find a text book problem and create something that can solve any problem of the same type with any input

  • Create a Tick-Tac-Toe / Rock Paper Scissors game to play against the computer and keep track of scores over time

Use your imagination, it can be as creative (or as trivial) as you like. I just want you to get some experience starting from just an idea and turning it into code. This exercise is likely to be the most challenging one of the whole course and may take more time than the others. If you need help, please reach out!

Preparation for Final Module

Watch the Video for the final project and make sure you can run it in Google Collab.