Я хотел бы создать карту того, какие файлы записаны, где на жестком диске. Он должен вывести что-то вроде дерева каталогов, а для каждого файла - список секторов ([10-20], [80-90], [60-70]), которые собираются вместе, чтобы составить весь файл. например, чтобы создать визуализацию, как дефрагментатор диска Windows старой школы:

дефрагментация окон

Есть ли инструменты для этого?

2 ответа2

1

Стандартным инструментом для производных Debian является Disk Usage Analyser (baobab), но он не показывает фрагментации.

Единственный известный мне способ демонстрации фрагментации - это использовать процесс командной строки для каждого файла отдельно, используя один из инструментов, описанных в этом ответе.

Для этого я написал скрипт, используя hdparm --fibmap:-

#!/bin/bash
#
# frags MountPoint SkipFrags    Reports all files under MountPoint with more than SkipFrags fragments
#       MountPoint defaults to / (root file system)
#       SkipFrags  defaults to 1 (report all files with more than one fragment)
#                  (setting to 0 will report all files, including unfragmanted)
#
# The report is sorted in fragment count order and must be run as root 
#
[ "${1:0:1}" == "-" ] && \
    echo 'frags MountPoint SkipFrags    Reports all files under MountPoint with more than SkipFrags fragments' && \
    echo '      MountPoint defaults to / (root file system)' && \
    echo '      SkipFrags  defaults to 1 (report all files with more than one fragment)' && \
    echo '                 (setting to 0 will report all files, including unfragmanted)' && \
    echo 'The report is sorted in fragment count order and must be run as root' && \
    { return 1 2>/dev/null; exit 1; }
[ "$(whoami)" != "root" ] && { echo 'Must be run from "root"' >&2; return 13 2>/dev/null; exit 13; }
eof='***EOF***'    ; # End-of-file marker
{ find "$1"/ -mount -type f; echo "$eof"; } | \
    while read -r f; \
        do  [ "$f" == "$eof" ] && { echo -ne "\e[K" >&2; continue; }; \
            r=$(hdparm --fibmap "$f" | grep -E "^[ 0-9]+$" | wc -l); \
            [ $r -gt "${2:-1}" ] && { echo -ne "\e[K--- $r: ${f::$(($COLUMNS-${#r}-6))}\r" >&2; echo "$r: $f"; } \
        done | \
sort -nt :

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

Процесс довольно медленный, и сортировка означает, что вы не получите никаких результатов до тех пор, пока не будет отсканирован каждый файл, поэтому я добавил диагностическое сообщение на stderr когда найден каждый файл, о котором будет сообщено. Экранирующая последовательность предназначена для xterm и зависит от $COLUMNS , устанавливаемого shopt -s checkwinsize; export COLUMNS в ~/.bashrc (или другой файл инициализации). Отказ от перевода строки останавливает прокрутку скрипта.

Я использовал [ ... ] && вместо if [ ... ]; then для уменьшения вложенности и сокращения сценария. return 1 2>/dev/null; exit 1; последовательность - это трюк, который я выбрал, чтобы вернуть код ошибки независимо от того, вызывается ли скрипт нормально или из ./source команда.

0

Я обычно пишу на python, поэтому, если кому-то интересна версия AFH для Python. Мой зависит от команды filefrag . Он проходит по дереву каталогов, начиная с root аргумента cli, и собирает имя файла, размер файла и экстенты блока. Может быть удобно добавить аргументы, чтобы указать размер блока и тому подобное, если это необходимо.

import subprocess
import os
import re
import argparse

size = re.compile("(\d+) \(\d+ block")

def get_extents(root):
    for root, dirs, files in os.walk(root):
        for f in files:
            fullpath = os.path.abspath(os.path.join(root, f))
            output = subprocess.check_output(["filefrag", "-e", "-v", fullpath]).decode("utf-8")
            lines = output.splitlines()
            sizeline = lines[1]
            extentlines = lines[3:-1]
            print(fullpath)
            print("size in bytes:", size.search(sizeline).group(1))
            extents = []
            for extentline in extentlines:
                stuff = extentline.split()
                lower = stuff[3].strip(".")
                upper = stuff[4].strip(":")
                extents.append((lower, upper))
            print("extents:", extents)

if __name__ == "__main__":
    parser = argparse.ArgumentParser("get the extents of all the files")
    parser.add_argument("root", type=os.path.expanduser, help="the root folder to examine recursively on")

    args = parser.parse_args()
    get_extents(args.root)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .