Есть ли в C # эквивалент mmap.mmap.rfind?

При просмотре файлов с отображением памяти в C # возникла некоторая трудность в определении того, как выполнять быстрый поиск в файле вперед и назад. Моя цель - переписать следующую функцию на языке, но не удалось найти ничего подобного используемым ниже методам find и rfind. Есть ли в C # способ быстрого поиска файла с отображением памяти с использованием определенной подстроки?

#! /usr/bin/env python3
import mmap
import pathlib


# noinspection PyUnboundLocalVariable
def drop_last_line(path):
    with path.open('r+b') as file:
        with mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as search:
            for next_line in b'\r\n', b'\r', b'\n':
                if search.find(next_line) >= 0:
                    break
            else:
                raise ValueError('cannot find any line delimiters')
            end_1st = search.rfind(next_line)
            end_2nd = search.rfind(next_line, 0, end_1st - 1)
        file.truncate(0 if end_2nd < 0 else end_2nd + len(next_line))

person Noctis Skytower    schedule 23.01.2018    source источник
comment
Не могли бы вы описать, чего вы на самом деле пытаетесь достичь, если у Python отстает в росте? Это просто определение того, содержит ли данный файл определенную строку?   -  person Jamiec    schedule 23.01.2018
comment
@Jamiec Нет, он пытается удалить последнюю строку файла CSV, где каждая строка заканчивается разделителем. Следующие вопросы имеют неприемлемые решения, поскольку они обрабатывают весь файл: (1) Как удалить последнюю строку в текстовом файле? , (2) Как удалить последнюю строку файла file.txt, (3) Эффективный способ удаления строки из текстового файла   -  person Noctis Skytower    schedule 23.01.2018
comment
Суть файлов с отображением в память заключается в том, что после того, как они отображаются, вы можете забыть, что источником является файл, и использовать любую функцию поиска в памяти или алгоритм, который вы хотите.   -  person MickyD    schedule 23.01.2018
comment
Возможно, это будет полезно: docs.microsoft.com/en -us / dotnet / standard / io / memory-mapped-files   -  person Jamiec    schedule 23.01.2018
comment
@MickyD Вы знаете какой-либо способ отобразить в памяти весь файл на C #, а затем обработать его как массив байтов? После просмотра исходного кода для методов find и rfind не кажется, что было бы слишком сложно создать их версию на C #, если бы массив был доступен. Ищу ли я Метод UnmanagedMemoryAccessor.ReadByte (Int64)?   -  person Noctis Skytower    schedule 24.01.2018
comment
Приносим извинения за задержку, см. Ответ ниже   -  person MickyD    schedule 24.01.2018


Ответы (1)


Есть ли в C # способ быстрого поиска файла с отображением памяти с использованием определенной подстроки?

Вы знаете какой-либо способ отобразить в памяти весь файл на C #, а затем обработать его как массив байтов?

Да, довольно легко отобразить весь файл в представление, а затем прочитать его в один массив byte, как показано в следующем коде:

static void Main(string[] args)
{
    var sourceFile=  new FileInfo(@"C:\Users\Micky\Downloads\20180112.zip");
    int length = (int) sourceFile.Length;  // length of target file

    // Create the memory-mapped file.
    using (var mmf = MemoryMappedFile.CreateFromFile(sourceFile.FullName,
                                                     FileMode.Open, 
                                                     "ImgA"))
    {
        var buffer = new byte[length]; // allocate a buffer with the same size as the file

        using (var accessor = mmf.CreateViewAccessor())
        {
            var read=accessor.ReadArray(0, buffer, 0, length); // read the whole thing
        }

        // let's try searching for a known byte sequence.  Change this to suit your file
        var target = new byte[] {71, 213, 62, 204,231};

        var foundAt = IndexOf(buffer, target);

    }
}

Мне не удалось найти какой-либо метод поиска байтов в Marshal или Array, но вы можете использовать этот алгоритм поиска любезно предоставлено из < strong> Social MSDN для начала:

private static int IndexOf2(byte[] input, byte[] pattern)
{
    byte firstByte = pattern[0];
    int  index     = -1;

    if ((index = Array.IndexOf(input, firstByte)) >= 0)
    {
        for (int i = 0; i < pattern.Length; i++)
        {
            if (index + i  >= input.Length ||
                pattern[i] != input[index + i]) return -1;
        }
    }

    return index;
}

... или даже этот более подробный пример (также любезно предоставлен Social MSDN, та же ссылка)

public static int IndexOf(byte[] arrayToSearchThrough, byte[] patternToFind)
{
    if (patternToFind.Length > arrayToSearchThrough.Length)
        return -1;
    for (int i = 0; i < arrayToSearchThrough.Length - patternToFind.Length; i++)
    {
        bool found = true;
        for (int j = 0; j < patternToFind.Length; j++)
        {
            if (arrayToSearchThrough[i + j] != patternToFind[j])
            {
                found = false;
                break;
            }
        }
        if (found)
        {
            return i;
        }
    }
    return -1;
}
person MickyD    schedule 24.01.2018
comment
Ваш алгоритм поиска не из лучших. Использование алгоритма Бойера-Мура вы, вероятно, увидите 5-8-кратное ускорение. - person Scott Chamberlain; 24.01.2018
comment
Спасибо за пример кода! Я, вероятно, подожду еще день, прежде чем приму ответ, чтобы посмотреть, будут ли представлены какие-либо другие идеи. - person Noctis Skytower; 24.01.2018
comment
@ScottChamberlain, потому что это не мое, как указано - person MickyD; 25.01.2018
comment
@MickyD Я знаю, что я пытаюсь найти пример Бойера-Мура и показать, что это было бы лучше. - person Scott Chamberlain; 25.01.2018