How to save to text file?

My script saves names to a text file and, in the main function, updates the file with new names when necessary. But when hosting on Fly.io, that’s not possible, from my understanding.

Do I have to set up a SQL database? I’d rather not, if it’s possible to avoid.

How can I store a list of names in a simple text format for my code to use?

What problems are you experiencing trying to accomplish this on fly? This is definitely supported.

I have this code for reading from and writing to a text file, but of course, that file is not updated when I re-deploy the program. Users are able to use a command on the website my bot runs on to add their username to users.txt, but once the script is re-deployed, those usernames are lost. It works until the script is re-deployed.

How can I achieve this?

if os.path.isfile('users.txt'):
    with open('users.txt', 'r') as file:
        users = [line.rstrip('\n') for line in file]
# Function for writing to users.txt
def write_to_users():
    try:
        with open('users.txt', 'w') \
                as file:
            for item in users:
                file.write('{}\n'.format(item))
    except FileNotFoundError:
        print('Current path:', os.getcwd())
        print('Isdir reports:', os.path.isdir(os.getcwd()))
        print('Isfile reports:', os.path.isfile(
            'users.txt'))
        raise

Place the text file on a volume: Volumes · Fly Docs

1 Like

Thank you. Do I have to modify my code, or will it work as though the file is local?

Also, when I re-deploy my application after updating it, won’t my local users.txt file overwrite the one in my Fly.io volume? Should I delete my local version of the folder containing users.txt so it’s only stored on Fly.io? And is it possible to check the contents of users.txt in my volume?

And lastly, is this the correct block to put in fly.toml if the path to users.txt is stored in root\data\users.txt?

[mounts]
source="my_volume_name"
destination="/data"

Okay, so I’ve tried using a volume, but I don’t understand how to access it. The script uses users.txt, which is a file containing a list of names. Locally, I’ve been using root_folder\data\users.txt.

The script adds new names to the file, and I need it to use persistent memory so that the names are always saved. I’ve created a 1 GB module and put this in my fly.toml:

[mounts]
source="bot"
destination="/data"

And here’s my code for writing to the file:

# Read users.txt
if os.path.isfile(r'/bot/data/users.txt'):
    with open(r'/bot/data/users.txt', 'r') as file:
        users = [line.rstrip('\n') for line in file]
# Function for writing to users.txt
def write_to_users():
    try:
        with open(r'/bot/data/users.txt', 'w') \
                as file:
            for item in users:
                file.write('{}\n'.format(item))
    except FileNotFoundError:
        print('Current path:', os.getcwd())
        print('Isdir reports:', os.path.isdir(os.getcwd()))
        print('Isfile reports:', os.path.isfile(
            r'/bot/data/users.txt'))
        raise

My problem is that I don’t know what path to use to access users.txt. I don’t really understand how volumes work.

What I want: Store a text file called users.txt in root\data to access in my script. It needs to be persistent, keeping the file’s contents when I re-deploy the application to update my code.

Problem: /bot/data/users.txt doesn’t seem to work for the path in my script. I’ve also tried /data/users.txt and data/users.txt.

I’m getting the error FileNotFoundError: [Errno 2] No such file or directory: '/data/users.txt'.

Umounting /dev/vdc from /data also shows up in the console, if that means anything.

If anyone can help me out with this, that would be much, much appreciated!

Think of a volume just as a regular folder on your computer. Because of this line destination="/data" we know that the folder lives at /data. So to access a hypothetical file in that volume (read folder) I would access it like /data/filenamethatiwant. With this error: FileNotFoundError: [Errno 2] No such file or directory: '/data/users.txt' it sounds like you are trying to open the users file without having created it first, oops! Just like on your computer, you have to create a file before you can open it. You need to do something like this:

# This is how you currently have it
if os.path.isfile(r'/bot/data/users.txt'):
    with open(r'/bot/data/users.txt', 'r') as file:
        users = [line.rstrip('\n') for line in file]

# Replace it with something like this
open(r'/data/users.txt', 'a+') as file:
    users = [line.rstrip('\n') for line in file]

The key changes there is that it removed the isfile check, it replaced the path with the right one (from /bot/data/users.txt to /data/users.txt) and used open mode a+ which will create the file if it does not exist.

1 Like

Thank you! I will try this right now. I’m assuming you meant to put with before open, though, correct?

Also, is there a way to check the files on my volume and potentially read them, or does the script need to do this?

I’m assuming you meant to put with before open , though, correct?

Ah yep sorry. Python is not my usual language :wink:

Also, is there a way to check the files on my volume and potentially read them, or does the script need to do this?

I assume you mean just reading the files manually? You can use flyctl ssh console to ssh into your app and then you can cd /data and mess around. The flyctl sftp command also exists for getting and putting files.

1 Like

Thank you so much for the help! Seems to work perfectly now.