在 2 个文件的字节数组中相交和并集

Intersect and Union in byte array of 2 files

我有 2 个文件。 1 是源文件,第二个是目标文件。

下面是我使用字节数组对 Intersect 和 Union 两个文件的代码。

FileStream frsrc = new FileStream("Src.bin", FileMode.Open);
FileStream frdes = new FileStream("Des.bin", FileMode.Open);
int length = 24; // get file length
byte[] src = new byte[length];
byte[] des = new byte[length]; // create buffer
int Counter = 0;   // actual number of bytes read
int subcount = 0;

while (frsrc.Read(src, 0, length) > 0)
{
    try
    {
        Counter = 0;
        frdes.Position = subcount * length;
        while (frdes.Read(des, 0, length) > 0)
        {                               
                var  data = src.Intersect(des);                          
                var data1 = src.Union(des);                               
                Counter++;                               
        }        
        subcount++;
        Console.WriteLine(subcount.ToString());
        }
    }
    catch (Exception ex)
    {                          
    }
}

以最快的速度运行正常。 但现在的问题是我想要计算它,当我使用下面的代码时它变得非常慢。

  var  data = src.Intersect(des).Count();                          
  var  data1 = src.Union(des).Count();

那么,有什么解决办法吗? 如果是,请尽快告诉我。 谢谢

IntersectUnion 不是最快的操作。您认为它很快的原因是您从未实际枚举结果!

两者都是return一个可枚举的,不是实际运行的结果。你应该通过它并枚举可枚举的,否则什么也不会发生——这叫做 "deferred execution"。现在,当您执行 Count 时,您实际上枚举了可枚举项,并承担了 IntersectUnion 的全部成本 - 相信我,Count 本身相对微不足道(虽然仍然是一个 O(n) 操作!)。

您很可能需要制定自己的方法。您希望避免可枚举的开销,更重要的是,您可能需要查找 table.

几点:注释 // get file length 是误导性的,因为它是缓冲区大小。 Counter不是读取的字节数,是读取的块数。 datadata1 将以最后一个块读取的结果结束,忽略它们之前的任何数据。这是假设在 while 循环中没有任何错误 - 你需要删除 try 结构以查看是否有任何错误。

你可以做的是计算每个文件中每个字节的出现次数,然后如果 any 文件中的字节数大于 1,则它是文件交集的成员,如果所有文件中的字节数大于一个,则它是文件并集的成员。

为两个以上的文件编写代码就像为两个文件编写代码一样容易,而 LINQ 为两个文件编写代码很容易,但为两个以上的文件编写代码就有点繁琐了。 (我在末尾对两个文件以天真的方式使用 LINQ 进行了比较。)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            var file1 = @"C:\Program Files (x86)\Electronic Arts\Crysis 3\Bin32\Crysis3.exe"; // 26MB
            var file2 = @"C:\Program Files (x86)\Electronic Arts\Crysis 3\Bin32\d3dcompiler_46.dll"; // 3MB
            List<string> files = new List<string> { file1, file2 };

            var sw = System.Diagnostics.Stopwatch.StartNew();

            // Prepare array of counters for the bytes
            var nFiles = files.Count;
            int[][] count = new int[nFiles][];
            for (int i = 0; i < nFiles; i++)
            {
                count[i] = new int[256];
            }

            // Get the counts of bytes in each file
            int bufLen = 32768;
            byte[] buffer = new byte[bufLen];

            int bytesRead;

            for (int fileNum = 0; fileNum < nFiles; fileNum++)
            {
                using (var sr = new FileStream(files[fileNum], FileMode.Open, FileAccess.Read))
                {
                    bytesRead = bufLen;
                    while (bytesRead > 0)
                    {
                        bytesRead = sr.Read(buffer, 0, bufLen);
                        for (int i = 0; i < bytesRead; i++)
                        {
                            count[fileNum][buffer[i]]++;
                        }
                    }
                }
            }

            // Find which bytes are in any of the files or in all the files
            var inAny = new List<byte>(); // union
            var inAll = new List<byte>(); // intersect

            for (int i = 0; i < 256; i++)
            {
                Boolean all = true;
                for (int fileNum = 0; fileNum < nFiles; fileNum++)
                {
                    if (count[fileNum][i] > 0)
                    {
                        if (!inAny.Contains((byte)i)) // avoid adding same value more than once
                        {
                            inAny.Add((byte)i);
                        }
                    }
                    else
                    {
                        all = false;
                    }
                };

                if (all)
                {
                    inAll.Add((byte)i);
                };

            }

            sw.Stop();

            Console.WriteLine(sw.ElapsedMilliseconds);

            // Display the results
            Console.WriteLine("Union: " + string.Join(",", inAny.Select(x => x.ToString("X2"))));
            Console.WriteLine();
            Console.WriteLine("Intersect: " + string.Join(",", inAll.Select(x => x.ToString("X2"))));
            Console.WriteLine();

            // Compare to using LINQ.
            // N/B. Will need adjustments for more than two files.

            var srcBytes1 = File.ReadAllBytes(file1);
            var srcBytes2 = File.ReadAllBytes(file2);

            sw.Restart();

            var intersect = srcBytes1.Intersect(srcBytes2).ToArray().OrderBy(x => x);
            var union = srcBytes1.Union(srcBytes2).ToArray().OrderBy(x => x);

            Console.WriteLine(sw.ElapsedMilliseconds);

            Console.WriteLine("Union: " + String.Join(",", union.Select(x => x.ToString("X2"))));
            Console.WriteLine();
            Console.WriteLine("Intersect: " + String.Join(",", intersect.Select(x => x.ToString("X2"))));

            Console.ReadLine();

        }
    }
}

在我的计算机上,计算字节出现次数的方法大约比 LINQ 方法快五倍,即使后者没有加载文件并且文件大小范围(几 KB 到几 MB)也是如此.