PowerShell 创建一个包含零大小文件的重复文件夹
PowerShell create a duplicate folder with zero-size files
我想创建一组文件夹的 0 文件大小的镜像,但是虽然 robocopy 非常好,但它并没有保存我想要的所有信息:
robocopy D:\documents E:\backups\documents_$(Get-Date -format "yyyyMMdd_HHmm")\ /mir /create
/create
开关使重复文件夹中的每个文件都具有零大小,这很好,但我希望重复文件夹中的每个文件都将 [size]
附加到末尾大小以 KB 或 MB 或 GB 为单位的名称,以及每个文件的创建/上次修改时间以与原始文件完全匹配。这样,我将拥有可存档文件夹的零大小副本,但其中包含该目录中文件的所有相关信息,显示每个文件的大小以及确切的创建/上次修改时间。
是否有好的/简单的方法来遍历 PowerShell 中的树,并为每个项目创建一个包含所有相关信息的零大小文件?
这将是使用我在评论中提到的方法实现复制命令的一种方法。这应该会给你一些灵感。我不打算像我那样花那么多时间在上面,但是我 运行 它在几个目录上发现了一些问题并调试了我遇到的每个问题。这是一个非常可靠的例子。
function Copy-FolderZeroSizeFiles {
[CmdletBinding()]
param( [Parameter(Mandatory)] [string] $FolderPath,
[Parameter(Mandatory)] [string] $DestinationPath )
$dest = New-Item $DestinationPath -Type Directory -Force
Push-Location -LiteralPath $FolderPath
try {
foreach ($item in Get-ChildItem '.' -Recurse) {
$relPath = Resolve-Path -LiteralPath $item -Relative
$type = if ($item.Attributes -match 'Directory')
{ 'Directory' }
else { 'File' }
$destItem = New-Item "$dest$relPath" -Type $type -Force
$destItem.Attributes = $item.Attributes
$destItem.LastWriteTime = $item.LastWriteTime
}
} finally {
Pop-Location
}
}
注意:上面的实现很简单,将目录之外的任何内容都表示为文件。这意味着符号链接等。将是没有信息的文件,它们将链接到什么。
这里有一个函数可以将字节数转换为 N.N B/K/M/G 格式。要获得更多小数位,只需将 0
添加到格式字符串的末尾即可。
function ConvertTo-FriendlySize($NumBytes) {
switch ($NumBytes) {
{$_ -lt 1024} { "{0,7:0.0}B" -f ($NumBytes) ; break }
{$_ -lt 1048576} { "{0,7:0.0}K" -f ($NumBytes / 1024) ; break }
{$_ -lt 1073741824} { "{0,7:0.0}M" -f ($NumBytes / 1048576) ; break }
default { "{0,7:0.0}G" -f ($NumBytes / 1073741824); break }
}
}
人们通常会弄错这些转换。例如,使用 1024 * 1000 来获取兆字节(将 1K 的 base10 值与 1K 的 base2 值混合)并遵循相同的逻辑来获取 GB 和 TB 是一个常见的错误。
这是我在问题中提出的其他部分,根据需要更改 $src
/ $dst
(D:\VMs
是我保留很多虚拟机的地方) .我已经设置了所有 CreationTime、LastWriteTime、LastAccessTime,以便具有 zero-size 个文件的备份位置是源的完美表示。因为我想将其用于存档目的,所以我最终将其压缩并在压缩文件名称中包含了一个 date-time 戳记。
# Copy-FolderZeroSizeFiles
$src = "D:\VMs"
$dst = "D:\VMs-Backup"
function ConvertTo-FriendlySize($NumBytes) {
switch ($NumBytes) {
{$_ -lt 1024} { "{0:0.0}B" -f ($NumBytes) ; break } # Change {0: to {0,7: to align to 7 characters
{$_ -lt 1048576} { "{0:0.0}K" -f ($NumBytes / 1024) ; break }
{$_ -lt 1073741824} { "{0:0.0}M" -f ($NumBytes / 1048576) ; break }
default { "{0:0.0}G" -f ($NumBytes / 1073741824); break }
}
}
function Copy-FolderZeroSizeFiles($FolderPath, $DestinationPath) {
Push-Location $FolderPath
if (!(Test-Path $DestinationPath)) { New-Item $DestinationPath -Type Directory }
foreach ($item in Get-ChildItem $FolderPath -Recurse -Force) {
$relPath = Resolve-Path $item.FullName -Relative
if ($item.Attributes -match 'Directory') {
$new = New-Item "$DestinationPath$relPath" -ItemType Directory -Force -EA Silent
}
else {
$fileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($item.Name)
$fileExt = [System.IO.Path]::GetExtension($item.Name)
$fileSize = ConvertTo-FriendlySize($item.Length)
$new = New-Item "$DestinationPath$(Split-Path $relPath)$fileBaseName ($fileSize)$fileExt" -ItemType File
}
"$($new.Name) : creation $($item.CreationTime), lastwrite $($item.CreationTime), lastaccess $($item.LastAccessTime)"
$new.CreationTime = $item.CreationTime
$new.LastWriteTime = $item.LastWriteTime
$new.LastAccessTime = $item.LastAccessTime
$new.Attributes = $item.Attributes # Must this after setting creation/write/access times or get error on Read-Only files
}
Pop-Location
}
Copy-FolderZeroSizeFiles $src $dst
$dateTime = Get-Date -Format "yyyyMMdd_HHmm"
$zipName = "$([System.IO.Path]::GetPathRoot($dst))$([System.IO.Path]::GetFileName($dst))_$dateTime.zip"
Add-Type -AssemblyName System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::CreateFromDirectory($dst, $zipName)
我想创建一组文件夹的 0 文件大小的镜像,但是虽然 robocopy 非常好,但它并没有保存我想要的所有信息:
robocopy D:\documents E:\backups\documents_$(Get-Date -format "yyyyMMdd_HHmm")\ /mir /create
/create
开关使重复文件夹中的每个文件都具有零大小,这很好,但我希望重复文件夹中的每个文件都将 [size]
附加到末尾大小以 KB 或 MB 或 GB 为单位的名称,以及每个文件的创建/上次修改时间以与原始文件完全匹配。这样,我将拥有可存档文件夹的零大小副本,但其中包含该目录中文件的所有相关信息,显示每个文件的大小以及确切的创建/上次修改时间。
是否有好的/简单的方法来遍历 PowerShell 中的树,并为每个项目创建一个包含所有相关信息的零大小文件?
这将是使用我在评论中提到的方法实现复制命令的一种方法。这应该会给你一些灵感。我不打算像我那样花那么多时间在上面,但是我 运行 它在几个目录上发现了一些问题并调试了我遇到的每个问题。这是一个非常可靠的例子。
function Copy-FolderZeroSizeFiles {
[CmdletBinding()]
param( [Parameter(Mandatory)] [string] $FolderPath,
[Parameter(Mandatory)] [string] $DestinationPath )
$dest = New-Item $DestinationPath -Type Directory -Force
Push-Location -LiteralPath $FolderPath
try {
foreach ($item in Get-ChildItem '.' -Recurse) {
$relPath = Resolve-Path -LiteralPath $item -Relative
$type = if ($item.Attributes -match 'Directory')
{ 'Directory' }
else { 'File' }
$destItem = New-Item "$dest$relPath" -Type $type -Force
$destItem.Attributes = $item.Attributes
$destItem.LastWriteTime = $item.LastWriteTime
}
} finally {
Pop-Location
}
}
注意:上面的实现很简单,将目录之外的任何内容都表示为文件。这意味着符号链接等。将是没有信息的文件,它们将链接到什么。
这里有一个函数可以将字节数转换为 N.N B/K/M/G 格式。要获得更多小数位,只需将 0
添加到格式字符串的末尾即可。
function ConvertTo-FriendlySize($NumBytes) {
switch ($NumBytes) {
{$_ -lt 1024} { "{0,7:0.0}B" -f ($NumBytes) ; break }
{$_ -lt 1048576} { "{0,7:0.0}K" -f ($NumBytes / 1024) ; break }
{$_ -lt 1073741824} { "{0,7:0.0}M" -f ($NumBytes / 1048576) ; break }
default { "{0,7:0.0}G" -f ($NumBytes / 1073741824); break }
}
}
人们通常会弄错这些转换。例如,使用 1024 * 1000 来获取兆字节(将 1K 的 base10 值与 1K 的 base2 值混合)并遵循相同的逻辑来获取 GB 和 TB 是一个常见的错误。
这是我在问题中提出的其他部分,根据需要更改 $src
/ $dst
(D:\VMs
是我保留很多虚拟机的地方) .我已经设置了所有 CreationTime、LastWriteTime、LastAccessTime,以便具有 zero-size 个文件的备份位置是源的完美表示。因为我想将其用于存档目的,所以我最终将其压缩并在压缩文件名称中包含了一个 date-time 戳记。
# Copy-FolderZeroSizeFiles
$src = "D:\VMs"
$dst = "D:\VMs-Backup"
function ConvertTo-FriendlySize($NumBytes) {
switch ($NumBytes) {
{$_ -lt 1024} { "{0:0.0}B" -f ($NumBytes) ; break } # Change {0: to {0,7: to align to 7 characters
{$_ -lt 1048576} { "{0:0.0}K" -f ($NumBytes / 1024) ; break }
{$_ -lt 1073741824} { "{0:0.0}M" -f ($NumBytes / 1048576) ; break }
default { "{0:0.0}G" -f ($NumBytes / 1073741824); break }
}
}
function Copy-FolderZeroSizeFiles($FolderPath, $DestinationPath) {
Push-Location $FolderPath
if (!(Test-Path $DestinationPath)) { New-Item $DestinationPath -Type Directory }
foreach ($item in Get-ChildItem $FolderPath -Recurse -Force) {
$relPath = Resolve-Path $item.FullName -Relative
if ($item.Attributes -match 'Directory') {
$new = New-Item "$DestinationPath$relPath" -ItemType Directory -Force -EA Silent
}
else {
$fileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($item.Name)
$fileExt = [System.IO.Path]::GetExtension($item.Name)
$fileSize = ConvertTo-FriendlySize($item.Length)
$new = New-Item "$DestinationPath$(Split-Path $relPath)$fileBaseName ($fileSize)$fileExt" -ItemType File
}
"$($new.Name) : creation $($item.CreationTime), lastwrite $($item.CreationTime), lastaccess $($item.LastAccessTime)"
$new.CreationTime = $item.CreationTime
$new.LastWriteTime = $item.LastWriteTime
$new.LastAccessTime = $item.LastAccessTime
$new.Attributes = $item.Attributes # Must this after setting creation/write/access times or get error on Read-Only files
}
Pop-Location
}
Copy-FolderZeroSizeFiles $src $dst
$dateTime = Get-Date -Format "yyyyMMdd_HHmm"
$zipName = "$([System.IO.Path]::GetPathRoot($dst))$([System.IO.Path]::GetFileName($dst))_$dateTime.zip"
Add-Type -AssemblyName System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::CreateFromDirectory($dst, $zipName)