Не удается заставить Powershell назначить массив определенного размера

Итак, я пытаюсь создать сценарий powershell, который измеряет скорость GPG с использованием файлов разного размера. Конкретная часть, которая вызывает у меня проблемы, заключается в следующем:

1 $temppath="$($env:Temp)\"
...
4 Measure-Command {$bytes= 10000MB
5 [System.Security.Cryptography.RNGCryptoServiceProvider]$rng = New- Object.System.Security.Cryptography.RNGCryptoServiceProvider
6 $rndbytes = New-Object byte[] $bytes
7 [System.Io.File]::WriteAllBytes("$($temppath)\test.txt", $rndbytes)} | Select-Object -OutVariable gentime | Out-Null; 

При $bytes >~ 1.5GB (использую для проверки 10000MB) получаю ошибку, которая, если я правильно понимаю, что происходит, соответствует тому, что байтовый массив индексируется переменной типа int32. Конкретная ошибка такова:

New-Object : Cannot convert argument "0", with value: "10485760000", for "Byte[]" to type "System.Int32": "Cannot convert value "10485760000" to type "System.Int32". Error: "Value was either too large or too small for an Int32.""
At line:6 char:13
+ $rndbytes = New-Object byte[] $bytes
    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

Есть ли способ заставить powershell индексировать $rndbytes при создании объекта с индексом типа int64 или uint64? Если это не проблема, я бы хотел, чтобы мне показали и объяснили, что именно идет не так.

Обратите внимание, если вы используете, например, $bytes=1000MB (или пишете $bytes=1GB), код работает отлично. Я подозреваю, что врежусь в стену на $bytes.index > 2^31 -1 или около того.

Спасибо за помощь~!!


person Shinaolord    schedule 08.02.2021    source источник
comment
Нет, длина массива не может превышать [int]::MaxValue. Вывод партиями   -  person Mathias R. Jessen    schedule 09.02.2021
comment
Дэн, это несчастье. Так что просто создайте несколько массивов и обработайте их партиями?   -  person Shinaolord    schedule 09.02.2021
comment
Создайте небольшой буферный массив (например, 4 КБ), а затем записывайте куски этого размера, пока не достигнете желаемого размера файла.   -  person Mathias R. Jessen    schedule 09.02.2021
comment
Пришло время узнать, как это сделать в powershell. Вы случайно не знаете, перезаписывает ли [System.Io.File]::WriteAllBytes данные или добавляет?   -  person Shinaolord    schedule 09.02.2021


Ответы (1)


Как упоминалось в комментариях, массивы в .NET не могут превышать длину 2 ^ 31-1 элементов, потому что значение индекса, используемое для массивов, равно [int], максимальное значение которого равно 2 ^ 31-1.

На самом деле это не проблема, потому что буферизация 2 миллиардов элементов в памяти в любом случае ужасно неэффективна — если вам нужны 10 ГБ случайных данных, вы вместо этого создаете и записываете их на диск фрагментами. :

# Set file size
$intendedSize = 10GB

# Create output buffer
$buffer = [byte[]]::new(4KB)

# Create RNG
$rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::Create()

# Create temp file, open writable filestrem
$tempFile = [System.IO.Path]::GetTempFileName() |Get-Item
$fileStream = $tempFile.OpenWrite()

do {
    # Fill buffer, write to disk, rinse-repeat
    $rng.GetBytes($buffer)
    $fileStream.Write($buffer, 0, $buffer.Length)
} while($fileStream.Length -lt $intendedSize)

# Dispose if filestream + RNG
$fileStream.Dispose()
$rng.Dispose()

4KB обычно является хорошим общим размером буфера в Windows, поскольку 4 КБ является размером кластера по умолчанию для томов NTFS, а большинство современных процессоров имеют размер кэша L1, кратный 4 КБ.

person Mathias R. Jessen    schedule 09.02.2021
comment
В чем разница между $rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::Create() и $rng = new [System.Security.Cryptography.RNGCryptoServiceProvider]() и [System.Security.Cryptography.RNGCryptoServiceProvider]$rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider ? Честно говоря, я очень новичок в Powershell, до этого я действительно использовал его только для самых простых вещей. Кроме того, Powershell очень похож на C#? Похоже, что это так, и если это так, я мог бы просто научиться использовать C # как способ дополнить свои способности Powershell. - person Shinaolord; 09.02.2021
comment
@Shinaolord $rng = new [TypeName]() не является допустимым PowerShell. New-Object TypeName по сути то же самое, что и [TypeName]::new(), но поскольку RNGCryptoServiceProvider предоставляет статический метод Create(), автор, вероятно, хотел, чтобы пользователи использовали его, поэтому я использовал его :-) PowerShell использует ту же базовую библиотеку базовых классов, что и C# (.NET) и некоторые элементы синтаксиса сильно заимствованы из C#, но это два разных языка. - person Mathias R. Jessen; 09.02.2021
comment
Я просто не видел метода ::Create(), когда просматривал страницу документации Microsoft для RNGCryptoServiceProvider, поэтому я не был уверен (: я действительно знаю только Mathematica и в меньшей степени Matlab, и баловался C++ и Python, но ни в коем случае я не знаю эти языки.Спасибо за помощь! - person Shinaolord; 09.02.2021