Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中从字节数组中删除尾部空值#_C#_Bytearray - Fatal编程技术网

C# 在C中从字节数组中删除尾部空值#

C# 在C中从字节数组中删除尾部空值#,c#,bytearray,C#,Bytearray,好的,我正在将dat文件读入字节数组。出于某种原因,生成这些文件的人在文件末尾放了大约一半meg的无用空字节。有人知道一个快速的方法来修剪这些末端吗 第一个想法是从数组的末尾开始,然后向后迭代,直到找到一个null以外的值,然后将所有内容复制到该点,但我想知道是否有更好的方法 要回答一些问题: 您确定0字节肯定在文件中,而不是在文件读取代码中存在错误吗?是的,我确信这一点 你能绝对地修剪所有尾随的0吗?对 文件的其余部分是否有0?是的,可能还有0的其他位置,因此,不,我不能从开头开始,在第一个0

好的,我正在将dat文件读入字节数组。出于某种原因,生成这些文件的人在文件末尾放了大约一半meg的无用空字节。有人知道一个快速的方法来修剪这些末端吗

第一个想法是从数组的末尾开始,然后向后迭代,直到找到一个null以外的值,然后将所有内容复制到该点,但我想知道是否有更好的方法

要回答一些问题: 您确定0字节肯定在文件中,而不是在文件读取代码中存在错误吗?是的,我确信这一点

你能绝对地修剪所有尾随的0吗?对


文件的其余部分是否有0?是的,可能还有0的其他位置,因此,不,我不能从开头开始,在第一个0处停止。

假设0=null,这可能是您最好的选择。。。作为一个小的调整,当您最终复制有用的数据时,您可能希望使用
Buffer.BlockCopy

这样如何:

[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
}

总有一个简单的答案

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();

您可以只在数组末尾计算零的数目,然后在以后迭代数组时使用它而不是.Length。你可以任意封装它。主要的一点是,您实际上不需要将其复制到新的结构中。如果他们是大的,那可能是值得的。

考虑到现在回答的额外问题,听起来你基本上做了正确的事情。特别是,您必须从最后0开始触摸文件的每个字节,以检查它是否只有0

现在,您是否必须复制所有内容取决于您对数据所做的操作

  • 您也许可以记住索引并将其与数据或文件名一起保存
  • 您可以将数据复制到新的字节数组中
  • 如果要“修复”该文件,可以调用截断该文件

“您必须读取截断点和文件结尾之间的每个字节”是关键部分。

我同意Jon的观点。关键的一点是,从最后一个字节到第一个非零字节,您必须“接触”每个字节。大概是这样的:

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);
我很确定这是你能做到的最有效的方法。

@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();

如果文件中的null字节可以是有效值,您知道文件中的最后一个字节不能为null吗。如果是这样,向后迭代并查找第一个非空条目可能是最好的,如果不是这样,则无法确定文件的实际结尾在哪里

如果您对数据格式了解得更多,例如空字节序列不能超过两个字节(或一些类似的约束)。然后,您可以实际对“转换点”进行二进制搜索。这应该比线性搜索快得多(假设您可以读取整个文件)

基本思想(使用我先前关于无连续空字节的假设)是:

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;
测试这一点:

    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;
        }
专用字节[]三字节(字节[]输入)
{
如果(input.Length>1)
{
int字节计数器=input.Length-1;
while(输入[字节计数器]==0x00)
{
字节计数器--;
}
字节[]rv=新字节[(字节计数器+1)];
for(int字节计数器1=0;字节计数器1<(字节计数器+1);字节计数器1++)
{
rv[字节计数器1]=输入[字节计数器1];
}
返回rv;
}

在我的例子中,LINQ方法从未完成过^)))使用字节数组的速度太慢了

伙计们,你们为什么不使用Array.Copy()方法呢

//
///从内存流获取字节数组。
/// 
///内存流。
公共静态字节[]GetAllBytes(此MemoryStream流)
{
字节[]结果=新字节[stream.Length];
Copy(stream.GetBuffer(),result,stream.Length);
返回结果;
}

将其视为文本似乎有风险-而且您刚刚将文件IO.Oh增加了两倍,CPU等也显著增加(编码/解码需要时间,即使是ASCII码)编码只是为了测试…编写示例文件。但是,将文件视为文本当然可能是个问题。这甚至不是字节数组。它是字符数组。您意识到,您可以在不进行任何文件写入的情况下从中生成字符串并修剪空字符,对吗?
char[]trimmed=new string(chars)。trim('\0')).ToCharArray()
而且这种编码会弄乱值大于0x80的字符,因此大小可能根本不匹配。只有在您确实必须复制数据的情况下:)另一种选择是将其视为更宽类型的数组,例如int或long。这可能需要不安全的代码,并且您必须处理数组的结尾如果它的字节数是奇数(续),那么它的“查找”效率可能会更高部分。在我证明这是瓶颈之前,我肯定不会尝试这样做:)你可能想在
中添加一个最小的签入,而
,或者如果数组只有0字节,你最终会尝试读取索引-1。我在另一个答案中发布了一个较短的LINQ替代方案。希望大家都喜欢。如果这是一个大的缓冲区,那么简单地向后使用索引器会更有效率是一个缓冲操作,并且有性能成本。很有趣。有没有人有任何基准来看看这与“原始”方法相比如何?这不是我会使用LINQ的原因。只是针对@Coderer的解决方案进行了测试,它大约是slowerstream.GetArray()的9倍在这个例子中进行调用会更好,因为它不会返回整个内存缓冲区,只返回写入缓冲区的数据……应该是stream.ToArray()。我的错。但是没有回答这个问题。好吧,这样的bu有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;
    }