使用什么工具绘制文件树形图


90

给定一个文件树-在其中有目录的目录等,您将如何编写脚本以将文件树的图表创建为图形文件,然后将其嵌入到文字处理器文档中。我更喜欢矢量(SVG,EPS,EMF ...)文件。该工具必须在Windows上运行,但最好在跨平台上运行。该工具可以是商业的,但是优选地是免费的。

更新2012-02-20。该问题与文档子项目有关。我不得不解释文件(特别是资源和配置文件)所在的位置。我最终使用了dos tree命令。我两个屏幕都抓取了结果(对于短文件夹),对于较长的文件夹,我都重定向到了文本文件,然后对其进行了编辑。例如,如果一个子文件夹包含20个相似类型的文件,这些文件对于我提出的要点分别并不重要,那么我只留下了两个,其余的替换为一行。然后,我打印出该文件以再次进行控制台,然后屏幕抓取它。在抓屏之前,我不得不将前景色修改为黑色,将背景色修改为白色,以使其看起来更好,并在应打印的文档中节省墨水。

令人惊讶的是,没有更好的工具。如果有时间,我会写一个Visio Extension或可能是产生SVG的某些命令行。SVG是HTML5次标准的,甚至可以轻松地包含到在线文档中。

更新2017-10-17。很抱歉,这个问题已被删除,因为它不属于SO。所以我重新措词了。我需要一个脚本-而不是所见即所得的工具。因此,任何脚本语言或库都可以。所以这是一个代码-写作问题,我相信属于SO。


10
为什么这个问题关闭?有编程DSL来绘制树的方法:例如诸如graphviz之类的工具,可以“以编程方式”解决该问题。
Piotr Lesnicki

5
我将(暂时)重新打开它,因为如果这是一个简单的“如何显示屏幕上的内容”,他会要求屏幕抓取器。如果他想绘制它,可能是设计文档或演示文稿,因此他将在某个时候进行编程。
paxdiablo

2
同意 在此之前,我需要使用相同类型的功能,并且不得不通过Visio对其进行伪装。欧盟文档需要它。绝对与代码有关。
约瑟夫·费里斯

6
非常愚蠢,将其关闭为题外。我也发现需要一些东西。.所以喜欢审查。
Boltimuss 2014年

1
如果我的问题不在这里,很抱歉。我了解原因。感谢所有提出要求的人,它很有帮助。为了明确起见,我需要一个图来将其包含在项目树的文档中。屏幕截图不会剪切它,因为整个树长于一个屏幕的长度。
迈克尔

Answers:


95

从MS-DOStree命令复制和粘贴也可能对您有用。例子:

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—将用于链接线的图形字符替换为ext字符,而不是图形字符。/a用于不支持图形字符的代码页,并将输出发送给不能正确解释图形字符的打印机。


1
好主意,但是如果文件/文件夹带有重音字母,它们将位于OEM字符集中,而不是Ansi。当然,对于大多数(至少会说英语)的用户来说,可能不是问题。与半图形字符相同。
PhiLho

4
Linux还有一个像这样的“ tree”命令,我在检查了这个Stack Overflow问题后才发现的。感谢您指出我应该寻找的名称!“ tree -A”是如何使用漂亮的绘图字符创建树;普通的“树”仅将自身限制为ASCII。
布兰登·罗兹

1
很好,我什至都不知道该命令
MiniScalope 2010年

感谢所有人的参与,存在许多选择。我认为这是一个答案,因为这就是我最后使用的答案。
Michael

1
或直接将其保存到文件中:tree > file_structure.txt我知道这在Unix系统上有效。我不知道它是否也可以在Windows上运行。
Lucio Mollinedo

19

Graphviz-从网页:

Graphviz布局程序以简单的文本语言描述图形,并以几种有用的格式制作图形,例如用于网页的图像和SVG,用于PDF或其他文档的Postscript。或在交互式图形浏览器中显示。(Graphviz还支持XML方言GXL。)

我发现它是创建各种箱线图的最简单,最高效的工具。我拥有并使用Visio和OmniGraffle,但是总是存在“仅需再进行一次调整”的诱惑。

编写代码以生成Graphiz所使用的“点文件”格式也非常容易,因此自动生成图表也很容易实现。


5

如所承诺的,这是我的开罗版本。我用Lua编写脚本,使用lfs遍历目录。我喜欢这些小挑战,因为它们使我能够探索相当长一段时间想要挖掘的API ...
lfs和LuaCairo都是跨平台的,因此它应该可以在其他系统上运行(在法语WinXP Pro SP3上进行了测试)。

我在树上行走时制作了第一个版本的图形文件名。优点:无内存开销。不便之处:我必须事先指定图像尺寸,因此清单可能会被切断。

因此,我制作了此版本,首先遍历目录树,并将其存储在Lua表中。然后,知道文件的数量,创建适合(至少垂直放置)的画布并绘制名称。
您可以轻松地在PNG渲染和SVG渲染之间切换。后者的问题:Cairo在较低级别生成它,绘制字母而不是使用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")

当然,您可以更改样式。我没有画连接线,也没有看到必要的线。以后可以选择添加它们。


3

为什么不只在Windows文件系统上制作一个文件结构并用所需的名称填充它,然后使用诸如HyperSnap(或无处不在的Alt-PrtScr)之类的屏幕抓取器来捕获Explorer窗口的一部分。

我是在“演示”具有可折叠部分的Internet应用程序时执行此操作的,我只需要创建看起来像所需条目的文件即可。

HyperSnap至少提供JPG(可能是其他JPG,但我从来没有打扰过调查)。

或者,您可以从资源管理器中截屏图标+/-,并在MS Word Draw本身中使用它们来制作图片,但是我从来无法使MS Word Draw正常工作。


2

使用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

我将使用开罗尝试另一个方向,开罗还可以导出多种格式。它需要做更多的工作(计算位置/偏移),但是结构简单,不应太难。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.