Python 3 Unicode-escape - PullRequest
       93

Python 3 Unicode-escape

0 голосов
/ 10 сентября 2018

У меня есть скрипт, который я построил, следуя плану в книге Изучение Python для криминалистики .Сценарий будет проходить через каталог, указанный пользователем, и собирать метаданные для каждого файла в каталоге.Результаты сохраняются в базе данных sqlite, а также записываются в файл CSV или HTML.

Сценарий изначально был написан на Python 2.7.15.Я пытаюсь обновить код для Python 3.7.Тем не менее, есть одна строка в функции каталога загрузки, которая вызывает у меня проблемы.

Функция ingestDirectory выглядит следующим образом:

def ingestDirectory(cur, source, custodian_id):    
    count = 0
    for root, folders, files in os.walk(source):
        for file_name in files:
            meta_data = dict()
            try:
                meta_data['file_name'] = file_name
                meta_data['file_path'] = os.path.join(root, file_name)
                meta_data['extension'] = os.path.splitext(file_name)[-1]

                file_stats = os.stat(meta_data['file_path'])
                meta_data['mode'] = oct(file_stats.st_mode)
                meta_data['inode'] = int(file_stats.st_ino)
                meta_data['file_size'] = int(file_stats.st_size)
                meta_data['atime'] = formatTimestamp(file_stats.st_atime)
                meta_data['mtime'] = formatTimestamp(file_stats.st_mtime)
                meta_data['ctime'] = formatTimestamp(file_stats.st_ctime)
            except Exception as e:
                logging.error('Could not gather data for file: ' + meta_data['file_path'] + e.__str__())
            meta_data['custodian'] = custodian_id
            columns = '","'.join(meta_data.keys())
            values = '","'.join(str(x).encode('string_escape') for x in meta_data.values())
            sql = 'INSERT INTO Files ("' + columns + '") VALUES ("' + values + '")'
            cur.execute(sql)
            count += 1

Строка, которая дает мне ошибки, это:

values = '","'.join(str(x).encode('string_escape') for x in meta_data.values())

Эта строка предназначена для обработки любых escape-символов строки, найденных в metadata.values перед записью данных в базу данных.

Когда я пытался запустить этот код в Python 3, яполучил ошибку о нераспознанном кодеке.Я провел некоторое исследование о переполнении стека и обнаружил, что string_escape был заменен на unicode-escape в Python 3.

Я довольно новичок в Python 3 и Unicode.У меня такой вопрос:

Как мне обновить строку выше, чтобы она использовала unicode-escape вместо string_escape и выдает тот же результат, что и код Python 2.7?

Любая помощь будетбыть оцененным!Я работаю над этим уже несколько дней, и каждое решение, которое я пробую, приводит к большему количеству кодов ошибок или поврежденных выходных файлов.

1 Ответ

0 голосов
/ 10 сентября 2018

Вы генерируете SQL в этом куске кода, и вы пытались создать правильный SQL.Это очень неудачная попытка избежать внедрения SQL.Это не очень эффективно и не нужно, так как драйвер базы данных уже знает, как позаботиться об этом, гораздо безопаснее!

Для баз данных SQL - правильный способ установки значений в параметры SQL.Параметры SQL состоят из двух компонентов: заполнителей и значений, передаваемых отдельно в метод .execute(), который база данных должна обрабатывать без ошибок.Библиотека sqlite3 не является исключением, подробнее см. Метод cursor.execute() .В вашем случае вы можете использовать именованные заполнители:

columns = [f'''"{name.replace('"', '""')}"''' for name in meta_data]
placeholders = [f':{name}' for name in meta_data]
sql = f'INSERT INTO Files ({", ".join(columns)}) VALUES ({", ".join(placeholders)})'    
cur.execute(sql, meta_data)

Обратите внимание, что meta_data передается в качестве второго аргумента;база данных принимает каждый заполнитель :name и получает значение этого заполнителя из словаря meta_data.

Я также правильно отформатировал имена столбцов, заключив их в двойные кавычки и удвоив любые символы " в имени;см. документацию по ключевым словам SQLite :

'keyword'       A keyword in single quotes is a string literal.
"keyword"       A keyword in double-quotes is an identifier.

В вашем коде жестко заданы имена этих столбцов, и ни одно из них не является зарезервированным ключевым словом SQL, поэтому им не нужна эта защита, но этовсе еще хорошая практика.

Для вашего кода, где meta_data имеет фиксированное количество ключей, приведенное выше строит эту строку sql:

>>> columns = [f'''"{name.replace('"', '""')}"''' for name in meta_data]
>>> placeholders = [f':{name}' for name in meta_data]
>>> sql = f'INSERT INTO Files ({", ".join(columns)}) VALUES ({", ".join(placeholders)})'
>>> from pprint import pprint
>>> pprint(sql)
('INSERT INTO Files ("file_name", "file_path", "extension", "mode", "inode", '
 '"file_size", "atime", "mtime", "ctime") VALUES (:file_name, :file_path, '
 ':extension, :mode, :inode, :file_size, :atime, :mtime, :ctime)')

Я бы также изменил способВы регистрируете ошибку вместо

logging.error('Could not gather data for file: ' + meta_data['file_path'] + e.__str__())

Я бы использовал

logging.exception('Could not gather data for file: %s', meta_data['file_path'])

и оставлял сбор ошибок в каркасе ведения журнала.Даже если вы включаете объект исключения, используйте str(e) или %s заполнитель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...