在 PowerShell 中创建一个临时目录?
Create a temporary directory in PowerShell?
PowerShell 5 introduces the New-TemporaryFile
cmdlet,好用。我怎样才能做同样的事情而不是文件创建目录?有 New-TemporaryDirectory
cmdlet 吗?
我认为可以通过使用目录名称的 GUID 来完成而无需循环:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
最初尝试使用 GetRandomFileName
这是我的 this C# solution 端口:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
$name = [System.IO.Path]::GetRandomFileName()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
碰撞可能性分析
GetRandomFileName
return 临时文件夹中已存在的名称的可能性有多大?
- 文件名 return 格式为
XXXXXXXX.XXX
,其中 X 可以是小写字母或数字。
- 这给了我们 36^11 种组合,以位为单位约为 2^56
- 调用 birthday paradox,一旦文件夹中的项目达到 2^28 左右,即大约 3.6 亿,我们预计会发生冲突
- NTFS supports about 2^32 items in a folder,因此可以使用
GetRandomFileName
进行碰撞
NewGuid
另一方面 can be one of 2^122 possibilities,几乎不可能发生碰撞。
.NET 已经 [System.IO.Path]::GetTempFileName()
很久了;您可以使用它来生成一个文件(并捕获名称),然后在删除该文件后创建一个具有相同名称的文件夹。
$tempfile = [System.IO.Path]::GetTempFileName();
remove-item $tempfile;
new-item -type directory -path $tempfile;
这是我的尝试:
function New-TemporaryDirectory {
$path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
#if/while path already exists, generate a new path
while(Test-Path $path)) {
$path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
}
#create directory with generated path
New-Item -ItemType Directory -Path $path
}
如果可能的话,我喜欢一个衬垫。 @alroc .NET 也有 [System.Guid]::NewGuid()
$temp = [System.Guid]::NewGuid();new-item -type directory -Path d:$temp
Directory: D:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 1/2/2016 11:47 AM 9f4ef43a-a72a-4d54-9ba4-87a926906948
我也喜欢 one-liners,我在这里请求投反对票。我只要求你把我自己对此模糊的负面感受写成文字。
New-TemporaryFile | %{ rm $_; mkdir $_ }
根据您的纯粹主义者类型,您可以%{ mkdir $_-d }
,留下占位符以避免冲突。
而且站在Join-Path $env:TEMP $(New-Guid) | %{ mkdir $_ }
上也是有道理的。
从 Michael Kropat 的回答扩展:
Function New-TemporaryDirectory {
$tempDirectoryBase = [System.IO.Path]::GetTempPath();
$newTempDirPath = [String]::Empty;
Do {
[string] $name = [System.Guid]::NewGuid();
$newTempDirPath = (Join-Path $tempDirectoryBase $name);
} While (Test-Path $newTempDirPath);
New-Item -ItemType Directory -Path $newTempDirPath;
Return $newTempDirPath;
}
这应该可以消除任何碰撞问题。
如果您想要保证既无竞争又无碰撞的循环解决方案,那么这里是:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
do {
$name = [System.IO.Path]::GetRandomFileName()
$item = New-Item -Path $parent -Name $name -ItemType "directory" -ErrorAction SilentlyContinue
} while (-not $item)
return $item.FullName
}
根据中的分析,绝大多数时候,这只会通过循环一次。它很少会通过两次。几乎永远不会通过三次。
这是 user4317867 的 的变体。我在用户的 Windows“Temp”文件夹中创建了一个新目录,并将临时文件夹路径作为变量提供 ($tempFolderPath
):
$tempFolderPath = Join-Path $Env:Temp $(New-Guid)
New-Item -Type Directory -Path $tempFolderPath | Out-Null
下面是可用作单行的相同脚本:
$tempFolderPath = Join-Path $Env:Temp $(New-Guid); New-Item -Type Directory -Path $tempFolderPath | Out-Null
完全限定的临时文件夹路径 ($tempFolderPath
) 如下所示:
C:\Users\MassDotNet\AppData\Local\Tempae2dbc4-c709-475b-b762-72108b8ecb9f
如果你愿意,你可以非常花哨,像这样调用 Windows API 函数 GetTempPathA()
:
# DWORD GetTempPathA(
# DWORD nBufferLength,
# LPSTR lpBuffer
# );
$getTempPath = @"
using System;
using System.Runtime.InteropServices;
using System.Text;
public class getTempPath {
[DllImport("KERNEL32.DLL", EntryPoint = "GetTempPathA")]
public static extern uint GetTempPath(uint nBufferLength, [Out] StringBuilder lpBuffer);
}
"@
Add-Type $getTempPath
$str = [System.Text.StringBuilder]::new()
$MAX_PATH = 260
$catch_res = [getTempPath]::GetTempPath($MAX_PATH, $str)
Write-Host $str.ToString() #echos temp path to STDOUT
# ... continue your code here and create sub folders as you wish ...
PowerShell 5 introduces the New-TemporaryFile
cmdlet,好用。我怎样才能做同样的事情而不是文件创建目录?有 New-TemporaryDirectory
cmdlet 吗?
我认为可以通过使用目录名称的 GUID 来完成而无需循环:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
最初尝试使用 GetRandomFileName
这是我的 this C# solution 端口:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
$name = [System.IO.Path]::GetRandomFileName()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
碰撞可能性分析
GetRandomFileName
return 临时文件夹中已存在的名称的可能性有多大?
- 文件名 return 格式为
XXXXXXXX.XXX
,其中 X 可以是小写字母或数字。 - 这给了我们 36^11 种组合,以位为单位约为 2^56
- 调用 birthday paradox,一旦文件夹中的项目达到 2^28 左右,即大约 3.6 亿,我们预计会发生冲突
- NTFS supports about 2^32 items in a folder,因此可以使用
GetRandomFileName
进行碰撞
NewGuid
另一方面 can be one of 2^122 possibilities,几乎不可能发生碰撞。
.NET 已经 [System.IO.Path]::GetTempFileName()
很久了;您可以使用它来生成一个文件(并捕获名称),然后在删除该文件后创建一个具有相同名称的文件夹。
$tempfile = [System.IO.Path]::GetTempFileName();
remove-item $tempfile;
new-item -type directory -path $tempfile;
这是我的尝试:
function New-TemporaryDirectory {
$path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
#if/while path already exists, generate a new path
while(Test-Path $path)) {
$path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
}
#create directory with generated path
New-Item -ItemType Directory -Path $path
}
如果可能的话,我喜欢一个衬垫。 @alroc .NET 也有 [System.Guid]::NewGuid()
$temp = [System.Guid]::NewGuid();new-item -type directory -Path d:$temp
Directory: D:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 1/2/2016 11:47 AM 9f4ef43a-a72a-4d54-9ba4-87a926906948
我也喜欢 one-liners,我在这里请求投反对票。我只要求你把我自己对此模糊的负面感受写成文字。
New-TemporaryFile | %{ rm $_; mkdir $_ }
根据您的纯粹主义者类型,您可以%{ mkdir $_-d }
,留下占位符以避免冲突。
而且站在Join-Path $env:TEMP $(New-Guid) | %{ mkdir $_ }
上也是有道理的。
从 Michael Kropat 的回答扩展:
Function New-TemporaryDirectory {
$tempDirectoryBase = [System.IO.Path]::GetTempPath();
$newTempDirPath = [String]::Empty;
Do {
[string] $name = [System.Guid]::NewGuid();
$newTempDirPath = (Join-Path $tempDirectoryBase $name);
} While (Test-Path $newTempDirPath);
New-Item -ItemType Directory -Path $newTempDirPath;
Return $newTempDirPath;
}
这应该可以消除任何碰撞问题。
如果您想要保证既无竞争又无碰撞的循环解决方案,那么这里是:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
do {
$name = [System.IO.Path]::GetRandomFileName()
$item = New-Item -Path $parent -Name $name -ItemType "directory" -ErrorAction SilentlyContinue
} while (-not $item)
return $item.FullName
}
根据
这是 user4317867 的 $tempFolderPath
):
$tempFolderPath = Join-Path $Env:Temp $(New-Guid)
New-Item -Type Directory -Path $tempFolderPath | Out-Null
下面是可用作单行的相同脚本:
$tempFolderPath = Join-Path $Env:Temp $(New-Guid); New-Item -Type Directory -Path $tempFolderPath | Out-Null
完全限定的临时文件夹路径 ($tempFolderPath
) 如下所示:
C:\Users\MassDotNet\AppData\Local\Tempae2dbc4-c709-475b-b762-72108b8ecb9f
如果你愿意,你可以非常花哨,像这样调用 Windows API 函数 GetTempPathA()
:
# DWORD GetTempPathA(
# DWORD nBufferLength,
# LPSTR lpBuffer
# );
$getTempPath = @"
using System;
using System.Runtime.InteropServices;
using System.Text;
public class getTempPath {
[DllImport("KERNEL32.DLL", EntryPoint = "GetTempPathA")]
public static extern uint GetTempPath(uint nBufferLength, [Out] StringBuilder lpBuffer);
}
"@
Add-Type $getTempPath
$str = [System.Text.StringBuilder]::new()
$MAX_PATH = 260
$catch_res = [getTempPath]::GetTempPath($MAX_PATH, $str)
Write-Host $str.ToString() #echos temp path to STDOUT
# ... continue your code here and create sub folders as you wish ...