3

ディレクトリ ツリーを実行し、JSON 形式でファイルを一覧表示する単純な PowerShell スクリプトがあります。

各エントリの形式は次のとおりです。

{id: ファイル名、サイズ: バイト}

短いリストでは問題なく動作しますが、大きなディレクトリでは非常に遅くなります。また、その内容をファイル (manifest.json) に書き込みたいと考えています。

私は C# .NET を書くのがずっと得意です (私は Directory.EnumerateFiles() を使用します)。

しかし、PowerShell で単純なことを簡単に実行できないかどうかを確認できると思いました。

しかし、このスクリプトは、10,000 エントリに達すると本当に行き詰まります。

$src = "G:\wwwroot\BaseMaps\BigBlueMarble"
$path = $src + "\*"
$excludes = @("*.json", "*.ps1")
$version = "1.1"
Write-Host "{" 
Write-Host "`"manifest-version`": `"$version`","
Write-Host "`"files`": [" 

$dirs = Get-Item -Path $path -Exclude $excludes 
$dirs | Get-ChildItem -Recurse -File | % { 
    $fpath = $_.FullName.Replace($src, "").Replace("\","/")
    $date = $_.LastWriteTime
    $size = $_.Length
    $id = $_.BaseName
    Write-Host "{`"id`": `"$id`", `"size`": `"$size`"},"
    } 
Write-Host "]"
Write-Host "}"
4

3 に答える 3

2

Get-ChildItem遅いかもしれませんが (PowerShell 3 では v2 の約 2 倍の速さのように見えますが)、write-host速度も大幅に低下しています。27000 以上のファイルを含むディレクトリ構造では、次のコードは 16.15 秒で実行されましたが、コードは 21.08 秒で実行されました。約 2400 個のファイルを含む小さなディレクトリでは、1.15 秒と 1.22 秒でした。

gci $path -file -Recurse |
select @{name="fpath";expression={$_.fullname.replace($src,"").replace("\","/")}},lastwritetime,@{Name="size";Expression={$_.length}},@{Name="id";Expression={$_.basename}}|
select id,size|
ConvertTo-Json

結果の JSON にはヘッダーがありませんが、事後にそれを処理できるはずです。

于 2013-06-26T16:39:41.983 に答える
1

私のシステムでは:

$pf = "C:\Program Files" # has about 50,000 files
measure-command {$a=[io.Directory]::EnumerateFiles($pf,"*","AllDirectories")|%{$_}}

次の約 2 倍の速さでした。

measure-command {$a=gci "C:\Program Files" -Recurse}

ポイントは、Powershell で .NET クラスを非常に簡単に使用でき、さらにうまく機能する可能性があることです。

この場合、get-childitem コマンドには、実行する独自の .NET クラスがあり、[io.directory] ​​で何かを呼び出すファイル システム プロバイダー クラスを呼び出します。そのため、PowerShell プロバイダーの概念は非常に優れていますが、実行時のオーバーヘッドが追加されます。

于 2013-06-27T02:41:49.743 に答える
1

ユーティリティを C# と .NET で作成した方がよい場合もあります。非常に便利なJSON.NETライブラリを使用して、フォルダー (そのうちの 1 つには 10 万個の PNG ファイルがあります) を選択し、上記で試した json "マニフェスト" を 2 秒未満で作成できる WPF アプリケーションをまとめました。これは、アプリケーションの非 UI ワーカー部分です。上記のヒントをありがとう、彼らは役に立ちました。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows;
using Newtonsoft.Json;

namespace Manifest
{
    internal class Worker
    {
        private DateTime start;
        private ViewModel vm;
        private readonly BackgroundWorker worker = new BackgroundWorker();
        private ManifestObject manifest;

        public Worker()
        {
            vm = ViewModel.myself;
            manifest = new ManifestObject();
            manifest.version = "1.1";
            manifest.files = new List<FileData>();
            worker.DoWork += build;
            worker.RunWorkerCompleted += done;
            worker.RunWorkerAsync();
        }

        public void build(object sender, DoWorkEventArgs e)
        {

            vm.Status = "Working...";
            start = DateTime.Now;
            scan();
        }

        private void scan()
        {
            var top = new DirectoryInfo(vm.FolderPath);
            try
            {
                foreach (var fi in top.EnumerateFiles("*" + vm.FileType, SearchOption.TopDirectoryOnly))
                {
                    FileData fd = new FileData();
                    fd.size = fi.Length;
                    fd.id = fi.Name.Replace(vm.FileType, "");
                    manifest.files.Add(fd);
                    vm.FileCount++;
                }
            }
            catch (UnauthorizedAccessException error)
                    {
                        MessageBox.Show("{0}", error.Message);
                    }
        }

        private void done(object sender,RunWorkerCompletedEventArgs e)
        {
            var done = DateTime.Now;
            var elapsed = done - start;
            vm.ElapsedTime = elapsed.ToString();
            vm.Status = "Done Scanning...";
            write();
        }

        private void write()
        {
            File.WriteAllText(vm.FolderPath + @"\manifest.json", JsonConvert.SerializeObject(manifest, Formatting.Indented));
            vm.Status = "Done";
        }
    }
}
于 2013-07-01T19:54:56.707 に答える