Добавление строки (строки) в заданную позицию на основе некоторых критериев (в Python) - PullRequest
2 голосов
/ 23 мая 2019

У меня есть следующий файл .sql:

execute_all.log
set echo on
SET SQLBLANKLINES ON
@@2019-03-26_DX_1.sql
@@2019-05-10_DX_2.sql
@@2019-05-10_DX_3.sql
@@2019-05-14_1600_DX_4.sql
@@2019-05-21_0900_DX_5.sql
@@2019-05-21_0900_DX_6.sql
@@2019-05-21_0900_DX_7.sql
@@2019-05-21_0900_DX_8.sql
SET SQLBLANKLINES OFF
spool off;
@@make_constraint.sql

все, что начинается с "@@", является именем файла, которое относится ко мне.В списке у меня есть еще следующие файлы:

skripts_to_deploy = ['2019-05-14_1600_DX_4.sql','2019-05-15_1500_DX_55.sql']

Критерии следующие:

  • , если файл уже существует, пропустите файл
  • Если файл нене существует, затем перейдите через строку файлов.Если дата файла (часть после @@) файла в skripts_to_deploy меньше, чем в следующей строке, то добавьте строку (имя файла) в это место (и оставьте также другие строки, но смещенные, при необходимости).

Вот код:

path = "C:\\Users\\danyef"
skripts_to_deploy = ['2019-05-14_1600_DX_13.sql','2019-05-15_1500_DX_55.sql']    
level = 'DXIDS'
with open(level + "_EXECUTE_ALL.sql","r+") as file:
    for line in file:
        if line == "execute_all.log\n" or line == "set echo on\n" or line == "SET SQLBLANKLINES ON\n":
            continue
        for skript in skripts_to_deploy:
            if '@@' + skript in line:
                continue
            next_line = next(file)
            print(next_line)
            if next_line == 'SET SQLBLANKLINES OFF':
                file.write('@@' + skript + '\n')
                print("written SET SQLBLANKLINES OFF:",skript)
            else:
                next_line = datetime.strptime((next_line.split('_')[0]).split('@@')[1],'%Y-%m-%d')
                if datetime.strptime(skript.split('_')[0],'%Y-%m-%d')<= next_line:
                    file.write('@@' + skript + '\n')
                    print("written:",skript)

Важное примечание: next_line = datetime.strptime((next_line.split('_')[0]).split('@@')[1],'%Y-%m-%d') просто извлекает дату из строки в существующем файле.

В моем коде это добавляет строку, но вместо правильного места (на основе критериев, упомянутых выше) это делает это в конце файла.

Может быть, пропущены некоторые другие с моей стороны, пожалуйстаисправить это.Спасибо заранее.

РЕДАКТИРОВАТЬ: Ожидается Выход:

execute_all.log
set echo on
SET SQLBLANKLINES ON
@@2019-03-26_DX_1.sql
@@2019-05-10_DX_2.sql
@@2019-05-10_DX_3.sql
@@2019-05-14_1600_DX_4.sql
**@@2019-05-15_1500_DX_55.sql**
@@2019-05-21_0900_DX_5.sql
@@2019-05-21_0900_DX_6.sql
@@2019-05-21_0900_DX_7.sql
@@2019-05-21_0900_DX_8.sql
SET SQLBLANKLINES OFF
spool off;
@@make_constraint.sql

1 Ответ

1 голос
/ 23 мая 2019

Большинство файловых систем не поддерживают вставку данных на месте.

В общем, у вас есть 3 варианта:

  1. использование file_obj.seek() (только для замены данных)
  2. загрузить весь файл в память и вывести его обратно
  3. создать временный файл, который вы изменяете по ходу работы, и вы копируете обратно в исходный файл

Опция 1, кажется, отключенаполки, как вы хотите, чтобы вставить данные.Вариант 2 кажется наиболее подходящим в вашем случае, вам просто нужно соответствующим образом адаптировать свой код (например, использовать нарезку строк и конкатенацию вместо read() и write()).Вариант 3 также возможен, но, как правило, более обременителен.Однако это особенно полезно, если вы не можете уместить весь файл в памяти.

Для полноты ниже приведен эскиз кода для каждой опции.


Вариант 1:

# file should be open as a binary to avoid messy offsets due to encoding
with open(filepath, 'rb+') as file_obj: 
    while True:
        line = file_obj.readline()
        if not line:  # reached end-of-file
            break
        if condition(line):  # for strings, use `line.decode()`
            position = file_obj.tell()
            offset = 0  # the offset from the beginning of the line
            file_obj.seek(position - len(line) + offset)  
            # new data must be `bytes`, for strings, use `new_data.encode()`
            file_obj.write(new_data)
            file_obj.seek(position)

Опция 2 :

with open(filepath, 'r+') as file_obj:
    text = file_obj.read()  # read the whole file
    ...                     # do your preprocessing on the text as string
    file_obj.seek(0)        # go back at the beginning of the file
    file_obj.truncate()     # disregard previous content
    file_obj.write(text)    # write data back

Опция 3 :

import shutil

with open(in_filepath, 'r') as in_file_obj, \
        open(out_filepath, 'w') as out_file_obj:
    for line in in_file_obj:
        # should actually reflect your logic here
        if must_insert_here():  
            # preprocess data to insert
            out_file_obj.write(new_line + '\n')

        # should actually reflect your logic here 
        if must_be_present_in_new():  
            out_file_obj.write(line)

# perhaps you actually want to use `copy2()` instead of `copy()`  
shutil.copy(out_filepath, in_filepath)      
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...