Самый быстрый способ удалить первые несколько байтов файла - PullRequest
2 голосов
/ 10 сентября 2011

Я использую телефон Windows Mobile Compact Edition 6.5 и записываю двоичные данные в файл с Bluetooth.Эти файлы становятся достаточно большими, 16M +, и что мне нужно сделать, это как только файл будет записан, мне нужно найти в файле начальный символ, а затем удалить все, прежде чем, таким образом, устраняя мусор.Я не могу сделать это встроенным, когда данные поступают из-за проблем с графикой и скоростью, так как я получаю много поступающих данных, и уже слишком много условий для входящих данных.Я подумал, что лучше всего опубликовать процесс.В любом случае, вот моя дилемма, скорость поиска начальных байтов, и перезапись файла занимает иногда 5 минут или больше ... Я в основном перемещаю файл во временный файл, анализирую его и переписываю целый новый файл.Я должен сделать это побайтно.

private void closeFiles() {
    try {

    // Close file stream for raw data.
    if (this.fsRaw != null) {
        this.fsRaw.Flush();
        this.fsRaw.Close();

        // Move file, seek the first sync bytes, 
        // write to fsRaw stream with sync byte and rest of data after it
        File.Move(this.s_fileNameRaw, this.s_fileNameRaw + ".old");
        FileStream fsRaw_Copy = File.Open(this.s_fileNameRaw + ".old", FileMode.Open);
        this.fsRaw = File.Create(this.s_fileNameRaw);

        int x = 0;
        bool syncFound = false;

        // search for sync byte algorithm
        while (x != -1) {
            ... logic to search for sync byte
            if (x != -1 && syncFound) {
                this.fsPatientRaw.WriteByte((byte)x);
            }
        }

        this.fsRaw.Close();

        fsRaw_Copy.Close();
        File.Delete(this.s_fileNameRaw + ".old");
    }


    } catch(IOException e) {
        CLogger.WriteLog(ELogLevel.ERROR,"Exception in writing: " + e.Message);
    }
}

Должен быть более быстрый способ, чем этот!

------------ Тестирование времени с использованием ответа -------------

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

27 Kb/sec

с использованием ответа ниже и буфера 32768 байт:

321 Kb/sec

с использованием ответа ниже и буфера 65536 байтов:

501 Kb/sec

Ответы [ 2 ]

2 голосов
/ 10 сентября 2011

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

EDIT

Вам не нужно читать все содержимое, чтобы сделать копию. Нечто подобное (непроверенное, но вы поняли идею) будет работать.

private void CopyPartial(string sourceName, byte syncByte, string destName)
{
    using (var input = File.OpenRead(sourceName))
    using (var reader = new BinaryReader(input))
    using (var output = File.Create(destName))
    {
        var start = 0;
        // seek to sync byte
        while (reader.ReadByte() != syncByte)
        {
            start++;
        }

        var buffer = new byte[4096]; // 4k page - adjust as you see fit

        do
        {
            var actual = reader.Read(buffer, 0, buffer.Length);
            output.Write(buffer, 0, actual);
        } while (reader.PeekChar() >= 0);
    }

}

РЕДАКТИРОВАТЬ 2

Мне действительно нужно было что-то похожее на это сегодня, поэтому я решил написать это без вызова PeekChar (). Вот суть того, что я сделал - не стесняйтесь интегрировать его со вторым циклом do...while выше.

            var buffer = new byte[1024];
            var total = 0;

            do
            {
                var actual = reader.Read(buffer, 0, buffer.Length);
                writer.Write(buffer, 0, actual);
                total += actual;
            } while (total < reader.BaseStream.Length);
1 голос
/ 13 сентября 2011

Не сбрасывайте со счетов подход, потому что вы боитесь, что он будет слишком медленным. Попробуйте! Это займет всего 5-10 минут, чтобы попробовать, и может привести к гораздо лучшему решению.

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

Как это сделать:

  • Используйте простой bool, чтобы узнать, обнаружили ли вы начало данных.Если вы читаете мусор, то не тратьте время на запись его на выход, просто отсканируйте его, чтобы определить начало данных.Как только вы найдете начало, прекратите сканирование для начала и просто скопируйте данные в вывод.Простое копирование хороших данных повлечет за собой не более чем if (found) проверку, которая действительно не окажет заметного влияния на вашу производительность.

Вы можете обнаружить, что это само по себе решает проблему.Но вы можете оптимизировать его, если вам нужно больше производительности:

  • Что вы можете сделать, чтобы минимизировать работу, которую вы выполняете, чтобы обнаружить начало данных?Возможно, если вы ищете сложную последовательность, вам нужно проверить только одно конкретное значение байта, которое запускает последовательность, и только если вы найдете этот начальный байт, вам нужно выполнить более сложную проверку.Есть несколько очень простых, но эффективных алгоритмов поиска строк, которые также могут помочь в этом случае.Или, возможно, вы можете выделить буфер (например, 4 КБ) и постепенно заполнять его байтами из вашего входящего потока.Когда буфер заполнен, тогда и только тогда ищет конец «мусора» в вашем буфере.Путем пакетной обработки вы можете использовать согласованность памяти и кэша, чтобы сделать обработку значительно более эффективной, чем если бы вы выполняли одну и ту же работу побайтно.

  • Делайте все остальные«условия на входящие данные» нужно постоянно проверять?Как вы можете минимизировать объем работы, которую вам нужно сделать, но при этом достичь желаемых результатов?Возможно, некоторые из представленных выше идей могут помочь и здесь?

  • Вам действительно нужно выполнять какую-либо обработку данных во время пропуска мусора?Если нет, то вы можете разбить все это на две фазы (пропустить ненужную, скопировать данные), и пропуск ненужной не будет вам стоить ничего, когда это действительно имеет значение.

...