Skip to content

Instantly share code, notes, and snippets.

@lysukhin
Last active April 26, 2017 12:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lysukhin/d33571730e8315b0edcd623e600151d0 to your computer and use it in GitHub Desktop.
Save lysukhin/d33571730e8315b0edcd623e600151d0 to your computer and use it in GitHub Desktop.
Задание из анкеты для Я.Стажировки
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Пожалуйста, выполните небольшое задание. Напишите функцию — аналог команды du. Функция должна иметь один параметр — путь к каталогу — и возвращать сумму размеров всех файлов в этом каталоге, включая файлы во вложенных каталогах. Представьте, что вы запустили полученную функцию и команду du в одном и том же каталоге. Функция возвратила большее число, чем команда du. Почему так могло получиться? Как это исправить?*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Начнем с того, что \"размер файла\" и \"место, занимаемое файлом на диске\" - это в общем случае не одно и то же. \n",
"\"Размером файла\" обычно называют собственно количество байт в файле. Пусть у нас есть файл `F.txt` размером FS = 15 КБ. \n",
"\n",
"Диск обычно разделен на блоки некоторого фиксированного размера; один и тот же блок не может быть \"поделен\" между двумя \"хозяевами\"-файлами. Пусть размер блока на нашем диске 4КБ.\n",
"Наш файл F, очевидно, потребует минимум 4 блока на диске (т.к. `3 x 4 = 12 < 15`), т.е. при собственном размере в 15 КБ он займет не менее 16 КБ. Обозначим размер занятого места за DS.\n",
"\n",
"Теперь непосредственно к команде `du`. Вызов **`du F.txt`** без дополнительных ключей вернёт число `(DS / 1024)`, т.е. (округлённый) размер занятого места на диске в КБ. Собственный размер файла (в байтах) можно узнать с ключом `--apparent-size:` **`du --apparent-size F.txt`**. В результате должны получить число `FS`. \n",
"\n",
"Тонким моментом является работа с разреженными (`sparse`) файлами, у которых собственный (`apparent`) размер может быть больше, чем размер на диске. Это происходит от того, что разреженные файлы содержат участки с последоватальностями нулей, которые файловая система не записывает на диск, но сохраняет информацию о том, где они расположены в файле.\n",
"\n",
"Т.к. нам нужна функция-аналог `du` без дополнительных параметров, напишем функцию, рекурсивно проходящуюся по всем вложенным директориям и возвращающую суммарный размер занятого места на диске вложенными файлами. Пустая директория тоже занимает место на диске (размер 1 блока). Библиотека `os` позволяет узнать как собственный размер файла, так и занимаемый размер на диске."
]
},
{
"cell_type": "code",
"execution_count": 249,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import os"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Напишем 2 функции: \n",
"+ `getFileSize()` для определения размера файла\n",
"+ `getDirSize()` для определения размера директории"
]
},
{
"cell_type": "code",
"execution_count": 260,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def getFileSize(filename):\n",
" \n",
" stats = os.stat(filename)\n",
" \n",
" # получение собственного размера файла\n",
" fs = stats.st_size\n",
" \n",
" # получение занятого места на диске: (число блоков по 512 байт) х 512 \n",
" fs_d = stats.st_blocks * 512\n",
" \n",
" # возвращаем размеры в байтах\n",
" return (fs, fs_d) \n",
"\n",
"def getDirSize(path, ondisk=True):\n",
" \n",
" size = 0\n",
" ondisk = int(ondisk)\n",
" \n",
" # размер пустой директории\n",
" dirsize = 4096\n",
" \n",
" # цикл по всем поддиректориям\n",
" for root, subdirs, files in os.walk(path):\n",
" size_cur = dirsize + sum([getFileSize(root + '/' + f)[ondisk] for f in files])\n",
" size += size_cur\n",
" \n",
" # возвращаем размер в килобайтах (как и `du`)\n",
" return size / 1024"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Проверим работу `getFileSize()` на тестовом документе:"
]
},
{
"cell_type": "code",
"execution_count": 261,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(30, 4096)"
]
},
"execution_count": 261,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"getFileSize(\"/data/test_dir/test_txt\")"
]
},
{
"cell_type": "code",
"execution_count": 262,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"30\t/data/test_dir/test_txt\n",
"4096\t/data/test_dir/test_txt\n"
]
}
],
"source": [
"!du --apparent-size -B1 /data/test_dir/test_txt\n",
"!du -B1 /data/test_dir/test_txt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Проверим работу `getDirSize()` на тестовой директории:"
]
},
{
"cell_type": "code",
"execution_count": 271,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"32\n"
]
}
],
"source": [
"print getDirSize(\"/data/test_dir/\", ondisk=True)"
]
},
{
"cell_type": "code",
"execution_count": 272,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"8\t/data/test_dir/test_subdir_1/test_subdir_3\r\n",
"16\t/data/test_dir/test_subdir_1\r\n",
"4\t/data/test_dir/test_subdir_2/.hidden_test_subdir\r\n",
"8\t/data/test_dir/test_subdir_2\r\n",
"32\t/data/test_dir/\r\n"
]
}
],
"source": [
"!du /data/test_dir/"
]
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python [conda root]",
"language": "python",
"name": "conda-root-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.12"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment