Извлеките первые 50 байтов файла, используя Powershell - PullRequest
1 голос
/ 20 марта 2020

Я пишу скрипт в powershell для извлечения файловой информации с серверов и записи данных в csv-файл для просмотра. У меня большая часть сценария работает очень хорошо, однако моя первоначальная попытка извлечь первую строку каждого файла привела к неожиданным результатам из-за того, что некоторые файлы не имели / cr и, следовательно, печатали все содержимое файла.

I Я хочу извлечь первые 50 байтов каждого файла в CSV, но -TotalCount читает первую строку, и я читал в. NET [IO.File] и [System.Text.Encoding], но не могу найти работающий метод .

Мой код в настоящее время:


    Select-Object FullName,Name,Directory,@{n="Owner";ex={(Get-ACL $_.Fullname).Owner}},CreationTimeUtc,LastAccessTimeUtc,LastWriteTimeUtc,@{n='Size(MB)';ex={[math]::Round($_.length/1MB, 2)}},
    @{n='MD5';ex={(Get-FileHash $_.fullname).hash}},@{n="Content(UTF8)";ex={(Get-Content $_.fullname -AsByteStream -Raw -TotalCount 50)}} |

    Export-Csv c:\temp\$fn-filelisting.csv -NoTypeInformation

Кажется, что PS использовал байты в качестве выбора для -TotalCount, но с тех пор изменил его, чтобы читать по строкам.

Необходимо использовать PS из-за системных ограничений, поэтому любые идеи будут с благодарностью.

Ответы [ 2 ]

1 голос
/ 20 марта 2020

Это вернет байтовый массив. В powershell 5 это -encoding byte.

get-content file -AsByteStream -totalcount 50

Использование powershell 5 и получение строки:

$a = get-content file -encoding byte -totalcount 50
-join [char[]]$a

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0 голосов
/ 20 марта 2020

Вы хотите прочитать первые 50 символов , а не байтов . Поэтому используйте экземпляр System.IO.StreamReader, поскольку Get-Content не поддерживает чтение заданного числа символов , только строк :

$charBuf = [char[]]::new(50) # buffer to read into
$textStream = [IO.StreamReader] $_.FullName # create the stream reader
$charCount = $textStream.Read($charBuf, 0, $charBuf.Length) # read into buffer
$textStream.Close() # close the stream
-join $charBuf[0..($charCount-1)] # output the chars. read as a string

Что вы попробовали:

Get-Content $_.fullname -AsByteStream -Raw -TotalCount 50

-AsByteStream поддерживается только в PowerShell [Core] 6+ , где он заменил -Encoding Byte.

Это было печальное переломное изменение: см. этот выпуск GitHub и этот комментарий .

In Windows Необходимо использовать PowerShell , -Encoding Byte.

-TotalCount эффективно при выводе только указанного количество байтов при объединении с -AsByteStream / -Encoding Byte.

Однако параметры -Raw и -TotalCount являются взаимоисключающими .

Пока Get-Content $_.fullname -Encoding Byte -TotalCount 50 / Get-Content $_.fullname -AsByteStream -TotalCount 50 поэтому работает в PowerShell [Core] / Windows PowerShell, он выводит байты один за другим , что без необходимости медленно , если вы хотите собрать все байты в памяти .

Следовательно, добавьте -ReadCount 50, чтобы сразу прочитать 50 байтов и вывести их в виде [byte[] массива :

# Read 50 bytes at once and utput a [byte[]] array

# Windows PowerShell:
Get-Content $_.fullname -Encoding Byte -TotalCount 50 -ReadCount 50

# PowerShell [Core] 6+
Get-Content $_.fullname -AsByteStream -TotalCount 50 -ReadCount 50

В PowerShell [Core] 7 доступна оптимизация: -ReadCount 0 - это ярлык для запроса того, чтобы любое количество -TotalCount запросов было прочитано в одном массиве :

# PowerShell 7
Get-Content $_.fullname -Encoding Byte -TotalCount 50 -ReadCount 0

Хотя приведенное выше является довольно эффективным способом извлечения первых 50 байтов , преобразования их в символов :

  • громоздко, потому что вам нужно знать кодировку исходного кода и преобразовывать байты в текст на его основе.

  • , но, что более важно, может привести к чтению неполный символ с входными файлами, использующими кодировки переменной длины , особенно UTF-8, если граница в 50 байт попадает в середину кратных байтов которые составляют один символ, который в UTF-8 применяется к любым символам вне диапазона ASCII, таким как é.

Начиная с v7.0, Get-Content не делает t предлагает способ чтения указанного числа символов , поэтому тип. NET System.IO.StreamReader используется в приведенном выше решении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...