質問
OK、私はdatファイルをバイト配列に読み込んでいます。何らかの理由で、これらのファイルを生成する人々は、ファイルの最後に約半分のメガバイトの無駄なヌルバイトを置きます。誰もがこれらを最後にトリムする簡単な方法を知っていますか?
最初に考えたのは、配列の最後から開始し、null以外の何かが見つかるまで逆方向に反復し、その時点まですべてをコピーすることでしたが、もっと良い方法はないかと思います。
いくつかの質問に答えるには: ファイルの読み取りコードにバグがあるのではなく、ファイルに0バイトが確実に含まれていると確信していますか?はい、確かです。
すべての末尾の0を確実に削除できますか?はい。
ファイルの残りに0を含めることはできますか?はい、0の他の場所がある可能性があるため、いいえ、最初から始めて最初の0で停止することはできません。
解決
追加の質問に答えると、基本的に正しいことをしているようです。特に、最後の0以降のファイルのすべてのバイトをタッチして、0のみが含まれていることを確認する必要があります。
今、すべてをコピーする必要があるかどうかは、データをどのように処理するかによって異なります。
- インデックスを覚えて、データまたはファイル名と一緒に保管することもできます。
- データを新しいバイト配列にコピーできます
- 「修正」したい場合ファイル、 FileStream.SetLength を呼び出すことができます。ファイルを切り捨てる
「切り捨てポイントからファイルの終わりまでのすべてのバイトを読み取る 」しかし、重要な部分です。
他のヒント
ジョンに同意します。重要なことは、「タッチ」する必要があることです。最後のバイトから最初の非ゼロバイトまでのすべてのバイト。このようなもの:
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();
これについてはどうですか:
[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
}
0 = nullと仮定すると、おそらくそれが最善の策です...微調整として、最終的に有用なデータをコピーするときに Buffer.BlockCopy
を使用することをお勧めします。
これをテスト:
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;
}
常に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();
配列の最後にあるゼロの数をカウントし、後で配列を反復するときに.Lengthの代わりにそれを使用できます。これを好きなようにカプセル化できます。要点は、新しい構造にコピーする必要は本当にないということです。それらが大きい場合、それは価値があるかもしれません。
ファイル内のヌルバイトが有効な値である可能性がある場合、ファイルの最後のバイトをヌルにすることはできません。その場合、逆方向に反復して最初の非ヌルエントリを検索するのがおそらく最善です。
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;
私の場合、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;
}