在 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();
那么,有什么解决办法吗?
如果是,请尽快告诉我。
谢谢
Intersect
和 Union
不是最快的操作。您认为它很快的原因是您从未实际枚举结果!
两者都是return一个可枚举的,不是实际运行的结果。你应该通过它并枚举可枚举的,否则什么也不会发生——这叫做 "deferred execution"。现在,当您执行 Count
时,您实际上枚举了可枚举项,并承担了 Intersect
和 Union
的全部成本 - 相信我,Count
本身相对微不足道(虽然仍然是一个 O(n) 操作!)。
您很可能需要制定自己的方法。您希望避免可枚举的开销,更重要的是,您可能需要查找 table.
几点:注释 // get file length
是误导性的,因为它是缓冲区大小。 Counter
不是读取的字节数,是读取的块数。 data
和 data1
将以最后一个块读取的结果结束,忽略它们之前的任何数据。这是假设在 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)也是如此.
我有 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();
那么,有什么解决办法吗? 如果是,请尽快告诉我。 谢谢
Intersect
和 Union
不是最快的操作。您认为它很快的原因是您从未实际枚举结果!
两者都是return一个可枚举的,不是实际运行的结果。你应该通过它并枚举可枚举的,否则什么也不会发生——这叫做 "deferred execution"。现在,当您执行 Count
时,您实际上枚举了可枚举项,并承担了 Intersect
和 Union
的全部成本 - 相信我,Count
本身相对微不足道(虽然仍然是一个 O(n) 操作!)。
您很可能需要制定自己的方法。您希望避免可枚举的开销,更重要的是,您可能需要查找 table.
几点:注释 // get file length
是误导性的,因为它是缓冲区大小。 Counter
不是读取的字节数,是读取的块数。 data
和 data1
将以最后一个块读取的结果结束,忽略它们之前的任何数据。这是假设在 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)也是如此.