ファイルを短くする唯一の方法は、実際にファイルの一部をコピーしてからスキップして、残りをコピーすることだと思います。本当にその場でそれを行う必要がある場合は、何らかの形式の論理的削除を選択できます。たとえば、LFのみを使用してテキストファイルの新しい行をエンコードできます(これはWindowsのデフォルトではなく、代わりにペアのCR-LFを使用します)。これはおそらく8ビットASCIIであり、次のようなものを選択する必要があります。 :
public static void LogicalEraseLine(string filename, int toDel)
{
FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite);
fs.Seek(toDel, SeekOrigin.Current);
int c;
while ((c = fs.ReadByte()) != -1)
{
if (c == '\n')
{
break;
}
else
{
fs.Seek(-1, SeekOrigin.Current);
fs.WriteByte((byte)'\n');
}
}
fs.Close();
}
toDelは、削除する行のインデックスではなく、削除する最初の文字のインデックスであることに注意してください。このコードは、toDelの文字と行の終わりの間のすべての文字を同じ数の空の行に置き換えるだけです。次に、ファイルを別のファイルにコピーするために別の関数が必要になりますが、空の行はすべてスキップします。このクリーンアップは、将来の都合の良いときにいつでも実行できます。ただし、実際のアルゴリズムでは、ファイル内の多くの空白行に対処できる必要があります。また、ファイルをチャンクで読み取る必要があるのは正しいですが、この例に示されている基本的な考え方は、その場合にも適用できます。
編集
この機能を使用して、論理的に削除された行を消去できます。
public static void Cleanup (string filename)
{
FileStream input = new FileStream(filename, FileMode.Open, FileAccess.Read);
FileStream output = new FileStream(filename + ".tmp", FileMode.Create, FileAccess.Write);
bool emptyLine = true;
int c;
while ((c = input.ReadByte()) != -1)
{
if (c == '\n')
{
if (!emptyLine)
{
output.WriteByte((byte)c);
emptyLine = true;
}
}
else
{
output.WriteByte((byte)c);
emptyLine = false;
}
}
input.Close();
output.Close();
File.Delete (filename);
File.Copy(filename + ".tmp", filename);
File.Delete(filename + ".tmp");
}
また、ファイルを削除するときは、細心の注意を払い、問題が発生する可能性のあるすべてのものを再確認することをお勧めします。
編集
最初のアルゴリズムは、まだファイル全体を読んでいたので、ちょっと意味がありませんでした。今では理にかなっています。