删除文件前几个字节的最快方法

时间:2011-09-09 20:35:00

标签: c# file-io windows-mobile-6 windows-mobile-6.5

我正在使用Windows Mobile Compact 6.5手机,并将二进制数据写入蓝牙文件。这些文件变得非常大,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 个答案:

答案 0 :(得分:2)

您正在对整个文件执行逐字节复制。由于一大堆原因,这种方法效率不高。搜索起始偏移(如果需要,则为结束偏移),然后从两个偏移(或起始偏移和文件结束)之间的整个内容从一个流复制到另一个流。

修改

您无需阅读全部内容即可进行复制。这样的事情(未经测试,但你明白了)会起作用。

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 :(得分:1)

不要忽视一种方法,因为你害怕它会太慢。 试一试!尝试一下只需要5-10分钟,可能会有更好的解决方案。

如果数据启动的检测过程不是太复杂/慢,那么在您启动之前避免写入数据实际上可能会使程序跳过垃圾数据更有效。 / p>

如何做到这一点:

  • 使用简单的bool来了解您是否检测到数据的开头。如果你正在阅读垃圾,那么不要浪费时间将其写入输出,只需扫描它以检测数据的开始。找到开始后,停止扫描开始,然后将数据复制到输出。只是复制好的数据只会产生if (found)次检查,这对您的表现不会产生任何明显的影响。

您可能会发现这本身就解决了这个问题。但如果您需要更高的性能,可以对其进行优化:

  • 您可以做些什么来最大限度地减少检测数据开始时所做的工作?也许如果您正在寻找一个复杂的序列,您只需要检查一个特定的字节值来启动序列,并且只有当您找到需要进行更复杂检查的起始字节时才会这样做。有一些非常简单但有效的字符串搜索算法也可能在这种情况下有所帮助。或者也许你可以分配一个缓冲区(例如4kB)并逐渐用输入流中的字节填充它。填充缓冲区后,然后只有搜索缓冲区中“垃圾”的结尾。通过批量处理工作,您可以利用内存/缓存一致性来使处理比逐字节完成相同工作时的处理效率更高。

  • 是否需要不断检查传入数据的所有其他“条件”?如何最大限度地减少您需要完成的工作量,但仍能达到要求的效果?也许上面的一些想法也可能对此有所帮助?

  • 在跳过垃圾时,你真的需要对数据进行任何处理吗?如果没有,那么你可以把整个事情分成两个阶段(跳过垃圾,复制数据),跳过垃圾不会花费任何实际问题。