pythonjsondatabase

python + json file saving


The issue is saving data in json files lets say it saves like this:

{"discordid1": {"username": "discorduser1", "roblox_username": "robloxuser1"}, "discordid2": {"username": "discorduser2", "roblox_username": "robloxuser2"}, "discordid3": {"username": "discorduser3", "roblox_username": "robloxuser3"}} thats whats its seen now when i do command and after some time (few hrs) it shows only 2 users and points for that 1 missing user dissapear (another json file)

COOLDOWNS_FILE = 'cooldowns.json'
SECOND_COOLDOWNS_FILE = 'second_cooldowns.json'
USER_LOGS_FILE = "user_logs.json"
USER_REGISTRATION_FILE = "user_registration.json"

def load_json_file(file_path):
    try:
        with open(file_path, 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return {}
    except json.JSONDecodeError:
        print(f"Error loading {file_path}: file is empty or invalid JSON")
        return {}

def save_json_file(data, file_path):
    with open(file_path, "w") as f:
        json.dump(data, f, indent=4)

def load_cooldowns(file_path):
    if not os.path.exists(file_path):
        return {}
    try:
        with open(file_path, "r") as f:
            data = json.load(f)
        data_to_return = {}
        for user_id, cooldown_time in data.items():
            data_to_return[user_id] = dt.datetime.fromisoformat(cooldown_time.replace("Z", "+00:00"))
        return data_to_return
    except json.JSONDecodeError:
        return {}

def save_cooldowns(cooldowns):
    data_to_save = {}
    for user_id, cooldown_time in cooldowns.items():
        data_to_save[user_id] = cooldown_time.isoformat()
    with open("cooldowns.json", "w") as f:
        json.dump(data_to_save, f, indent=4)

def load_second_cooldowns():
    if not os.path.exists(SECOND_COOLDOWNS_FILE):
        return {}
    try:
        with open(SECOND_COOLDOWNS_FILE, "r") as f:
            data = json.load(f)
        data_to_return = {}
        for user_id, cooldown_time in data.items():
            data_to_return[user_id] = dt.datetime.fromisoformat(cooldown_time)
        return data_to_return
    except json.JSONDecodeError:
        return {}

def save_second_cooldowns(second_cooldowns):
    data_to_save = {}
    for user_id, cooldown_time in second_cooldowns.items():
        data_to_save[user_id] = cooldown_time.isoformat()
    with open(SECOND_COOLDOWNS_FILE, "w") as f:
        json.dump(data_to_save, f, indent=4)

cooldowns = load_cooldowns(COOLDOWNS_FILE)
second_cooldowns = load_second_cooldowns()

and thats how it is saving files

i also tried append method but no luck. it shouldnt reset points or users. in leaderboard they all show but after sometime they dissapear and their points are reset that shouldnt happen. any help would be much appriciated


Solution

  • Here’s what we can do to fix the problem:

    Save data to a temporary file first, then rename it. This way, you won't lose data if something goes wrong while writing. If your program uses multiple threads, make sure they don’t mess with the files at the same time. Catch and handle errors more gracefully to avoid data loss.

    Improved code should be something like this:

    import json
    import os
    import datetime as dt
    import threading
    
    # File paths
    COOLDOWNS_FILE = 'cooldowns.json'
    SECOND_COOLDOWNS_FILE = 'second_cooldowns.json'
    USER_LOGS_FILE = "user_logs.json"
    USER_REGISTRATION_FILE = "user_registration.json"
    
    # Lock for safety when using threads
    lock = threading.Lock()
    
    def load_json_file(file_path):
        """Load data from a JSON file."""
        with lock:
            try:
                if not os.path.exists(file_path):
                    return {}
                with open(file_path, 'r') as f:
                    return json.load(f)
            except (FileNotFoundError, json.JSONDecodeError):
                return {}
    
    def save_json_file(data, file_path):
        """Save data to a JSON file safely."""
        with lock:
            temp_file_path = file_path + '.tmp'
            with open(temp_file_path, "w") as f:
                json.dump(data, f, indent=4)
            os.replace(temp_file_path, file_path)
    
    def load_cooldowns(file_path):
        """Load cooldown times from a JSON file."""
        data = load_json_file(file_path)
        data_to_return = {}
        for user_id, cooldown_time in data.items():
            data_to_return[user_id] = dt.datetime.fromisoformat(cooldown_time.replace("Z", "+00:00"))
        return data_to_return
    
    def save_cooldowns(cooldowns):
        """Save cooldown times to a JSON file."""
        data_to_save = {user_id: cooldown_time.isoformat() for user_id, cooldown_time in cooldowns.items()}
        save_json_file(data_to_save, COOLDOWNS_FILE)
    
    def load_second_cooldowns():
        """Load second cooldown times from a JSON file."""
        data = load_json_file(SECOND_COOLDOWNS_FILE)
        data_to_return = {}
        for user_id, cooldown_time in data.items():
            data_to_return[user_id] = dt.datetime.fromisoformat(cooldown_time)
        return data_to_return
    
    def save_second_cooldowns(second_cooldowns):
        """Save second cooldown times to a JSON file."""
        data_to_save = {user_id: cooldown_time.isoformat() for user_id, cooldown_time in second_cooldowns.items()}
        save_json_file(data_to_save, SECOND_COOLDOWNS_FILE)
    
    # Load initial data
    cooldowns = load_cooldowns(COOLDOWNS_FILE)
    second_cooldowns = load_second_cooldowns()