Сгруппируйте то, что находится между нулевыми байтами, используя Regex на FileStream - PullRequest
0 голосов
/ 25 сентября 2018

Я просматриваю двоичный файл, и мне нужно сгруппировать несколько байтов, которые находятся между нулевыми значениями, чтобы я мог выполнить некоторые преобразования int.Parse (), учитывая следующие байты, как бы вы вернули группы:

C8 6B 02 00 55 4E 02 00 C8 6B 02 00 00 00 00 00
00 00 00 00 27 00 00 00 81 09 00 00 00 00 00 00
EC 6A 05 00 79 75 01 88 81 00 00 00 41 00 00 28
01 00 00 00 00 00 00 00 00 00 01 00 00 02 01 04
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 F6 5F A4 59 00 00 00 00
FF 00 00 00 2F 00 00 00 00 00 00 00 49 00 00 00
40 3C 9F 5A 00 00 00 00 00 00 00 00 00 00 00 00
FF FF 33 00 00 00 00 00 00 0F 06 EA E8 33 35 36

Чтобы он возвращал что-то вроде:

["C86B02", "554E02", "C86B02", "27","8109"....]

Было бы примерно так:

  public static FileStream stream = new FileStream(@"C:\BitBucket\Datamining\WpfApp1\WpfApp1\zip.dat", FileMode.Open, FileAccess.Read);
  int limit = 3000;
    public MainWindow()
    {
        byte[] block = new byte[limit];

        stream.Position = 0;
        stream.Read(block, 0, limit);

        for (int i = 0; i < block.Length; i++)
        {
            if (block[i] == 0x00)
            {
                block[i] = 0x7E; // I added this to visualize the null, but now I realize it will screw up Int conversions
            }
        }
        fs.Write(block, 0, block.Length);
    }

Некоторые из файлов, с которыми я работаю, огромны (более1 ГБ), так что открывать только первые несколько килобайт лучше, чем использовать File.ReadAllText().

В качестве дополнительного бонуса было бы здорово иметь его в качестве пары ключ-значение с расположением смещения первого байта совпадения.

Ответы [ 4 ]

0 голосов
/ 26 сентября 2018

Ограничьте размер, который вы можете сделать, настраивая параметр функции чтения, но может быть что-то вроде:

 static void Main(string[] args)
        {
            var fs = new FileStream(@"file.bin", FileMode.Open);
            var b = new byte[fs.Length];
            var data = fs.Read(b, 0, (int)fs.Length);
            var concatenatedData = new List<string>();
            var temp = string.Empty;
            var processedData = new Dictionary<int, string>();
            var offSet = 0;
            for (int x = 0; x < fs.Length; x ++)
            {
                if (b[x] == 32 || b[x] == 10 || b[x] == 13)
                    continue;
                if (b[x] == 48)
                {
                    if ((x + 1) < fs.Length && b[x + 1] == 48)
                    {
                        if (!string.IsNullOrEmpty(temp))
                            processedData.Add(offSet, temp);
                        temp = string.Empty;
                        x++;
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(temp))
                            offSet = x;
                        temp += ((char)b[x]).ToString();
                    }
                }
                else
                {
                    if (string.IsNullOrEmpty(temp))
                        offSet = x;
                    temp += ((char)b[x]).ToString();
                }
            }
            if (!string.IsNullOrEmpty(temp))
                processedData.Add(offSet , temp);



            Console.ReadLine();
        }
0 голосов
/ 25 сентября 2018

Попробуйте это:

void Main()
{

// you can run the commented code as test
//  var bytes = new byte[]
//  {0xC8,  0x6B,  0x02,  0x00,  0x55,  0x4E,  0x02,  0x00,  0xC8,  0x6B,  0x02,  0x00,  0x00,  0x00,  0x00,  0x00, 
//  0x00,  0x00,  0x00,  0x00,  0x27,  0x00,  0x00,  0x00,  0x81,  0x09,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00, 
//  0xEC,  0x6A,  0x05,  0x00,  0x79,  0x75,  0x01,  0x88,  0x81,  0x00,  0x00,  0x00,  0x41,  0x00,  0x00,  0x28, 
//  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x02,  0x01,  0x04, 
//  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00, 
//  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xF6,  0x5F,  0xA4,  0x59,  0x00,  0x00,  0x00,  0x00, 
//  0xFF,  0x00,  0x00,  0x00,  0x2F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x49,  0x00,  0x00,  0x00, 
//  0x40,  0x3C,  0x9F,  0x5A,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00, 
//  0xFF,  0xFF,  0x33,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x0F,  0x06,  0xEA,  0xE8,  0x33,  0x35,  0x36};
//  var testStream = new MemoryStream(bytes);
//  var entries = SplitStream(testStream);

    var fileStreamBufferSize = 1024 * 1024; // one megabyte, increasing this might speed up
    using(var stream = new FileStream(@"C:\BitBucket\Datamining\WpfApp1\WpfApp1\zip.dat",
                  FileMode.Open,
                  FileAccess.Read,
                  FileShare.Read,
                  fileStreamBufferSize,
                  FileOptions.SequentialScan // SequentialScan helps os optimize for read
                  ))
    {
        var entiries = SplitStream(stream);
    }
}

private IEnumerable<KeyValuePair<int, IEnumerable<byte>>> SplitStream(Stream stream)
{
    var buf = new byte[1024];
    var entry = new List<byte>();
    int readCount = 0;
    var offset = 0;
    var entryStartOffset = 0;

    while((readCount = stream.Read(buf, 0, buf.Length)) > 0)
    {
        for(int i = 0; i < readCount; i++)
        {
            if(buf[i] == 0) // found entry end
            {
                if(entry.Count > 0) // check if we have values to return
                {
                    yield return new KeyValuePair<int, IEnumerable<byte>>(entryStartOffset, entry);
                    entry.Clear();
                }
            }
            else // add to current entry
            {
                if(entry.Count < 1) // if first value save start offset
                {
                    entryStartOffset = offset;
                }
                entry.Add(buf[i]);
            }
            offset++;
        }
    }
    if(entry.Count > 0) // if current entry not returned
    {
        yield return new KeyValuePair<int, IEnumerable<byte>>(entryStartOffset, entry);             
    }
}
0 голосов
/ 25 сентября 2018

Фокус на вашей основной проблеме (вывод на печать частей файла), без «бонуса»:

private static IEnumerable<string> FindParts(byte[] file)
{
    return file.Aggregate(new string[1], (acc, b) =>
    {
        if (b != 0)
        {
            acc[acc.Length - 1] += b.ToString("X2");
            return acc;
        }
        else
        {
            return acc.Concat(new string[1]).ToArray();
        }
    })
    .Where(s => !string.IsNullOrEmpty(s));
}
0 голосов
/ 25 сентября 2018

Читайте пошагово и собирайте данные до тех пор, пока вы не найдете нулевой байт.Если вы найдете нулевой байт, добавьте собранные байты в список и продолжайте.Чтобы дать вам представление, я создал примерный фрагмент кода:

public class BytesInfo
{
    public int Position { get; set; }
    public string Bytes { get; set; }
}

var source = @"C86B0200554E0200C86B02000000000000000000270000008109000000000000EC6A050079750188810000004100002801000000000000000000010000020104000000000000000000000000000000000000000000000000F65FA45900000000FF0000002F0000000000000049000000403C9F5A000000000000000000000000FFFF330000000000000F06EAE8333536";
var l = new List<BytesInfo>();
var p = 0;
var s = "";
for (var i = 0; i < source.Length; i += 2)
{
    var b = source.Substring(i, 2);
    if (b == "00")
    {
        if (s != "")
        {
            l.Add(new BytesInfo()
            {
                Position = p,
                Bytes = s
            });
            s = "";
        }
    }
    else
    {
        if (s == "")
        {
            p = i;
        }
        s += b;
    }
}

foreach (var e in l)
{
    Console.WriteLine($"Position: {e.Position}, Bytes: {e.Bytes}");
}
...