Как искать уникальную последовательность в двоичных данных?

Я пытаюсь прочитать двоичный файл с заголовком. Я знаю, что определенная информация сохраняется после уникальной последовательности 02 06 08 22 02 02 08 00. Как мне найти позицию такой уникальной последовательности?

я могу использовать

String StreamReadAsText (поток ScriptObject, числовая кодировка, числовое значение)

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

Кроме того, как мне сравнить результат StreamReadAsText(), если вывод не является фактическим текстом (между 00 и 1F в таблице Ascii)?

Затем, как мне прочитать двоичный файл как int8 (того же размера, что и символ в строке). Например, прочитать 02, затем 06, затем 08 и т. д.

Любая помощь приветствуется и приветствуется.

С уважением,

Роджер


person Roger    schedule 15.06.2017    source источник
comment
Связанный (но не повторяющийся): stackoverflow.com/q/34834197/1302888   -  person BmyGuest    schedule 15.06.2017


Ответы (2)


Вы уже на правильном пути, читая файл с командами потоковой передачи. Однако зачем вам читать поток как текст? Вы можете прочитать поток как любой (поддерживаемый) номер, используя объект tagGroup в качестве прокси с TagGroupReadTagDataFromStream().

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

Справка F1

 Object stream = NewStreamFromBuffer( NewMemoryBuffer( 256 ) )
 TagGroup tg = NewTagGroup();

 Number stream_byte_order = 1; // 1 == bigendian, 2 == littleendian
 Number v_uint32_0, v_uint32_1, v_sint32_0, v_uint16_0, v_uint16_1

 // Create the tags and initialize with default values
 tg.TagGroupSetTagAsUInt32( "UInt32_0", 0 )
 tg.TagGroupSetTagAsUInt32( "UInt32_1", 0 )
 tg.TagGroupSetTagAsLong( "SInt32_0", 0 )
 tg.TagGroupSetTagAsUInt16( "UInt16_0", 0 )
 tg.TagGroupSetTagAsUInt16( "UInt16_1", 0 )

 // Stream the data into the tags   
 TagGroupReadTagDataFromStream( tg, "UInt32_0", stream, stream_byte_order );
 TagGroupReadTagDataFromStream( tg, "UInt32_1", stream, stream_byte_order );
 TagGroupReadTagDataFromStream( tg, "SInt32_0", stream, stream_byte_order );
 TagGroupReadTagDataFromStream( tg, "UInt16_0", stream, stream_byte_order );
 TagGroupReadTagDataFromStream( tg, "UInt16_1", stream, stream_byte_order );

// Show the taggroup, if you want
// tg.TagGroupOpenBrowserWindow("AuxTags",0)

 // Get the data from the tags
 tg.TagGroupGetTagAsUInt32( "UInt32_0", v_uint32_0 )
 tg.TagGroupGetTagAsUInt32( "UInt32_1", v_uint32_1 )
 tg.TagGroupGetTagAsLong( "Sint32_0", v_sint32_0 )
 tg.TagGroupGetTagAsUInt16( "UInt16_0", v_uint16_0 )
 tg.TagGroupGetTagAsUInt16( "UInt16_1", v_uint16_1 )

На сайте уже есть сообщение о поиске шаблона в потоке: Найти изображение шаблона (двоичный файл) Это показывает, как вы будете использовать поток для просмотра изображения, но, конечно, вы можете использовать файловый поток напрямую.


В качестве альтернативы вы можете прочитать весь массив из потока с помощью ImageReadImageDataFromStream, предварительно подготовив подходящий образ. Затем вы можете использовать изображения для поиска местоположения. Это будет пример:

// Example of reading the first X bytes of a file
// as uInt16 data

image ReadHeaderAsUint16( string filepath, number nBytes )
{
    number kEndianness = 0 // Default byte order of the current platform
    if ( !DoesFileExist( filePath ) ) 
        Throw( "File '" + filePath + "' not found." )
    number fileID = OpenFileForReading( filePath )
    object fStream = NewStreamFromFileReference( fileID, 1 )
    if ( nBytes > fStream.StreamGetSize() ) 
        Throw( "File '" + filePath + "' has less than " + nBytes + "bytes." )

    image buff := IntegerImage( "Header", 2, 0, nBytes/2 )  // UINT16 array of suitable size
    ImageReadImageDataFromStream( buff, fStream, kEndianness )
    return buff 
}

number FindSignature( image header, image search )
{
    // 1D images only
    if (        ( header.ImageGetNumDimensions() != 1 ) \
            ||  ( search.ImageGetNumDimensions() != 1 ) )
        Throw( "Only 1D images supported" )

    number sx = search.ImageGetDimensionSize( 0 ) 
    number hx = header.ImageGetDimensionSize( 0 )
    if ( hx < sx )
        return -1

    // Create a mask of possible start locations
    number startV = search.getPixel( 0, 0 )
    image mask = (header == startV) ? 1 : 0

    // Search all the occurances from the first
    number mx, my
    while( max( mask, mx, my ) )
    {
        if ( 0 == sum( header[0,mx,1,mx+sx] - search ) )
            return mx
        else
            mask.SetPixel( mx, 0, 0)
    }
    return -1
}

// Example
// 1) Load file header as image (up to the size you want )
string path = GetApplicationDirectory( "open_save", 0 )
number maxHeaderSize = 200
if ( !OpenDialog( NULL, "Select file to open", path, path ) ) Exit(0)
image headerImg := ReadHeaderAsUint16( path, maxHeaderSize  )
headerImg.ShowImage()

// 2) define search-header as image
image search := [8]: { 02, 06, 08, 22, 02, 02, 08, 00 }
// MatrixPrint( search )

// 3) search for it in the header
number foundAt = FindSignature( headerImg, search )
if ( -1 == foundAt ) 
    Throw( "The file header does not contain the search pattern." )
else
    OKDialog( "Found the search pattern at offset: " + foundAt * 16 + "bytes" )
person BmyGuest    schedule 15.06.2017
comment
Спасибо за ответ. - person Roger; 17.06.2017
comment
Спасибо за ответ. Я не очень хорошо разбираюсь в тегах. Но я могу читать поток по тегам Int32, Int16 и Double. Насколько я понимаю, Int32 имеет длину как 02 06 08 22, а Int16 имеет длину как 02 06. Если поток приходит как 00 02 06 08, то он пропустит эту последовательность, прочитав Int16. Поэтому мне нужно будет читать как Int8 (я даже не знаю, называется ли это так). Тогда длина должна быть равна 02. Таким образом, я буду уверен, что он не пропустит правильную последовательность заголовков. Проблема сейчас в том, что я не могу читать Int8. Только поток чтения, поскольку текст имеет такую ​​длину, но я не могу сравнить ASCII - person Roger; 17.06.2017
comment
@Roger Вы можете прочитать данные как изображение UInt8 - IntegerImage (, 1,0,...) - или изображение Int8 - IntegerImage (, 1, 1, ...). Или вы можете искать с двумя проходами (один со смещением 1 байт на шаг). К сожалению, сейчас я не знаю о командах типа GetTagAsUInt8 или Int8. - person BmyGuest; 17.06.2017
comment
Отличная идея!! Я читаю заголовок как IntegerImage (, 1, 0, nBytes). Используйте функцию FindSignature, чтобы найти последовательность (на этот раз это изображение размером 8 пикселей). Я тестировал последовательность {2,6,8,34,2,2,8,0}, она отлично работает. Он нашел положение такой последовательности!! он работал правильно и для последовательности {112,0,7,5,1,96,0,34,7}. Но когда я проверил его с последовательностью {0,7,5,1,96,0,34,7}, он не вернулся с правильной позицией. Мне интересно, должна ли эта последовательность для поиска начинаться с ненулевого значения? Кроме того, могу ли я таким же образом искать подстроку из длинной строки? - person Roger; 18.06.2017
comment
@Roger: Вы можете использовать такие вещи для строк, но для поиска подстрок я бы предпочел использовать предисловие к команде «найти». - person BmyGuest; 18.06.2017

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

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

person Malcolm McLean    schedule 15.06.2017
comment
К сожалению, в языке DM-скриптов такой функции нет. Однако идея, которую я изложил ниже, не сильно отличается в принципе. - person BmyGuest; 15.06.2017