Какой инструмент использовать для рисования диаграммы дерева файлов
Учитывая дерево файлов - каталог с каталогами в нем и т.д., Как бы вы написали скрипт для создания схемы файлового дерева в виде графического файла, который я могу встроить в документ текстового процессора.
Я предпочитаю векторные (SVG, EPS, EMF...) файлы.
Инструмент должен работать на Windows, но желательно кроссплатформенный.
Инструмент может быть коммерческим, но предпочтительно бесплатным.
Обновление 2012-02-20.
Вопрос был связан с подпроектом документации. Мне пришлось объяснить, где находятся файлы (в частности, ресурсы и файлы конфигурации).
В итоге я использовал команду dos tree. Я оба экрана захватили результат (для коротких папок) И для более длинных папок я перенаправил в текстовый файл, который я затем отредактировал. Например, если подпапка содержала 20 файлов одинакового типа, которые по отдельности не были важны для того, что я делал, я оставил только два, а остальные заменил одной... строкой. Затем я снова распечатал файл на консоль, и экран его схватил.
Перед захватом экрана мне пришлось изменить цвет переднего плана на черный и цвет фона на белый, чтобы лучше выглядеть и экономить чернила в документе, который должен быть напечатан.
Очень удивительно, что лучшего инструмента для этого нет. Если бы у меня было время, я бы написал расширение Visio или, может быть, какую-то командную строку, которая выдает SVG. SVG, будучи некачественным HTML5, позволит даже безболезненное включение в онлайн-документацию.
Обновление 2017-10-17.
Я сожалею, что этот вопрос был удален как не принадлежащий SO. Так что я перефразировал это. Мне нужен скрипт, а не инструмент WYSIWYG. Таким образом, любой язык сценариев или библиотека в порядке. Так что это вопрос написания кода, и я считаю, что он принадлежит SO.
Ответы
Ответ 1
Копирование и вставка из команды MS-DOS tree
также может работать для вас. Примеры:
дерево
C:\Foobar>tree
C:.
├───FooScripts
├───barconfig
├───Baz
│ ├───BadBaz
│ └───Drop
...
дерево /F
C:\Foobar>tree
C:.
├───FooScripts
│ foo.sh
├───barconfig
│ bar.xml
├───Baz
│ ├───BadBaz
│ │ badbaz.xml
│ └───Drop
...
дерево /A
C:\Foobar>tree /A
C:.
+---FooScripts
+---barconfig
+---Baz
¦ +---BadBaz
¦ \---Drop
...
дерево /F/A
C:\Foobar>tree /A
C:.
+---FooScripts
¦ foo.sh
+---barconfig
¦ bar.xml
+---Baz
¦ +---BadBaz
¦ ¦ badbaz.xml
¦ \---Drop
...
tree
[drive:
] [path
] [/F
] [/A
]
drive:\path
- Дисковод и каталог, содержащий диск для отображения структуры каталогов, без файлов листинга.
/F
- Включите все файлы, живущие в каждом каталоге.
/A
- Заменить графические символы, используемые для связывания строк с внешними символами, вместо графических символов. /A
используется с кодовыми страницами, которые не поддерживают графические символы и отправляют выходные данные на принтеры, которые неправильно интерпретируют графические символы.
Ответ 2
Graphviz - с веб-страницы:
Программы макета Graphviz описывают графики на простом текстовом языке и делают диаграммы в нескольких полезных форматах, таких как изображения и SVG для веб-страниц, Postscript для включения в PDF или другие документы; или отображение в интерактивном графическом браузере. (Graphviz также поддерживает GXL, диалект XML).
Это самый простой и эффективный инструмент, который я нашел для создания различных диаграмм ящиков и линий. Я использую Visio и OmniGraffle, но всегда есть соблазн сделать "еще одну настройку".
Также довольно легко написать код для создания формата "dot file", который потребляет Graphiz, поэтому автоматическое создание диаграмм также прекрасно доступно.
Ответ 3
Как и было обещано, вот моя Каирская версия. Я написал его с помощью Lua, используя lfs, чтобы ходить по каталогам. Мне нравятся эти небольшие проблемы, так как они позволяют мне исследовать API, которые я давно хотел копать...
lfs и LuaCairo являются кросс-платформенными, поэтому он должен работать на других системах (проверен на французском WinXP Pro SP3).
Я сделал имена файлов чертежей первой версии, когда шел по дереву. Преимущество: отсутствие накладных расходов памяти. Неудобство: я должен заранее указать размер изображения, поэтому списки, вероятно, будут отключены.
Итак, я сделал эту версию, сначала пробив дерево каталогов, сохранив ее в таблице Lua. Затем, зная количество файлов, создавая холст, чтобы он поместился (по крайней мере, вертикально) и нарисовал имена.
Вы можете легко переключаться между рендерингом PNG и SVG. Проблема с последним: Каир генерирует его на низком уровне, рисуя буквы вместо использования возможности SVG-текста. Ну, по крайней мере, это гарантирует точный разрыв даже в системах без шрифта. Но файлы больше... Не проблема, если вы сжимаете ее, чтобы иметь файл .svgz.
Или это не должно быть слишком сложно для создания SVG напрямую, я использовал Lua для генерации SVG в прошлом.
-- LuaFileSystem <http://www.keplerproject.org/luafilesystem/>
require"lfs"
-- LuaCairo <http://www.dynaset.org/dogusanh/>
require"lcairo"
local CAIRO = cairo
local PI = math.pi
local TWO_PI = 2 * PI
--~ local dirToList = arg[1] or "C:/PrgCmdLine/Graphviz"
--~ local dirToList = arg[1] or "C:/PrgCmdLine/Tecgraf"
local dirToList = arg[1] or "C:/PrgCmdLine/tcc"
-- Ensure path ends with /
dirToList = string.gsub(dirToList, "([^/])$", "%1/")
print("Listing: " .. dirToList)
local fileNb = 0
--~ outputType = 'svg'
outputType = 'png'
-- dirToList must have a trailing slash
function ListDirectory(dirToList)
local dirListing = {}
for file in lfs.dir(dirToList) do
if file ~= ".." and file ~= "." then
local fileAttr = lfs.attributes(dirToList .. file)
if fileAttr.mode == "directory" then
dirListing[file] = ListDirectory(dirToList .. file .. '/')
else
dirListing[file] = ""
end
fileNb = fileNb + 1
end
end
return dirListing
end
--dofile[[../Lua/DumpObject.lua]] -- My own dump routine
local dirListing = ListDirectory(dirToList)
--~ print("\n" .. DumpObject(dirListing))
print("Found " .. fileNb .. " files")
--~ os.exit()
-- Constants to change to adjust aspect
local initialOffsetX = 20
local offsetY = 50
local offsetIncrementX = 20
local offsetIncrementY = 12
local iconOffset = 10
local width = 800 -- Still arbitrary
local titleHeight = width/50
local height = offsetIncrementY * (fileNb + 1) + titleHeight
local outfile = "CairoDirTree." .. outputType
local ctxSurface
if outputType == 'svg' then
ctxSurface = cairo.SvgSurface(outfile, width, height)
else
ctxSurface = cairo.ImageSurface(CAIRO.FORMAT_RGB24, width, height)
end
local ctx = cairo.Context(ctxSurface)
-- Display a file name
-- file is the file name to display
-- offsetX is the indentation
function DisplayFile(file, bIsDir, offsetX)
if bIsDir then
ctx:save()
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_BOLD)
ctx:set_source_rgb(0.5, 0.0, 0.7)
end
-- Display file name
ctx:move_to(offsetX, offsetY)
ctx:show_text(file)
if bIsDir then
ctx:new_sub_path() -- Position independent of latest move_to
-- Draw arc with absolute coordinates
ctx:arc(offsetX - iconOffset, offsetY - offsetIncrementY/3, offsetIncrementY/3, 0, TWO_PI)
-- Violet disk
ctx:set_source_rgb(0.7, 0.0, 0.7)
ctx:fill()
ctx:restore() -- Restore original settings
end
-- Increment line offset
offsetY = offsetY + offsetIncrementY
end
-- Erase background (white)
ctx:set_source_rgb(1.0, 1.0, 1.0)
ctx:paint()
--~ ctx:set_line_width(0.01)
-- Draw in dark blue
ctx:set_source_rgb(0.0, 0.0, 0.3)
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_BOLD)
ctx:set_font_size(titleHeight)
ctx:move_to(5, titleHeight)
-- Display title
ctx:show_text("Directory tree of " .. dirToList)
-- Select font for file names
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_NORMAL)
ctx:set_font_size(10)
offsetY = titleHeight * 2
-- Do the job
function DisplayDirectory(dirToList, offsetX)
for k, v in pairs(dirToList) do
--~ print(k, v)
if type(v) == "table" then
-- Sub-directory
DisplayFile(k, true, offsetX)
DisplayDirectory(v, offsetX + offsetIncrementX)
else
DisplayFile(k, false, offsetX)
end
end
end
DisplayDirectory(dirListing, initialOffsetX)
if outputType == 'svg' then
cairo.show_page(ctx)
else
--cairo.surface_write_to_png(ctxSurface, outfile)
ctxSurface:write_to_png(outfile)
end
ctx:destroy()
ctxSurface:destroy()
print("Found " .. fileNb .. " files")
Конечно, вы можете изменить стили. Я не рисовал линии связи, я не видел его по мере необходимости. Я могу добавить их позже.
Ответ 4
Почему бы вам не просто создать файловую структуру в файловой системе Windows и заполнить ее нужными именами, а затем использовать захват экрана, например HyperSnap (или вездесущий Alt-PrtScr), чтобы захватить раздел окна проводника.
Я сделал это, когда "демонтировал" интернет-приложение, которое имело бы разборчивые разделы, мне просто нужно было создавать файлы, похожие на мои нужные записи.
HyperSnap дает JPG как минимум (возможно, другие, но я никогда не потрудился расследовать).
Или вы можете отображать значки +/- из Проводника и использовать их в самой программе MS Word Draw, чтобы сделать свое изображение, но я никогда не мог заставить MS Word Draw вести себя правильно.
Ответ 5
Совет по использованию Graphviz хорош: вы можете генерировать точечный файл, и он будет выполнять тяжелую работу по измерению строк, выполнению макета и т.д. Кроме того, он может выводить графики во множестве форматов, включая векторные.
Я нашел программу Perl, которая делает именно это, в списке рассылки, но я просто не могу найти его обратно! Я скопировал образец файла точки и изучил его, так как я мало знаю этого декларативного синтаксиса, и мне хотелось узнать немного больше.
Проблема: с последним Graphviz у меня есть ошибки (или, скорее, предупреждения, так как генерируется окончательная диаграмма), как в исходном графике, так и в том, что я написал (вручную). Некоторые поиски, показавшие эту ошибку, были найдены в старых версиях и исчезли в более поздних версиях. Похоже, что он вернулся.
Я все еще даю файл, возможно, это может быть отправной точкой для кого-то, или, может быть, этого достаточно для ваших нужд (конечно, вы все равно должны его генерировать).
digraph tree
{
rankdir=LR;
DirTree [label="Directory Tree" shape=box]
a_Foo_txt [shape=point]
f_Foo_txt [label="Foo.txt", shape=none]
a_Foo_txt -> f_Foo_txt
a_Foo_Bar_html [shape=point]
f_Foo_Bar_html [label="Foo Bar.html", shape=none]
a_Foo_Bar_html -> f_Foo_Bar_html
a_Bar_png [shape=point]
f_Bar_png [label="Bar.png", shape=none]
a_Bar_png -> f_Bar_png
a_Some_Dir [shape=point]
d_Some_Dir [label="Some Dir", shape=ellipse]
a_Some_Dir -> d_Some_Dir
a_VBE_C_reg [shape=point]
f_VBE_C_reg [label="VBE_C.reg", shape=none]
a_VBE_C_reg -> f_VBE_C_reg
a_P_Folder [shape=point]
d_P_Folder [label="P Folder", shape=ellipse]
a_P_Folder -> d_P_Folder
a_Processing_20081117_7z [shape=point]
f_Processing_20081117_7z [label="Processing-20081117.7z", shape=none]
a_Processing_20081117_7z -> f_Processing_20081117_7z
a_UsefulBits_lua [shape=point]
f_UsefulBits_lua [label="UsefulBits.lua", shape=none]
a_UsefulBits_lua -> f_UsefulBits_lua
a_Graphviz [shape=point]
d_Graphviz [label="Graphviz", shape=ellipse]
a_Graphviz -> d_Graphviz
a_Tree_dot [shape=point]
f_Tree_dot [label="Tree.dot", shape=none]
a_Tree_dot -> f_Tree_dot
{
rank=same;
DirTree -> a_Foo_txt -> a_Foo_Bar_html -> a_Bar_png -> a_Some_Dir -> a_Graphviz [arrowhead=none]
}
{
rank=same;
d_Some_Dir -> a_VBE_C_reg -> a_P_Folder -> a_UsefulBits_lua [arrowhead=none]
}
{
rank=same;
d_P_Folder -> a_Processing_20081117_7z [arrowhead=none]
}
{
rank=same;
d_Graphviz -> a_Tree_dot [arrowhead=none]
}
}
> dot -Tpng Tree.dot -o Tree.png
Error: lost DirTree a_Foo_txt edge
Error: lost a_Foo_txt a_Foo_Bar_html edge
Error: lost a_Foo_Bar_html a_Bar_png edge
Error: lost a_Bar_png a_Some_Dir edge
Error: lost a_Some_Dir a_Graphviz edge
Error: lost d_Some_Dir a_VBE_C_reg edge
Error: lost a_VBE_C_reg a_P_Folder edge
Error: lost a_P_Folder a_UsefulBits_lua edge
Error: lost d_P_Folder a_Processing_20081117_7z edge
Error: lost d_Graphviz a_Tree_dot edge
Я попробую другое направление, используя Cairo, который также может экспортировать несколько форматов. Это больше работы (вычислительные позиции/смещения), но структура проста, не должна быть слишком сложной.