17

わかりました、dat ファイルをバイト配列に読み込んでいます。なんらかの理由で、これらのファイルを生成する人々は、ファイルの最後に約 0.5 メガ分の無駄なヌル バイトを置きます。これらを端から切り取る簡単な方法を知っている人はいますか?

最初に考えたのは、配列の最後から開始して、null 以外のものが見つかるまで逆方向に反復し、その時点まですべてをコピーすることでしたが、もっと良い方法はないのでしょうか。

いくつかの質問に答えるには: コードを読み取るファイルにバグがあるのではなく、0 バイトが間違いなくファイルにあると確信していますか? はい、私はそれを確信しています。

末尾の 0 をすべて確実に削除できますか? はい。

ファイルの残りの部分に 0 を含めることはできますか? はい、0 の他の場所が存在する可能性があるため、いいえ、最初から開始して最初の 0 で停止することはできません。

4

11 に答える 11

23

ジョンに同意します。重要なのは、最後のバイトから最初の非ゼロバイトまでのすべてのバイトに「触れる」必要があるということです。このようなもの:

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

それはあなたがそれを成し遂げることができるのと同じくらい効率的だと私はかなり確信しています。

于 2008-10-27T17:32:31.870 に答える
11

現在回答されている追加の質問を考えると、基本的に正しいことをしているように思えます。特に、ファイルの最後の0以降のすべてのバイトをタッチして、ファイルに0しかないことを確認する必要があります。

さて、すべてをコピーする必要があるかどうかは、データをどのように処理しているかによって異なります。

  • おそらく、インデックスを覚えて、データまたはファイル名と一緒に保持することができます。
  • データを新しいバイト配列にコピーできます
  • ファイルを「修正」する場合は、FileStream.SetLengthを呼び出してファイルを切り捨てることができます。

ただし、「切り捨てポイントとファイルの終わりの間のすべてのバイトを読み取る必要がある」ということは重要な部分です。

于 2008-10-27T17:10:38.980 に答える
9

@ファクターミスティック、

最短の方法があると思います:

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();
于 2008-10-27T17:33:50.243 に答える
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
}
于 2008-10-27T15:30:50.210 に答える
2

0=null と仮定すると、おそらくそれが最善の策です...微調整として、Buffer.BlockCopy最終的に有用なデータをコピーするときに使用することをお勧めします..

于 2008-10-27T15:23:50.070 に答える
1

これをテストします:

    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;
        }
于 2010-02-07T07:24:03.510 に答える
0

ファイル内のnullバイトが有効な値になる可能性がある場合、ファイル内の最後のバイトをnullにすることはできないことをご存知ですか。その場合、逆方向に繰り返して最初のnull以外のエントリを探すのがおそらく最善です。そうでない場合は、ファイルの実際の終わりがどこにあるかを知る方法はありません。

2バイトより長い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;
于 2008-10-27T17:49:52.223 に答える
0

配列の最後にあるゼロの数を数えて、後で配列を反復するときに.Lengthの代わりにそれを使用することができます。これは好きなようにカプセル化できます。重要な点は、それを新しい構造にコピーする必要がないということです。それらが大きい場合、それは価値があるかもしれません。

于 2008-10-27T16:56:01.133 に答える
0

常に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();
于 2008-10-27T16:38:41.307 に答える
-2

私の場合、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;
    }
于 2010-04-27T22:02:08.130 に答える