【问题标题】:Intersect and Union in byte array of 2 files2个文件的字节数组中的相交和联合
【发布时间】:2015-11-28 06:29:23
【问题描述】:

我有 2 个文件。 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();

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

【问题讨论】:

  • 为什么会变慢?因为他们使用延迟执行。意味着例如src.Intersect(des) 实际上并没有进行相交。但它准备好了。当你使用 Count 它开始相交。 ;)
  • 几点:注释// get file length 具有误导性,因为它是缓冲区大小。 Counter 不是读取的字节数,而是读取的块数。 datadata1 将以最后一个块读取的结果结束,忽略它们之前的任何数据。那是假设 while 循环中没有任何问题 - 您需要删除 try 结构以查看是否有任何错误。

标签: c# bytearray union filestream intersection


【解决方案1】:

IntersectUnion 不是最快的操作。您看到它很快的原因是您从未真正枚举结果!

两者都返回一个可枚举的,而不是操作的实际结果。你应该经历那个并枚举可枚举的,否则什么都不会发生 - 这被称为“延迟执行”。现在,当您执行Count 时,您实际上枚举了可枚举对象,并承担了IntersectUnion 的全部成本 - 相信我,Count 本身是相对微不足道的(尽管仍然是 O(n) 操作!)。

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

【讨论】:

  • 是否有另一种有效的方法来计算外部的相交和联合?如果是,请提供给我。
  • @ChetanSanghani 这很难说,很大程度上取决于您的实际要求。你为什么首先要做联合和相交(在 24 字节的数据块上)?
【解决方案2】:

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

你可以做的是计算每个文件中每个字节的出现次数,然后如果 any 文件中一个字节的计数大于一个,那么它就是交集的成员的文件,如果 all 文件中的字节计数大于 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)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 2011-08-14
    • 2012-10-04
    • 2013-04-19
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    相关资源
    最近更新 更多