Intro to File I/O and Terminal Usage — How to Create a Journal Using Python 📔

Candace Williams
thebit
Published in
10 min readNov 3, 2018

In this tutorial, we’ll be going over the basics of file I/O and terminal usage by building a journal that utilizes such. The terminal will be used to create journals and pages, whereas file I/O will be used to interact with the text in the pages.

“MacBook Pro, white ceramic mug,and black smartphone on table” by Andrew Neel on Unsplash

If you don’t have Python already installed, get it from: here, I’m currently running 3.6.4, but feel free to download the most recent one. Depending on when you’re reading this, the version shouldn’t affect our code all that much.

Also, this tutorial will be easier to understand with prior knowledge about terminal commands. If you aren’t too familiar with the terminal, that’s okay, our program will utilize the most basic of them. Here are some cheat sheets that you can reference if you need a refresher or are completely new: Linux/Mac OS, Windows

For now, create a .py file using a text editor (I’m using IDLE) and place it somewhere you can easily access it. Later on, our file will produce journals and entries in the same place. I chose to place it within a folder on my desktop, but it’s your choice.

On the first two lines of your file, you’ll need to add these two imports:

import datetime
import os

The datetime library will give us access to the current date, which can be later used to keep track of when our entries are made. Importing the os library gives us access to the terminal through our code. Without it, navigating directories and creating files would be impossible.

Now, before we get building, let’s go over a couple of the new methods we’ll be using to make this python journal work.

For one, you’ll be seeing a lot of os.[something]() (that comes from our os import). The successor to the os. will be a command we can use from within our code. Let’s do a quick rundown of what those commands are so that we don’t have to worry about them later.

  • os.getcwd() allows us to access the “current working directory.” Or in other words, what directory we’re currently in. Typically on a command line, the current working directory is always shown and prefaces any statement you might enter, and a specific command isn’t actually needed. But in Python, we have to use os.getcwd() to get a hold of our path because it isn’t a given. Our path will be used later on for adding or removing entities that exist in the same directory as our code.
  • os.mkdir() gives us the ability to create a directory. It’s about the same as using right-click on your mouse to create a new folder
  • os.remove() lets us remove a directory.
  • os.chdir() mimics the cd command which is able to change which directory we’re currently in. Think of this as being able to move from one spot on your computer to another. Ex. opening a folder within your desktop.
  • os.listdir() mimics the dir command on Windows and the ls command that’s used on Mac and Linux. Both of which display what entities exist within the directory you’re currently in. This doesn’t really affect the functionality of anything, it just makes it easier for a user to use our finished code.

Baby Steps

We could jump right into our code, but it’ll be easier to understand if we think through how we’re going to do so. Since we’re building a journal using python, the question we need to ask ourselves is: How do we use a regular journal? Well, the answer’s pretty obvious:

  1. Buy a journal
  2. Open it
  3. Flip to a new page
  4. Write stuff

Of course, using terminal commands, we can mimic such actions by creating directories (folders and .txt files in this case) and navigating between them.

Blah, Blah, Blah. Let’s Code

First, let’s create a global variable that we can update with the user’s name: author = "". This will most likely be your name, or whoever you want to show your project off to.

Then we’ll need to create a function that allows us to create a journal in the first place, let’s call it create_journal(): You may have noticed that I didn’t include parameters. That’s because input( ) can be used to ask the user to fill in any info that we need. Here’s some psuedo code that maps out our function.

def create_journal():Ask the user to name the journalFind the current directory we’re in so that we can create our
journal in the same one
Create the journal

Now let’s turn our pseudocode into real code:

def create_journal():
name = input("Name your journal: ") #Ask for a name
cwd = os.getcwd() #Uses os import to get our current path
path = cwd + "/" + name #Concatenate to create a new path
try:
os.mkdir(path)
except OSError:
print("Creation of the directory %s failed" % path)
else:
print("Successfully created the directory")

Everything there should look familiar up until the “try,” “except,” and “else.” It looks quite menacing at first, but don’t overthink it. First, we’re asking our computer to try creating our journal using os.mkdir(path) . Then if we receive an error ( OSError ), we’re printing a statement so we know that we can’t create that specific path. If we don’t get an error, a success message is printed out to let us know that everything has gone right.

The next function we’ll need to write is our open_journal() function. What’s the point of buying a journal if we can’t use it?

You’re probably wondering how much work could possibly go into opening a journal, it’s only one action after all. But because our journal is written in code and isn’t physically in our hands, we have no way of knowing what page we want to flip through and how to do it in the first place. Luckily, python has an answer! Let’s write some more pseudocode:

def open_journal():
Move into the directory where our file is
Get a list of the journals within the current directory
Loop through our list of journals and print them one by oneAsk the user to choose a journal out of the list displayed
Create the path we're going to move into
Move to the path we just created
Get a list of entries
Loop through our list of entries and print them one by one

Here’s how that can be translated into code:

def open_journal():
os.chdir(os.getcwd()) #Change directory to current path
journal_list = os.listdir() #Get list of journals

print("Current Journals: " + str(len(journal_list)))
for journal in journal_list:
print(journal) #Print out each journal name for the user

name = input("Name of journal: ") #Ask user to select a journal
cwd = os.getcwd() #Find the directory we’re in
path = cwd + "/" + name #Update path
os.chdir(path) #Change directories the path we determined
directory_list = os.listdir() #Get a list of entries
print("Current Entries: " + str(len(directory_list)))
for entry in directory_list:
print(entry) #Display entries for the user

Not much is going on in the code above. We’re basically trying to get everything to print to our shell so that our user doesn’t have to navigate through the folders themselves. Python acts as our eyes in this scenario.

Okay, great… what about our journal entries?

So, the next couple of functions will vary in size. A few will be quite long, but most will be pretty short and sweet. First, let’s write a helper function that we can use to grab text from the user

def fetch_content():
content = input("Write till your heart's content :)") #Input
return content

Then, let’s write another helper function that actually puts the content we fetch into an entry. As always, let’s write some pseudocode first:

def add_content():
Ask user for a title for their entry
Fetch content for the entry
Generate a filename
Add the author's name
Add the title
Add the date
Fix the spacing of the document and add it to the .txt file

The first part of the code should be pretty simple using file/io. First, we’ll need to open up the file for our new entry using: entry = open(filename, "a") . The parameter “a” means that we’re opening up our file in append mode, which allows us to add text into the desired file, in this case, our new entry file. We have the option of using “w” instead of “a,” but typically it’s only used when you’re adding text into a blank file. We want our add_content() function to be able to create entries for text files with or without text so that we can make new entries and add text into an older entry. Then, we can start adding the title, date, etc. using entry.write( ) . All together, the first chunk of our add_content() function will look like this:

def add_content():
title = input("What's the title of your entry? ") #Get a title
content = fetch_content() #Grab content
filename = title.replace(" ","") + ".txt" #Remove spaces in name
entry = open(filename, "a") #Create/open our file
entry.write(author + "\n") #Add the user's name
entry.write(title + "\n") #Add the chosen title
entry.write(str(datetime.datetime.now()) + "\n") #Add the date

Now, to get the text from our user into the file, you’re probably thinking of simply passing our content into the entry.write() function like this: entry.write(content). That would work, but you’ll end up having all of your sentences on a single line. That would be super difficult to read, yuck!

An alternative solution is looping through our content and adding a “\n” (which creates a new line) after every 10 letters so that our file is equally spaced and not an eyesore to read. So, the add_content() function should end up like so:

def add_content():
title = input("What's the title of your entry? ")
content = fetch_content()
filename = title.replace(" ","") + ".txt"
entry = open(filename, "a")
entry.write(author + "\n")
entry.write(title + "\n")
entry.write(str(datetime.datetime.now()) + "\n")

count = 0
prev_index = 0
for i in range(0, len(content) - 1):
if content[i] == " ":
entry.write(content[prev_index:i])
count += 1
prev_index = i
if count == 10:
count = 0
entry.write("\n")

entry.close()

Here’s a quick explanation on how that loop works:

First, we’re initializing, or creating a variable called count to 0 so that we can keep track of how many words have gone by before we add a new line. We also initialized a prev_index variable that’s going to be used in our loop so that we don’t lose our place when counting. Using prev_index and i together let’s us get a hold of a full word opposed to a single space or letter.

After creating our variables, we created a loop that indexes every character within our content. We know that something is a complete word or not if a space comes after it. In the loop, the conditional “ if content[i] == “ “:” uses that logic to check if i is following a full word. If so, count increases by one, prev_index is updated to our current place, and the word is added into our text file. The second conditional “ if count == 10:” checks if 10 words have been passed already. If so, we add “\n” to create a new line and count is reset to 0 so that we can do the same thing after the next ten words. Finally, after the loop has finished executing, an entry.close() is at the end of the file to tell python that we’re done writing the entry and interacting with our file.

Let’s make it pretty!

Congrats! You’ve made it through the bulk of this whole process. All that’s left is to add a couple of functions that that’ll allow the user to interact with the code easily.

Let’s add a function that creates the pages for us:

def add_page():
title = input("Name your entry: ")
filename = title.replace(" ","") + ".txt"
add_content(title)

Then a function to remove a page if we need to:

def remove_page():
title = input("What's the title of your entry? ")
filename = title.replace(" ","") + ".txt"
os.remove(filename)

Remember when we described how to use a journal? Now that we have all of the pieces/actions, we can put them together in one function that’s easy for our userto use. Feel free to get creative, but this should work:

def controls():
print("What would you like to do?: ")
print("1: Create a journal")
print("2: Open a journal")
print("3: Create an entry")
print("4: Add to an entry")
print("5: Remove an entry")
option = input("Your choice: ")
print("-----\n-----")
#^^This prefaces the user with options and asks for input
if option == "1" or option == 1:
create_journal()
elif option == "2" or option == 2:
open_journal()
elif option == "3" or option == 3:
add_page()
elif option == "4" or option == 4:
add_content()
elif option == "5" or option == 5:
remove_page()
else:
print("Please answer based on your choices")
controls()
#^Conditions that execute functions based on user's choice
choice = input("Do you need to do anything else? (y/n)")
if choice == "y" or choice == "yes":
controls()
else:
print("See you later!")
#^Asks if the user wants to do anything else. If not,
#the program ends

Then, to finish it all off, let’s ask the user what their name is so that we can update the author variable and start the program for them at the bottom of the function so they don’t even have to call the controls() function:

author = input("What's your name?  ")
controls()

Recap & Resources

You learned the following:

  • How to think through a process before turning it into code
  • File I/O
  • How terminal commands can be used in python

Here’s the code all together: https://github.com/CandaceJWilliams/python-journal.git

Beyond this tutorial, file I/O can be used for many things, such as algorithms like the Markov Text Generator. There are also tons of other algorithms that combine file I/O and AI. As for the terminal, I personally love typing ping and then the name of a website like this: ping www.google.com, which does something cool, try it! A terminal can do a lot, so much that it’d be impossible to fit in this tutorial. But search around and see what’s out there, I’m sure you’ll find something cool or interesting!

--

--