将文件读入 4 个字节的字节数组
本文关键字:字节 字节数 数组 文件 | 更新日期: 2023-09-27 18:33:07
我想知道如何将文件读入4字节长的ByteArrays。这些数组将作,然后必须转换回准备写入文件的单个数组。
编辑:代码片段。
var arrays = new List<byte[]>();
using (var f = new FileStream("file.cfg.dec", FileMode.Open))
{
for (int i = 0; i < f.Length; i += 4)
{
var b = new byte[4];
var bytesRead = f.Read(b, i, 4);
if (bytesRead < 4)
{
var b2 = new byte[bytesRead];
Array.Copy(b, b2, bytesRead);
arrays.Add(b2);
}
else if (bytesRead > 0)
arrays.Add(b);
}
}
foreach (var b in arrays)
{
BitArray source = new BitArray(b);
BitArray target = new BitArray(source.Length);
target[26] = source[0];
target[31] = source[1];
target[17] = source[2];
target[10] = source[3];
target[30] = source[4];
target[16] = source[5];
target[24] = source[6];
target[2] = source[7];
target[29] = source[8];
target[8] = source[9];
target[20] = source[10];
target[15] = source[11];
target[28] = source[12];
target[11] = source[13];
target[13] = source[14];
target[4] = source[15];
target[19] = source[16];
target[23] = source[17];
target[0] = source[18];
target[12] = source[19];
target[14] = source[20];
target[27] = source[21];
target[6] = source[22];
target[18] = source[23];
target[21] = source[24];
target[3] = source[25];
target[9] = source[26];
target[7] = source[27];
target[22] = source[28];
target[1] = source[29];
target[25] = source[30];
target[5] = source[31];
var back2byte = BitArrayToByteArray(target);
arrays.Clear();
arrays.Add(back2byte);
}
using (var f = new FileStream("file.cfg.enc", FileMode.Open))
{
foreach (var b in arrays)
f.Write(b, 0, b.Length);
}
编辑2:这是丑陋的贝蒂外观代码,可以实现我想要的。现在我必须改进它以提高性能...
var arrays_ = new List<byte[]>();
var arrays_save = new List<byte[]>();
var arrays = new List<byte[]>();
using (var f = new FileStream("file.cfg.dec", FileMode.Open))
{
for (int i = 0; i < f.Length; i += 4)
{
var b = new byte[4];
var bytesRead = f.Read(b, 0, b.Length);
if (bytesRead < 4)
{
var b2 = new byte[bytesRead];
Array.Copy(b, b2, bytesRead);
arrays.Add(b2);
}
else if (bytesRead > 0)
arrays.Add(b);
}
}
foreach (var b in arrays)
{
arrays_.Add(b);
}
foreach (var b in arrays_)
{
BitArray source = new BitArray(b);
BitArray target = new BitArray(source.Length);
target[26] = source[0];
target[31] = source[1];
target[17] = source[2];
target[10] = source[3];
target[30] = source[4];
target[16] = source[5];
target[24] = source[6];
target[2] = source[7];
target[29] = source[8];
target[8] = source[9];
target[20] = source[10];
target[15] = source[11];
target[28] = source[12];
target[11] = source[13];
target[13] = source[14];
target[4] = source[15];
target[19] = source[16];
target[23] = source[17];
target[0] = source[18];
target[12] = source[19];
target[14] = source[20];
target[27] = source[21];
target[6] = source[22];
target[18] = source[23];
target[21] = source[24];
target[3] = source[25];
target[9] = source[26];
target[7] = source[27];
target[22] = source[28];
target[1] = source[29];
target[25] = source[30];
target[5] = source[31];
var back2byte = BitArrayToByteArray(target);
arrays_save.Add(back2byte);
}
using (var f = new FileStream("file.cfg.enc", FileMode.Open))
{
foreach (var b in arrays_save)
f.Write(b, 0, b.Length);
}
编辑3:将一个大文件加载到 4 个字节的字节数组中并不是最聪明的主意......我有超过 6800 万个数组正在处理和操作。我真的想知道是否可以将其加载到单个数组中并且仍然可以进行位操作。:/
这是另一种方式,类似于@igofed的解决方案:
var arrays = new List<byte[]>();
using (var f = new FileStream("test.txt", FileMode.Open))
{
for (int i = 0; i < f.Length; i += 4)
{
var b = new byte[4];
var bytesRead = f.Read(b, i, 4);
if (bytesRead < 4)
{
var b2 = new byte[bytesRead];
Array.Copy(b, b2, bytesRead);
arrays.Add(b2);
}
else if (bytesRead > 0)
arrays.Add(b);
}
}
//make changes to arrays
using (var f = new FileStream("test-out.txt", FileMode.Create))
{
foreach (var b in arrays)
f.Write(b, 0, b.Length);
}
关于您的"编辑 3"...我会咬,尽管这确实是偏离原始问题的转移。
没有理由需要数组列表,因为您只需将文件分解为一个连续的 4 字节序列列表,循环遍历和处理每个序列,然后循环遍历并写入每个序列。 你可以做得更好。 注意:下面的实现不检查或处理长度不完全是 4 的倍数的输入文件。 如果它很重要,我把它留给你们作为练习。
为了直接解决您的意见,这里有一个单阵列解决方案。 我们将放弃 List 对象,将整个文件读入单个 byte[] 数组,然后复制该数组的 4 字节部分以执行位转换,然后将结果放回原处。 最后,我们将把整个东西猛击到输出文件中。
byte[] data;
using (Stream fs = File.OpenRead("E:''temp''test.bmp")) {
data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
}
byte[] element = new byte[4];
for (int i = 0; i < data.Length; i += 4) {
Array.Copy(data, i, element, 0, element.Length);
BitArray source = new BitArray(element);
BitArray target = new BitArray(source.Length);
target[26] = source[0];
target[31] = source[1];
// ...
target[5] = source[31];
target.CopyTo(data, i);
}
using (Stream fs = File.OpenWrite("E:''temp''test_out.bmp")) {
fs.Write(data, 0, data.Length);
}
所有丑陋的初始读取代码都消失了,因为我们只使用单字节数组。 请注意,我在处理循环之前保留了一个 4 字节数组以供重用,因此我们可以为垃圾回收器节省一些工作。 然后,我们一次循环遍历 4 个字节的巨型数据数组,并将它们复制到我们的工作数组中,使用它来初始化转换的 BitArray,然后块中的最后一条语句将 BitArray 转换回字节数组,并将其直接复制回其在巨型数据数组中的原始位置。 这将替换BitArrayToByteArray
方法,因为您没有提供它。 最后,写作也很容易,因为它只是猛烈抨击现在转换的巨大数据数组。
当我运行您的原始解决方案时,我的原始测试文件 100MB 出现内存不足异常,因此我使用了 44MB 文件。 它消耗了 650MB 的内存,并在 30 秒内运行。 单阵列解决方案使用了 54MB 内存,并在 10 秒内运行。 这不是一个糟糕的改进,它证明了保留数百万个小数组对象是多么糟糕。
这是你想要的:
using (var reader = new StreamReader("inputFileName"))
{
using (var writer = new StreamWriter("outputFileName"))
{
char[] buff = new char[4];
int readCount = 0;
while((readCount = reader.Read(buff, 0, 4)) > 0)
{
//manipulations with buff
writer.Write(buff);
}
}
}
IEnumerable<byte[]> arraysOf4Bytes = File
.ReadAllBytes(path)
.Select((b,i) => new{b, i})
.GroupBy(x => x.i / 4)
.Select(g => g.Select(x => x.b).ToArray())