44

我正在尝试在 Windows 命令行中使用 tree 命令来生成一个列出目录内容的文本文件,但是当我通过管道输出时,unicode 字符会被填满。

这是我正在使用的命令:

tree /f /a > output.txt

控制台窗口中的结果很好:

\---Erika szobája
        封面.jpg
        Erika szobája.m3u
        Kátai Tamás - 01 Télvíz.ogg
        Kátai Tamás - 02 Zölderdõ.ogg
        Kátai Tamás - 03 雷诺阿 kertje.ogg
        Kátai Tamás - 04 Esõben szaladtál.ogg
        Kátai Tamás - 05 Ázik az út.ogg
        Kátai Tamás - 06 Sûrû völgyek takaród.ogg
        Kátai Tamás - 07 Õszhozó.ogg
        Kátai Tamás - 08 Mécsvilág.ogg
        Kátai Tamás - 09 Zúzmara.ogg

但是文本文件不好:

\---Erika szob ja
        封面.jpg
        Erika szob ja.m3u
        K tai Tam s - 01 T‚lv¡z.ogg
        K tai Tam s - 02 Z”lderdä.ogg
        K tai Tam s - 03 雷诺阿 kertje.ogg
        K tai Tam s - 04 Esäben szaladt l.ogg
        K tai Tam s - 05 µzik az £t.ogg
        K tai Tam s - 06 S–r– v”lgyek takar¢d.ogg
        K tai Tam s - 07 åszhoz¢.ogg
        K tai Tam s - 08 M‚csvil g.ogg
        K tai Tam s - 09 Z£zmara.ogg

我怎样才能解决这个问题?理想情况下,文本文件将与控制台窗口中的输出完全相同。

我尝试了使用 /U 开关运行命令行的 Chris Jester-Young 的建议(发生了什么事,你删除了它吗?),它看起来正是我需要的,但它似乎不起作用。我尝试在 VS2008 和记事本中打开文件,都显示相同的错误字符。

4

13 回答 13

66

有人已经尝试过这个:

tree /f /a |clip

打开记事本,ctrl + V,在记事本中保存为支持unicode的output.txt?

于 2012-06-26T02:02:42.377 回答
17

使用 PowerShell:

powershell -command "tree /f > tree.txt"

测试用例:

create.ps1

mkdir "Erika szobája"
$null | Set-Content "Erika szobája/cover.jpg"
$null | Set-Content "Erika szobája/Erika szobája.m3u"
$null | Set-Content "Erika szobája/Kátai Tamás - 01 Télvíz.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 02 Zölderdõ.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 03 Renoir kertje.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 04 Esõben szaladtál.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 05 Ázik az út.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 06 Sûrû völgyek takaród.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 07 Õszhozó.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 08 Mécsvilág.ogg"
$null | Set-Content "Erika szobája/Kátai Tamás - 09 Zúzmara.ogg"

输出:

tree.txt

Folder PATH listing
Volume serial number is 00000000 0000:0000
C:.
│   create.ps1
│   tree.txt
│   
└───Erika szobája
        cover.jpg
        Erika szobája.m3u
        Kátai Tamás - 01 Télvíz.ogg
        Kátai Tamás - 02 Zölderdo.ogg
        Kátai Tamás - 03 Renoir kertje.ogg
        Kátai Tamás - 04 Esoben szaladtál.ogg
        Kátai Tamás - 05 Azik az út.ogg
        Kátai Tamás - 06 Sûrû völgyek takaród.ogg
        Kátai Tamás - 07 Oszhozó.ogg
        Kátai Tamás - 08 Mécsvilág.ogg
        Kátai Tamás - 09 Zúzmara.ogg

编辑:

高级用户的增强和改进版本

使用 Unicode 的列表树菜单

测试用例:

$null | Set-Content "欲速则不达.txt"
$null | Set-Content "爱不是占有,是欣赏.txt"
$null | Set-Content "您先请是礼貌.txt"
$null | Set-Content "萝卜青菜,各有所爱.txt"
$null | Set-Content "广交友,无深交.txt"
$null | Set-Content "一见钟情.txt"
$null | Set-Content "山雨欲来风满楼.txt"

$null | Set-Content "悪妻は百年の不作。.txt"
$null | Set-Content "残り物には福がある。.txt"
$null | Set-Content "虎穴に入らずんば虎子を得ず。.txt"
$null | Set-Content "夏炉冬扇.txt"
$null | Set-Content "花鳥風月.txt"
$null | Set-Content "起死回生.txt"
$null | Set-Content "自業自得.txt"

$null | Set-Content "아는 길도 물어가라.txt"
$null | Set-Content "빈 수레가 요란하다.txt"
$null | Set-Content "방귀뀐 놈이 성낸다.txt"
$null | Set-Content "뜻이 있는 곳에 길이 있다.txt"
$null | Set-Content "콩 심은데 콩나고, 팥 심은데 팥난다.txt"

从他的回答中,@Chris Jester-Young 写道:

现在,在 中ulib,该WriteString方法在两个类中实现,SCREEN并且STREAM。该SCREEN版本 WriteConsoleW直接使用,因此所有 Unicode 字符都能正确显示。该STREAM版本将 Unicode 文本转换为三种不同编码之一(_UseConsoleConversions⇒ 控制台代码页 ( GetConsoleCP)、_UseAnsiConversions⇒ 默认 ANSI 代码页,否则 ⇒ 默认 OEM 代码页),然后将其写出。

这意味着我们不能依赖从流中获取字符。文件重定向不起作用。我们必须依靠写入控制台来获取 Unicode 字符。

解决方法或 hack 是将树写入控制台,然后将缓冲区转储到文件中。

当您在资源管理器中右键单击目录时,我已经编写了添加树上下文菜单的脚本。将文件保存在同一目录中,然后Install list menu.bat以管理员身份运行进行安装。

Install list menu.bat

@echo on

regedit /s "List files.reg"

copy "List.ps1" "%SystemRoot%"

pause

List files.reg

Windows Registry Editor Version 5.00

; Directory.
[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Shell\List]
"MUIVerb"="List"
"ExtendedSubCommandsKey"="Directory\\ContextMenus\\List"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\ContextMenus\List\Shell\Files]
"MUIVerb"="Files"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\ContextMenus\List\Shell\Files\Command]
; powershell -executionPolicy bypass "%SystemRoot%\List.ps1" -type 'files' -directory '%1'
@=hex(2):70,00,6f,00,77,00,65,00,72,00,73,00,68,00,65,00,6c,00,6c,00,20,00,2d,\
  00,65,00,78,00,65,00,63,00,75,00,74,00,69,00,6f,00,6e,00,50,00,6f,00,6c,00,\
  69,00,63,00,79,00,20,00,62,00,79,00,70,00,61,00,73,00,73,00,20,00,22,00,25,\
  00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,\
  4c,00,69,00,73,00,74,00,2e,00,70,00,73,00,31,00,22,00,20,00,2d,00,74,00,79,\
  00,70,00,65,00,20,00,27,00,66,00,69,00,6c,00,65,00,73,00,27,00,20,00,2d,00,\
  64,00,69,00,72,00,65,00,63,00,74,00,6f,00,72,00,79,00,20,00,27,00,25,00,31,\
  00,27,00,00,00

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\ContextMenus\List\Shell\FilesRecursively]
"MUIVerb"="Files recursively"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\ContextMenus\List\Shell\FilesRecursively\Command]
; powershell -executionPolicy bypass "%SystemRoot%\List.ps1" -type 'filesRecursively' -directory '%1'
@=hex(2):70,00,6f,00,77,00,65,00,72,00,73,00,68,00,65,00,6c,00,6c,00,20,00,2d,\
  00,65,00,78,00,65,00,63,00,75,00,74,00,69,00,6f,00,6e,00,50,00,6f,00,6c,00,\
  69,00,63,00,79,00,20,00,62,00,79,00,70,00,61,00,73,00,73,00,20,00,22,00,25,\
  00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,\
  4c,00,69,00,73,00,74,00,2e,00,70,00,73,00,31,00,22,00,20,00,2d,00,74,00,79,\
  00,70,00,65,00,20,00,27,00,66,00,69,00,6c,00,65,00,73,00,52,00,65,00,63,00,\
  75,00,72,00,73,00,69,00,76,00,65,00,6c,00,79,00,27,00,20,00,2d,00,64,00,69,\
  00,72,00,65,00,63,00,74,00,6f,00,72,00,79,00,20,00,27,00,25,00,31,00,27,00,\
  00,00

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\ContextMenus\List\Shell\Tree]
"MUIVerb"="Tree"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\ContextMenus\List\Shell\Tree\Command]
; powershell -executionPolicy bypass "%SystemRoot%\List.ps1" -type 'tree' -directory '%1'
@=hex(2):70,00,6f,00,77,00,65,00,72,00,73,00,68,00,65,00,6c,00,6c,00,20,00,2d,\
  00,65,00,78,00,65,00,63,00,75,00,74,00,69,00,6f,00,6e,00,50,00,6f,00,6c,00,\
  69,00,63,00,79,00,20,00,62,00,79,00,70,00,61,00,73,00,73,00,20,00,22,00,25,\
  00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,\
  4c,00,69,00,73,00,74,00,2e,00,70,00,73,00,31,00,22,00,20,00,2d,00,74,00,79,\
  00,70,00,65,00,20,00,27,00,74,00,72,00,65,00,65,00,27,00,20,00,2d,00,64,00,\
  69,00,72,00,65,00,63,00,74,00,6f,00,72,00,79,00,20,00,27,00,25,00,31,00,27,\
  00,00,00

; Directory background.
[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Background\Shell\List]
"MUIVerb"="List"
"ExtendedSubCommandsKey"="Directory\\Background\\ContextMenus\\List"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Background\ContextMenus\List\Shell\Files]
"MUIVerb"="Files"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Background\ContextMenus\List\Shell\Files\Command]
; powershell -executionPolicy bypass "%SystemRoot%\List.ps1" -type 'files' -directory '%V'
@=hex(2):70,00,6f,00,77,00,65,00,72,00,73,00,68,00,65,00,6c,00,6c,00,20,00,2d,\
  00,65,00,78,00,65,00,63,00,75,00,74,00,69,00,6f,00,6e,00,50,00,6f,00,6c,00,\
  69,00,63,00,79,00,20,00,62,00,79,00,70,00,61,00,73,00,73,00,20,00,22,00,25,\
  00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,\
  4c,00,69,00,73,00,74,00,2e,00,70,00,73,00,31,00,22,00,20,00,2d,00,74,00,79,\
  00,70,00,65,00,20,00,27,00,66,00,69,00,6c,00,65,00,73,00,27,00,20,00,2d,00,\
  64,00,69,00,72,00,65,00,63,00,74,00,6f,00,72,00,79,00,20,00,27,00,25,00,56,\
  00,27,00,00,00

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Background\ContextMenus\List\Shell\FilesRecursively]
"MUIVerb"="Files recursively"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Background\ContextMenus\List\Shell\FilesRecursively\Command]
; powershell -executionPolicy bypass "%SystemRoot%\List.ps1" -type 'filesRecursively' -directory '%V'
@=hex(2):70,00,6f,00,77,00,65,00,72,00,73,00,68,00,65,00,6c,00,6c,00,20,00,2d,\
  00,65,00,78,00,65,00,63,00,75,00,74,00,69,00,6f,00,6e,00,50,00,6f,00,6c,00,\
  69,00,63,00,79,00,20,00,62,00,79,00,70,00,61,00,73,00,73,00,20,00,22,00,25,\
  00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,\
  4c,00,69,00,73,00,74,00,2e,00,70,00,73,00,31,00,22,00,20,00,2d,00,74,00,79,\
  00,70,00,65,00,20,00,27,00,66,00,69,00,6c,00,65,00,73,00,52,00,65,00,63,00,\
  75,00,72,00,73,00,69,00,76,00,65,00,6c,00,79,00,27,00,20,00,2d,00,64,00,69,\
  00,72,00,65,00,63,00,74,00,6f,00,72,00,79,00,20,00,27,00,25,00,56,00,27,00,\
  00,00

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Background\ContextMenus\List\Shell\Tree]
"MUIVerb"="Tree"

[HKEY_LOCAL_MACHINE\Software\Classes\Directory\Background\ContextMenus\List\Shell\Tree\Command]
; powershell -executionPolicy bypass "%SystemRoot%\List.ps1" -type 'tree' -directory '%V'
@=hex(2):70,00,6f,00,77,00,65,00,72,00,73,00,68,00,65,00,6c,00,6c,00,20,00,2d,\
  00,65,00,78,00,65,00,63,00,75,00,74,00,69,00,6f,00,6e,00,50,00,6f,00,6c,00,\
  69,00,63,00,79,00,20,00,62,00,79,00,70,00,61,00,73,00,73,00,20,00,22,00,25,\
  00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,\
  4c,00,69,00,73,00,74,00,2e,00,70,00,73,00,31,00,22,00,20,00,2d,00,74,00,79,\
  00,70,00,65,00,20,00,27,00,74,00,72,00,65,00,65,00,27,00,20,00,2d,00,64,00,\
  69,00,72,00,65,00,63,00,74,00,6f,00,72,00,79,00,20,00,27,00,25,00,56,00,27,\
  00,00,00

List.ps1

function sortNaturally {
    [Regex]::replace($_, '\d+', {
        $args[0].value.padLeft(20)
    })
}

function writeList {
    param(
        [parameter(mandatory = $true)]
        [string] $text = $null
    )

    $filePath = "$env:temp\List.txt"
    $text > "$filePath"
    notepad "$filePath" | out-null
    del "$filePath"
}

function listFiles {
    param(
        [switch] $recurse = $false
    )

    get-childItem -name -recurse:$recurse -force | sort-object $function:sortNaturally | out-string
}

function listTree {
    tree /f
}

function getBufferText {
    $rawUi = $host.ui.rawUi
    $width = [Math]::max([Math]::max($rawUi.bufferSize.width, $rawUi.windowSize.width) - 1, 0)
    $height = [Math]::max($rawUi.cursorPosition.y - 1, 0)

    $lines = new-object System.Text.StringBuilder
    $characters = new-object System.Text.StringBuilder

    for ($h = 0; $h -lt $height; $h += 1) {
        $rectangle = new-object System.Management.Automation.Host.Rectangle 0, $h, $width, $h
        $buffer = $rawUi.getBufferContents($rectangle)

        for ($w = 0; $w -lt $width; $w += 1) {
            $cell = $buffer[0, $w]
            $character = $cell.character
            $characters.append($character) | out-null
        }

        $lines.appendLine($characters.toString()) | out-null
        $characters.length = 0
    }

    $lines.toString() -replace '[ \0]*\r?\n', "`r`n"
}

function main {
    param(
        [parameter(mandatory = $true)]
        [string] $type = $null,

        [parameter(mandatory = $true)]
        [string] $directory = $null
    )

    $outputEncoding = [Text.UTF8Encoding]::UTF8
    [Console]::outputEncoding = [Text.UTF8Encoding]::UTF8
    $PSDefaultParameterValues['out-file:encoding'] = 'utf8'

    set-location -literalPath "$directory"

    $typeFunction = @{
        'files' = { writeList -text $(listFiles) };
        'filesRecursively' = { writeList -text $(listFiles -recurse) };
        'tree' = {
            listTree
            writeList -text $(getBufferText)
        }
    }

    &($typeFunction.get_item($type))
}

main @args
于 2013-04-12T01:45:49.003 回答
11

如果您输出为非 Unicode(您显然是这样做的),您必须使用控制台窗口使用的相同编码查看您创建的文本文件。这就是它在控制台中看起来正确的原因。在某些文本编辑器中,您可以在打开文件时选择编码(或“代码页”)。(如何输出为 Unicode 我不知道。 cmd /U 没有按照文档所说的那样做。)

控制台编码取决于您的 Windows 安装。对我来说,它是 Microsoft Word 中的“西欧 (DOS)”(或只是“MS-DOS”)。

于 2008-09-26T10:59:40.637 回答
6

我决定我必须看看tree.com并弄清楚为什么它不尊重控制台的 Unicode 设置。事实证明(就像许多命令行文件实用程序一样),它使用一个名为的库ulib.dll来执行所有打印(特别是TREE::DisplayName调用WriteStringin ulib)。

现在,在 中ulib,该WriteString方法在两个类中实现,SCREEN并且STREAM。该SCREEN版本WriteConsoleW直接使用,因此所有 Unicode 字符都能正确显示。该STREAM版本将 Unicode 文本转换为三种不同编码之一(_UseConsoleConversions⇒ 控制台代码页 ( GetConsoleCP)、_UseAnsiConversions⇒ 默认 ANSI 代码页,否则 ⇒ 默认 OEM 代码页),然后将其写出。我不知道如何更改转换模式,我不相信可以禁用转换。

我只是简单地看了这个,所以也许更喜欢冒险的灵魂可以更多地谈论它!:-)

于 2008-09-26T12:54:49.913 回答
5

这会将结果保存为 ASCII(美国信息交换标准代码)在您的桌面上,ASCII\ANSI 不能识别每个国际或扩展字符:

tree /f > ascii.txt

这会将您的 ASCII 文本转换为 Unicode(/c 必须在实际命令之前):

cmd /u /c type ascii.txt > unicode.txt

那么为什么不把 ascii 文件看作一个临时文件并删除它呢?

del ascii.txt

如果您必须将所有内容放在一行中,您可以使用:

tree /f > ascii.txt & cmd.exe /u /c type ascii.txt > unicode.txt & del ascii.txt
于 2013-04-18T15:50:05.740 回答
4

简短的回答是你不能,这是因为tree.com它是一个 ANSI 应用程序,即使在 Windows 7 上也是如此。

唯一的解决方案是编写自己的tree实现。您也可以向 Microsoft 提交错误,但我怀疑他们还没有意识到这一点。

于 2010-05-04T17:22:20.383 回答
4

你可以试试

tree /A > output.txt

虽然它看起来与 CMD 线不同,但它仍然可以接受。:P

于 2013-01-25T08:23:36.300 回答
2

这对我有用:

tree /f /a > %temp%\Listing >> files.txt
于 2011-12-19T03:53:07.540 回答
2

XP1 的答案很好,但有一个小警告:输出编码是 UCS2-LE,而我更喜欢 UTF8(更小的文件大小,更广泛)。

经过大量搜索和挠头,我终于可以向您展示以下命令,该命令会生成一个 UTF8-BOM 文件:

PowerShell -Command "TREE /F | Out-File output.txt -Encoding utf8"

如果输出文件名有空格:

PowerShell -Command "TREE /F | Out-File ""output file.txt"" -Encoding utf8"

非常感谢这篇文章:https ://www.kongsli.net/2012/04/20/powershell-gotchas-redirect-to-file-encodes-in-unicode/


另外,我个人在我的 PATH 中创建了以下文件:

xtree.cmd

@IF [%1]==[] @(
    ECHO You have to specify an output file.
    GOTO :EOF
)

@PowerShell -Command "TREE | Out-File %1 -Encoding utf8"

xtreef.cmd

@IF [%1]==[] @(
    ECHO You have to specify an output file.
    GOTO :EOF
)

@PowerShell -Command "TREE /F | Out-File %1 -Encoding utf8"

最后,而不是tree > output.txt我只是做xtree output.txt

于 2018-07-10T00:48:50.443 回答
1

我已经设法通过Take Command Console正确地将树命令中的非 ascii 字符输出到文件中。

在 TCC 中键入“选项”并在第一个选项卡上选择“Unicode 输出”。然后简单地运行

tree /f /a > output.txt
于 2017-05-29T13:53:48.470 回答
0

我已经成功地获得了控制台中的输出,所有非ASCII字符都没有转换,通过输出到控制台(只是tree)然后从中复制(系统菜单->编辑->标记,全选,回车) . 控制台缓冲区大小应根据文件/文件夹的数量在控制台的属性(系统菜单 -> 属性)中提前增加。其他方法都不起作用。tree|clip,在之前的文章中提到,将非 ascii 字符转换为 ascii 字符,与tree>file.txt.

于 2016-08-11T20:52:54.267 回答
0

我使用这种方法对近 100 个 SDRAM 和 USB 闪存驱动器进行了编目,并且效果很好。

从DOS内部......

C:\doskey [enter] {启用方便的键盘快捷键}

C:\tree j:\ >> d:\MyCatalog.txt /a [enter] {j:= is my USB drive ; d:= 是我想要目录的地方;/a = 查看此页面上的其他帖子}

于 2019-04-27T21:40:07.403 回答
0

XP1 的答案很棒,或者至少是这里最好的答案——tree 命令即使经过这种处理也无法处理某些符号。

但是,至少在我的设置中,这个脚本会生成缺少最后一行的树。虽然我不确定为什么会发生这种情况,但可以通过修改函数 listTree 来修复它,如下所示:

function listTree {
    tree /f
    echo .
}

Whereecho .打印一行让 PowerShell 自由蚕食。这种牺牲满足了它,并且整个树都被输出了。

于 2021-07-22T17:48:17.170 回答