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

本文关键字:数组 文件 2个 字节 字节数 | 更新日期: 2023-09-27 18:24:44

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

下面是我使用字节数组的交集和并集两个文件的代码。

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();

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

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

IntersectUnion不是最快的操作。你看到它很快的原因是你从来没有真正列举过结果!

两者都返回可枚举值,而不是操作的实际结果。你应该遍历并枚举可枚举的,否则什么都不会发生——这被称为"延迟执行"。现在,当你执行Count时,你实际上枚举了可枚举的,并产生了IntersectUnion的全部成本——相信我,Count本身相对来说是微不足道的(尽管仍然是一个O(n)运算!)。

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

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

您可以做的是计算每个文件中每个字节的出现次数,如果任何文件中的一个字节计数大于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)。