Индексация данных в файловой системе с помощью Python

Раздел: Python -> Файловый ввод-вывод

Основной подход к индексации файлов

Эффективное решение с pathlib

Для создания индекса всех файлов в каталоге и его подпапках рекомендуется использовать модуль pathlib. Он предоставляет удобный интерфейс для работы с путями и встроенную рекурсивную итерацию. Функция ниже возвращает словарь с числовыми ключами и полными путями к файлам.

from pathlib import Path

def build_index(path: str) -> dict:
    index = {}
    for idx, file in enumerate(Path(path).rglob('*'), start=1):
        if file.is_file():
            index[idx] = str(file.resolve())
    return index

# Пример использования
print(build_index('/tmp/test'))

ввод программ на python (ввод данных в программе python)

Такой подход позволяет быстро получить пронумерованный список файлов. Преимущество: автоматическая обработка путей, кроссплатформенность, читаемый код.

Возможные проблемы и их решение

  • При очень большом количестве файлов (миллионы) rglob может замедлиться. Альтернатива - использовать os.scandir с явным управлением рекурсией.
  • Ошибки доступа к отдельным папкам приводят к исключению PermissionError. Рекомендуется обернуть вызов в try-except или использовать ignore-функции.
  • Символические ссылки могут зациклиться. В pathlib по умолчанию они разрешаются, но можно отключить через параметр follow_symlinks=False.

Как пронумеровать файлы только в текущей папке без рекурсии?

import os

def index_flat(path: str) -> dict:
    files = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
    return {i: os.path.join(path, f) for i, f in enumerate(files, start=1)}

Python file io (ввод-вывод файлов в python)

Этот вариант прост, но не затрагивает подпапки. Используется, когда нужен только список файлов в одном каталоге.

Ошибка: os.listdir не различает файлы и папки, поэтому требуется дополнительная проверка isfile. При работе с большими папками os.listdir может потреблять много памяти, лучше использовать os.scandir.

Как построить индекс с фильтрацией по расширению?

from pathlib import Path

def index_filtered(path: str, extension: str) -> dict:
    index = {}
    pattern = f'**/*{extension}'
    for idx, file in enumerate(Path(path).glob(pattern), start=1):
        if file.is_file():
            index[idx] = str(file.resolve())
    return index

Python temp files (временные файлы в python)

Фильтрация происходит на этапе обхода, что сокращает объём обрабатываемых данных. Для нескольких расширений можно комбинировать через or.

Важно: glob.iglob может не найти файлы, если расширение указано неверно (регистр символов в Windows не учитывается, в Linux - да). Рекомендуется приводить к нижнему регистру.

Как сохранить индекс для последующего быстрого поиска?

import sqlite3

def save_index_to_db(path: str, db_path: str):
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    c.execute('CREATE TABLE IF NOT EXISTS index_files (id INTEGER PRIMARY KEY, path TEXT)')
    for idx, file in enumerate(Path(path).rglob('*'), start=1):
        if file.is_file():
            c.execute('INSERT INTO index_files (id, path) VALUES (?, ?)', (idx, str(file.resolve())))
    conn.commit()
    conn.close()

Хранение индекса в SQLite позволяет выполнять произвольные запросы (по части пути, по id) без повторного обхода файловой системы. Это удобно при частом обращении к одному и тому же каталогу.

Проблема: база данных может быстро расти. Для миллионов записей требуется индексирование полей. Также при изменении файловой структуры индекс устаревает - нужна периодическая переиндексация или отслеживание через inotify.

- Python file utf 8 (кодировка utf-8 для файлов в python)
- Python config files (конфигурационные файлы в python)
- Python copy file (копирование файла в python)

Расширенные примеры индексации файлов

Ниже приведены более сложные сценарии, которые могут потребоваться в реальных проектах.

Индексация с метаданными

Помимо пути, часто нужно хранить размер, дату изменения и тип файла. Используем os.stat для получения атрибутов.

Пример
from pathlib import Path
import os, time

def index_with_metadata(base: str) -> list:
    records = []
    for file in Path(base).rglob('*'):
        if file.is_file():
            stat = file.stat()
            records.append({
                'path': str(file),
                'size': stat.st_size,
                'mtime': time.ctime(stat.st_mtime),
                'permissions': oct(stat.st_mode)[-3:]
            })
    return records

result = index_with_metadata('/tmp/test')
print(result[:2])
[{'path': '/tmp/test/file1.txt', 'size': 1024, 'mtime': 'Mon Mar 10 12:00:00 2025', 'permissions': '644'},
 {'path': '/tmp/test/sub/file2.py', 'size': 2048, 'mtime': 'Mon Mar 10 12:05:00 2025', 'permissions': '755'}]

Параллельная индексация с multiprocessing

Для ускорения обхода нескольких корневых каталогов можно распараллелить работу.

Пример
from multiprocessing import Pool
from pathlib import Path

def index_single(root: str) -> dict:
    idx = {}
    for i, f in enumerate(Path(root).rglob('*'), start=1):
        if f.is_file():
            idx[i] = str(f)
    return idx

def parallel_index(roots: list) -> dict:
    with Pool() as pool:
        results = pool.map(index_single, roots)
    combined = {}
    counter = 1
    for res in results:
        for k, v in res.items():
            combined[counter] = v
            counter += 1
    return combined

print(parallel_index(['/tmp/a', '/tmp/b']))
{1: '/tmp/a/f1.txt', 2: '/tmp/a/f2.txt', 3: '/tmp/b/g1.txt', ...}

Инвертированный индекс для полнотекстового поиска

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

Пример
from collections import defaultdict
import re
from pathlib import Path

def build_inverted_index(dir_path: str) -> dict:
    index = defaultdict(list)
    for file in Path(dir_path).rglob('*.txt'):
        if file.is_file():
            with open(file, 'r', encoding='utf-8', errors='ignore') as f:
                words = set(re.findall(r'\w+', f.read().lower()))
                for word in words:
                    index[word].append(str(file))
    return dict(index)

inv = build_inverted_index('/tmp/docs')
print('собака' in inv)
True

Примечание: такой индекс может быть большим. Для реальных приложений лучше использовать специализированные библиотеки, например Whoosh или Elasticsearch.

Индекс с помощью Pandas DataFrame

Если требуется дальнейший анализ (статистика размеров, группировка по папкам), удобно представить индекс как DataFrame.

Пример
import pandas as pd
from pathlib import Path

def index_to_dataframe(base: str) -> pd.DataFrame:
    data = []
    for file in Path(base).rglob('*'):
        if file.is_file():
            stat = file.stat()
            data.append({
                'id': len(data) + 1,
                'path': str(file),
                'size': stat.st_size,
                'parent': str(file.parent)
            })
    return pd.DataFrame(data)

df = index_to_dataframe('/tmp/test')
print(df.describe())
               id         size
count   5.000000     5.000000
mean    3.000000  1536.000000
std     1.581139   820.487000
min     1.000000   512.000000
25%     2.000000  1024.000000
50%     3.000000  1536.000000
75%     4.000000  2048.000000
max     5.000000  2560.000000

DataFrame позволяет легко фильтровать, сортировать и визуализировать данные.

Индексация файлов в Python - comments

En
Python index files (python)