Неправильно работает сохранения в файл python
У меня есть python aiogram код, который на команде /start спрашивает у пользователя имя и записывает в файл в формате "username - entered name", и команда /namechange, которая снова спрашивает у пользователя имя и перезаписывает его. Всё работает нормально до того момента, пока пишет 1 пользователь, если начинает писать второй пользователь, то функция замены имени ломается, и вместо перезаписи просто добавляет новое имя в конец файла, что вызывает несколько сообщений (вместо одного) типа "Привет {name}". Как можно это починить? Заранее спасибо.
from aiogram import Bot, types
from aiogram.dispatcher import Dispatcher
from aiogram.utils import executor
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxx'
bot = Bot(token=TOKEN)
storage=MemoryStorage()
dp = Dispatcher(bot, storage=storage)
class Form(StatesGroup):
name = State()
newname = State()
admins = open('admins.zailoxconf', 'r')
admins.seek(0)
blocked_users = open('blocked_users.zailoxconf', 'r')
blocked_users.seek(0)
names = open('names.zailoxconf', 'r')
names.seek(0)
#ALLOWED_USERS = ['username']
#ADMINS = ['username']
bur = blocked_users.read()
ar = admins.read()
nr = names.read()
@dp.message_handler(lambda msg: msg.from_user.username not in bur, commands=['check'])
async def check(message: types.Message):
await message.answer("Вы не заблокированы")
@dp.message_handler(lambda msg2: msg2.from_user.username in bur, commands=['check'])
async def check2(message: types.Message):
await message.answer("Вы заблокированы")
@dp.message_handler(lambda msg: msg.from_user.username, commands=['unblock'])
async def unblock(message: types.Message):
global bur
global blocked_users
msg = message.text.replace('/unblock ', '')
if msg == "2601":
await message.answer('Разблокирован успешно')
#ALLOWED_USERS.append(message.from_user.username)
unblock = bur.replace(message.from_user.username, "")
bur = blocked_users.read()
blocked_users = open('blocked_users.zailoxconf', 'w')
blocked_users.write(unblock)
blocked_users = open('blocked_users.zailoxconf', 'r')
else:
await message.answer('Неверный код')
@dp.message_handler(lambda msg: msg.from_user.username not in bur and msg.from_user.username in ar, commands=['block'])
async def ban(message: types.Message):
global bur
global ar
msg = message.text.replace("/block ", "")
block = open('blocked_users.zailoxconf', 'a+')
block.write(msg)
block.close()
blocked_users = open('blocked_users.zailoxconf', 'r')
bur = blocked_users.read()
await message.reply("Пользователь заблокирован ✓")
@dp.message_handler(lambda msg: msg.from_user.username in ar, commands=['pardon'])
async def unban(message: types.Message):
global bur
global blocked_users
#ALLOWED_USERS.append(message.from_user.username)
msg = message.text.replace("/pardon ", "")
unblock = bur.replace(msg, "")
bur = blocked_users.read()
blocked_users = open('blocked_users.zailoxconf', 'w')
blocked_users.write(unblock)
blocked_users = open('blocked_users.zailoxconf', 'r')
bur = blocked_users.read()
await message.reply("Пользователь разблокирован ✓")
@dp.message_handler(lambda msg: msg.from_user.username not in bur and msg.from_user.username not in ar, commands=['block'])
async def unban(message: types.Message):
await message.reply("Вы не админ")
@dp.message_handler(lambda msg: msg.from_user.username, commands=['sendall'])
async def sendall(message: types.Message):
if message.from_user.username in admins: #ADMINS:
for i in users:
await bot.send_message(i,message.text[message.text.find(' '):])
await message.answer('Done')
else:
await message.reply("Вы не админ")
@dp.message_handler(lambda msg: msg.from_user.username not in nr, commands=['start'])
async def start(message: types.Message):
await Form.name.set()
await message.reply("Как тебя зовут?\n/cancel - отмена")
@dp.message_handler(state='*', commands=['cancel'])
async def cancel_handler(message: types.Message, state: FSMContext):
"""Allow user to cancel action via /cancel command"""
current_state = await state.get_state()
if current_state is None:
# User is not in any state, ignoring
return
# Cancel state and inform user about it
await state.finish()
await message.reply('Отменено.')
@dp.message_handler(state=Form.name)
async def process_name(message: types.Message, state: FSMContext):
"""Process user name"""
# Finish our conversation
await state.finish()
await message.reply(f"Привет, {message.text}") # <-- Here we get the name
global name
global names
global nr
name=message.text
names = open('names.zailoxconf', 'a+')
replaces = name.replace('\n', '')
names.write(f"{message.from_user.username} - {replaces}\n")
names.close()
names = open('names.zailoxconf', 'r')
nr = names.read()
@dp.message_handler(lambda msg: msg.from_user.username in nr, commands=['start'])
async def process_name(message: types.Message):
global nr
global names
for item in nr.split("\n"):
if message.from_user.username in item:
await message.answer(f"С возвращением, {nr.strip().replace(f'{message.from_user.username} - ', '')}")
names.close()
names = open('names.zailoxconf', 'r')
names.seek(0)
nr = names.read()
@dp.message_handler(lambda msg: msg.from_user.username in nr, commands=['namechange'])
async def process_name(message: types.Message):
await Form.newname.set()
await message.reply("Отправьте новое имя\nОтмена - /cancel")
@dp.message_handler(state='*', commands=['cancel'])
async def cancel_handler(message: types.Message, state: FSMContext):
"""Allow user to cancel action via /cancel command"""
current_state = await state.get_state()
if current_state is None:
# User is not in any state, ignoring
return
# Cancel state and inform user about it
await state.finish()
await message.reply('Отменено.')
@dp.message_handler(state=Form.newname)
async def process_name(message: types.Message, state: FSMContext):
"""Process user name"""
# Finish our conversation
await state.finish()
global name
global names
global nr
name = nr.strip().replace(f'{message.from_user.username} - ', '')
newname = message.text
oldname = name
names = open('names.zailoxconf', 'a+')
names.seek(0)
replaces = newname.replace('\n', '')
names.close()
names = open('names.zailoxconf', 'r')
names.seek(0)
b = nr.replace(f'{message.from_user.username} - {oldname}', '')
names = open('names.zailoxconf', 'w')
names.seek(0)
names.write(f"{b}\n")
names = open('names.zailoxconf', 'a+')
names.write(f"{message.from_user.username} - {replaces}\n")
names = open('names.zailoxconf', 'r')
names.seek(0)
nr = names.read()
name = message.text
await message.reply(f"Новое имя - {name}") # <-- Here we get the name
@dp.message_handler(lambda msg: msg.from_user.username not in nr, commands=['namechange'])
async def process_name(message: types.Message):
await message.reply("Сначала выберите имя /start")
async def on_startup(_):
print("Бот успешно запущен")
def blankremove():
global names
names = open('names.zailoxconf', 'r')
lines = names.readlines()
non_empty_lines = (line for line in lines if not line.isspace())
names = open('names.zailoxconf', 'w')
names.close()
names = open('names.zailoxconf', 'r+')
names.writelines(non_empty_lines)
if __name__ == '__main__':
executor.start_polling(dp, on_startup=on_startup)
admins.close()
blocked_users.close()
blankremove()
names.close()
print('Бот успешно остановлен')
Ответы (1 шт):
Лучшим решением будет писать данные в БД. Если это "игрушечный" проект, то подойдет SQLite. Там необходимо создать таблицу users и в нее добавлять пользователя через INSERT, или удалять через DELETE (редактировать через UPDATE) + будет правильно создать ещё таблицы, в которых хранить заблокированных пользователей и т.д.
Если пытаться делать через файл, то во-первых, лучше всего открыть его один раз и на чтение и на запись, а не открывать каждый раз (важно ещё каждый раз не забывать тогда закрывать), и закрывать при завершении работы бота. Для замены пользователей использовать поиск по файлу по имени пользователя (он вернет положение каретки начала) и перезаписывать всю строку целиком.