我有一个简单的PowerShell脚本,它通过目录树运行,并以JSON格式列出文件。
每个条目的格式为:
{id:filename,size:bytes}
适用于短列表,但对于大型目录来说效果很慢。我还想将内容写入文件(manifest.json)。
我更擅长编写C#.NET(我会使用Directory.EnumerateFiles())
但我想我会在PowerShell中看到我是否能够轻松完成简单的事情。
但是当我获得10K条目时,这个脚本真的陷入困境。
$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 "}"
答案 0 :(得分:2)
Get-ChildItem
可能会变慢(尽管它在PowerShell 3中的速度似乎是在v2中的两倍),write-host
也会让您的速度减慢很多。在包含27000+个文件的目录结构中,以下代码在16.15秒内运行,而代码运行时间为21.08秒。在包含大约2400个文件的较小目录中,它是1.15秒vs 1.22s。
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没有您的标题,但您应该能够在事后处理它。
答案 1 :(得分:1)
在我的系统上:
$pf = "C:\Program Files" # has about 50,000 files
measure-command {$a=[io.Directory]::EnumerateFiles($pf,"*","AllDirectories")|%{$_}}
的速度是以下的两倍:
measure-command {$a=gci "C:\Program Files" -Recurse}
关键是你可以使用Powershell非常容易地使用.NET类,并且它们可以更好地工作。
在这种情况下,get-childitem命令有自己的.NET类来执行以及调用文件系统提供程序类,这些类无疑会在[io.directory]中调用。因此虽然powershell提供程序概念非常酷,但它确实增加了运行时开销。
答案 2 :(得分:1)
有时候在C#和.NET中编写实用程序可能会更好。使用一个非常方便的JSON.NET库,我将一个WPF应用程序放在一起,让我选择一个文件夹(其中一个有100K PNG文件),然后在不到2秒的时间内创建我在上面尝试过的json“manifest”。这是应用程序的非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";
}
}
}