PowerShell ищут сценарий, который игнорирует двоичные файлы

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

что-то как:

Type ti = typeof(IYourInterface);
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
    foreach (Type t in asm.GetTypes()) {
        if (ti.IsAssignableFrom(t)) {
            // here's your type in t
        }
    }
}
25
задан Community 23 May 2017 в 11:46
поделиться

2 ответа

В Windows расширения файлов обычно достаточно хороши:

# all C# and related files (projects, source control metadata, etc)
dir -r -fil *.cs* | ss foo

# exclude the binary types most likely to pollute your development workspace
dir -r -exclude *exe, *dll, *pdb | ss foo

# stick the first three lines in your $profile (refining them over time)
$bins = new-list string
$bins.AddRange( [string[]]@("exe", "dll", "pdb", "png", "mdf", "docx") )
function IsBin([System.IO.FileInfo]$item) { !$bins.Contains($item.extension.ToLower()) }
dir -r | ? { !IsBin($_) } | ss foo

Но, конечно, расширения файлов не идеальны. Никто не любит печатать длинные списки, и многие файлы в любом случае имеют неправильные имена.

Я не думаю, что Unix имеет какие-либо специальные двоичные или текстовые индикаторы в файловой системе. (Что ж, VMS сделала, но я сомневаюсь, что это источник ваших привычек grep.) Я посмотрел на реализацию Grep -I, и, очевидно, это просто эвристика быстрого и грязного, основанная на первом фрагменте файла. Оказывается, это стратегия, с которой у меня небольшой опыт . Итак, вот мой совет по выбору эвристической функции, подходящей для текстовых файлов Windows:

  • Проверьте как минимум 1 КБ файла. Многие форматы файлов начинаются с заголовка, который выглядит как текст, но вскоре после этого ваш синтаксический анализатор перестанет работать. Как работает современное оборудование, чтение 50 байт имеет примерно те же накладные расходы ввода-вывода, что и чтение 4 КБ.
  • Если вас интересует только прямой ASCII, выходите, как только увидите что-то за пределами диапазона символов [31-127 плюс CR и LF ]. Вы можете случайно исключить какой-нибудь хитрый ASCII-код, но попытка отделить эти случаи от двоичного мусора нетривиальна.
  • Если вы хотите обрабатывать текст Unicode, позвольте библиотекам MS выполнять грязную работу. Это сложнее, чем ты думаешь. Из Powershell вы можете легко получить доступ к интерфейсу IMultiLang2 (COM) или к статическому методу Encoding.GetEncoding (.NET). Конечно, они пока только догадываются. Комментарии Раймонда об алгоритме обнаружения блокнота (и ссылка на Майкла Каплана) заслуживают внимания, прежде чем точно решить, как вы хотите смешивать и соответствуют библиотекам, предоставляемым платформой.
  • Если результат важен - т. е. ошибка приведет к чему-то похуже, чем просто загромождает вашу консоль grep - тогда не бойтесь жестко закодировать некоторые расширения файлов ради точность. Например, файлы * .PDF иногда содержат несколько КБ текста впереди, несмотря на то, что они являются двоичным форматом, что приводит к печально известным ошибкам, указанным выше. Точно так же, если у вас есть расширение файла, которое может содержать XML или XML-подобные данные, вы можете попробовать схему обнаружения, аналогичную редактору HTML Visual Studio . (SourceSafe 2005 фактически заимствует этот алгоритм для некоторых случаев)
  • Что бы ни случилось, имейте разумный план резервного копирования.

В качестве примера, вот быстрый детектор ASCII:

function IsAscii([System.IO.FileInfo]$item)
{
    begin 
    { 
        $validList = new-list byte
        $validList.AddRange([byte[]] (10,13) )
        $validList.AddRange([byte[]] (31..127) )
    }

    process
    {
        try 
        {
            $reader = $item.Open([System.IO.FileMode]::Open)
            $bytes = new-object byte[] 1024
            $numRead = $reader.Read($bytes, 0, $bytes.Count)

            for($i=0; $i -lt $numRead; ++$i)
            {
                if (!$validList.Contains($bytes[$i]))
                    { return $false }
            }
            $true
        }
        finally
        {
            if ($reader)
                { $reader.Dispose() }
        }
    }
}

Шаблон использования, на который я нацелен, - это где Предложение -object вставлено в конвейер между " Между тем, \ 00 довольно часто встречается в структурированных двоичных файлах (а именно, когда поле фиксированной длины в байтах нуждается в заполнении), так что это отличный простой черный список. VSS 6.0 использовал только эту проверку и сработал нормально.

Кроме того: файлы * .zip - это тот случай, когда проверка на \ 0 более рискованна. В отличие от большинства двоичных файлов, их структурированный блок «заголовок» (нижний колонтитул?) Находится в конце, а не в начале. Предполагая идеальное сжатие энтропии, вероятность отсутствия \ 0 в первых 1 КБ составляет (1-1 / 256) ^ 1024 или около 2%. К счастью, простое сканирование остальной части NTFS-чтения кластера 4 КБ снизит риск до 0,00001% без изменения алгоритма или записи другого особого случая.

Чтобы исключить недопустимый UTF-8, добавьте \ C0-C1 и \ F8 -FD и \ FE-FF (после того, как вы искали возможную спецификацию) в черный список. Очень неполно, поскольку вы фактически не проверяете последовательности, но достаточно близко для ваших целей. Если вы хотите получить что-то более интересное, то пора вызвать одну из библиотек платформы, например IMultiLang2 :: DetectInputCodepage.

Не знаю, почему \ C8 (200 десятичных) находится в списке Grep. Это не слишком длинная кодировка. Например, последовательность \ C8 \ 80 представляет Ȁ (U + 0200). Может быть, что-то специфическое для Unix.

32
ответ дан 28 November 2019 в 21:13
поделиться

Хорошо, после еще нескольких часов исследований я считаю, что нашел свое решение. Я не буду отмечать это как ответ.

Pro Windows Powershell имел очень похожий пример. Я совершенно забыл, что у меня есть этот отличный справочник. Пожалуйста, купите его, если вас интересует Powershell. В нем подробно описаны спецификации Get-Content и Unicode.

Этот ответ на аналогичные вопросы также был очень полезен при идентификации Unicode.

Вот сценарий. Сообщите мне, если вы знаете о каких-либо проблемах.

# The file to be tested
param ($currFile)

# encoding variable
$encoding = ""

# Get the first 1024 bytes from the file
$byteArray = Get-Content -Path $currFile -Encoding Byte -TotalCount 1024

if( ("{0:X}{1:X}{2:X}" -f $byteArray) -eq "EFBBBF" )
{
    # Test for UTF-8 BOM
    $encoding = "UTF-8"
}
elseif( ("{0:X}{1:X}" -f $byteArray) -eq "FFFE" )
{
    # Test for the UTF-16
    $encoding = "UTF-16"
}
elseif( ("{0:X}{1:X}" -f $byteArray) -eq "FEFF" )
{
    # Test for the UTF-16 Big Endian
    $encoding = "UTF-16 BE"
}
elseif( ("{0:X}{1:X}{2:X}{3:X}" -f $byteArray) -eq "FFFE0000" )
{
    # Test for the UTF-32
    $encoding = "UTF-32"
}
elseif( ("{0:X}{1:X}{2:X}{3:X}" -f $byteArray) -eq "0000FEFF" )
{
    # Test for the UTF-32 Big Endian
    $encoding = "UTF-32 BE"
}

if($encoding)
{
    # File is text encoded
    return $false
}

# So now we're done with Text encodings that commonly have '0's
# in their byte steams.  ASCII may have the NUL or '0' code in
# their streams but that's rare apparently.

# Both GNU Grep and Diff use variations of this heuristic

if( $byteArray -contains 0 )
{
    # Test for binary
    return $true
}

# This should be ASCII encoded 
$encoding = "ASCII"

return $false

Сохраните этот сценарий как isBinary.ps1

Этот сценарий исправил все текстовые или двоичные файлы, которые я пробовал.

9
ответ дан 28 November 2019 в 21:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: