Подтвердить что ты не робот

Удаление конечных нулей из массива байтов в С#

Хорошо, я читаю в dat файлах в массив байтов. По какой-то причине люди, которые генерируют эти файлы, помещают в конец файла бесполезные нулевые байты в полтора мегабайта. Кто-нибудь знает быстрый способ обрезать их до конца?

Сначала нужно было начинать в конце массива и итерации назад, пока не найду что-то другое, кроме нулевого, а затем скопируйте все до этой точки, но мне интересно, нет ли лучшего способа.

Чтобы ответить на некоторые вопросы: Вы уверены, что 0 байтов определенно находятся в файле, а не ошибка в коде чтения файла? Да, я уверен в этом.

Можете ли вы точно обрезать все конечные 0? Да.

Могут ли быть какие-либо 0s в остальной части файла? Да, может быть 0 других мест, поэтому нет, я не могу начать с начала и останавливаться при первом 0.

4b9b3361

Ответ 1

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

Теперь, нужно ли вам копировать все или нет, зависит от того, что вы делаете с данными.

  • Возможно, вы помните индекс и сохраните его с данными или именем файла.
  • Вы можете скопировать данные в новый массив байтов
  • Если вы хотите "исправить" файл, вы можете вызвать FileStream.SetLength для обрезания файла

"Вы должны читать каждый байт между точкой усечения и концом файла", однако, является важной частью.

Ответ 2

Я согласен с Джоном. Критический бит заключается в том, что вы должны "касаться" каждого байта от последнего до первого ненулевого байта. Что-то вроде этого:

byte[] foo;
// populate foo
int i = foo.Length - 1;
while(foo[i] == 0)
    --i;
// now foo[i] is the last non-zero byte
byte[] bar = new byte[i+1];
Array.Copy(foo, bar, i+1);

Я уверен, что это так же эффективно, как вы сможете это сделать.

Ответ 3

@Factor Mystic,

Я думаю, что есть кратчайший путь:

var data = new byte[] { 0x01, 0x02, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00 };
var new_data = data.TakeWhile((v, index) => data.Skip(index).Any(w => w != 0x00)).ToArray();

Ответ 4

Как насчет этого:

[Test]
public void Test()
{
   var chars = new [] {'a', 'b', '\0', 'c', '\0', '\0'};

   File.WriteAllBytes("test.dat", Encoding.ASCII.GetBytes(chars));

   var content = File.ReadAllText("test.dat");

   Assert.AreEqual(6, content.Length); // includes the null bytes at the end

   content = content.Trim('\0');

   Assert.AreEqual(4, content.Length); // no more null bytes at the end
                                       // but still has the one in the middle
}

Ответ 5

Предполагая, что 0 = нуль, это, вероятно, лучший выбор... в качестве незначительной настройки вы можете использовать Buffer.BlockCopy, когда вы, наконец, скопируете полезные данные.

Ответ 6

проверьте это:

    private byte[] trimByte(byte[] input)
    {
        if (input.Length > 1)
        {
            int byteCounter = input.Length - 1;
            while (input[byteCounter] == 0x00)
            {
                byteCounter--;
            }
            byte[] rv = new byte[(byteCounter + 1)];
            for (int byteCounter1 = 0; byteCounter1 < (byteCounter + 1); byteCounter1++)
            {
                rv[byteCounter1] = input[byteCounter1];
            }
            return rv;
        }

Ответ 7

Всегда есть ответ LINQ

byte[] data = new byte[] { 0x01, 0x02, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00 };
bool data_found = false;
byte[] new_data = data.Reverse().SkipWhile(point =>
{
  if (data_found) return false;
  if (point == 0x00) return true; else { data_found = true; return false; }
}).Reverse().ToArray();

Ответ 8

Вы можете просто подсчитать количество нулей в конце массива и использовать это вместо .Length при повторном повторе массива. Вы можете инкапсулировать это, как хотите. Главное, вам не нужно копировать его в новую структуру. Если они большие, это может стоить того.

Ответ 9

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

Если вы знаете больше о формате данных, например, не может быть последовательности нулевых байтов длиной более двух байтов (или какого-либо подобного ограничения). Тогда вы можете фактически выполнить двоичный поиск "точки перехода". Это должно быть намного быстрее, чем линейный поиск (при условии, что вы можете читать во всем файле).

Основная идея (с использованием моего более раннего предположения о отсутствии последовательных нулевых байтов):

var data = (byte array of file data...);
var index = data.length / 2;
var jmpsize = data.length/2;
while(true)
{
    jmpsize /= 2;//integer division
    if( jmpsize == 0) break;
    byte b1 = data[index];
    byte b2 = data[index + 1];
    if(b1 == 0 && b2 == 0) //too close to the end, go left
        index -=jmpsize;
    else
        index += jmpsize;
}

if(index == data.length - 1) return data.length;
byte b1 = data[index];
byte b2 = data[index + 1];
if(b2 == 0)
{
    if(b1 == 0) return index;
    else return index + 1;
}
else return index + 2;

Ответ 10

В моем случае подход LINQ никогда не заканчивался ^))) Это замедлить работу с байтовыми массивами!

Ребята, почему вы не используете метод Array.Copy()?

    /// <summary>
    /// Gets array of bytes from memory stream.
    /// </summary>
    /// <param name="stream">Memory stream.</param>
    public static byte[] GetAllBytes(this MemoryStream stream)
    {
        byte[] result = new byte[stream.Length];
        Array.Copy(stream.GetBuffer(), result, stream.Length);

        return result;
    }