Решение состоит из двух частей. Для первой части вам нужно прочитать карту памяти в обратном направлении, чтобы захватить строки, пока вы не прочитаете нужное количество строк (в данном случае 20).
Для второй части вы хотите обрезать файл до последних двадцати строк (установив их в string.Empty). Я не уверен, что вы можете сделать это с картой памяти. Возможно, вам придется где-то сделать копию файла и перезаписать оригинал исходными данными, за исключением последних байтов xxx (которые представляют последние двадцать строк)
Приведенный ниже код извлечет последние двадцать строк и отобразит его.
Вы также получите позицию (переменная lastBytePos )
где начинаются последние двадцать строк. Вы можете использовать эту информацию, чтобы знать, где обрезать файл.
ОБНОВЛЕНИЕ: Чтобы усечь файл, вызовите FileStream.SetLength (lastBytePos)
Я не был уверен, что вы имели в виду, что последние 20 строк плохие. Если диск физически поврежден и данные не могут быть прочитаны, я добавил список badPositions , который содержит позиции, в которых на карте памяти возникли проблемы с чтением данных.
У меня нет файла + 2GB для тестирования, но он должен работать (скрестив пальцы).
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.MemoryMappedFiles;
using System.IO;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
string filename = "textfile1.txt";
long fileLen = new FileInfo(filename).Length;
List<long> badPositions = new List<long>();
List<byte> currentLine = new List<byte>();
List<string> lines = new List<string>();
bool lastReadByteWasLF = false;
int linesToRead = 20;
int linesRead = 0;
long lastBytePos = fileLen;
MemoryMappedFile mapFile = MemoryMappedFile.CreateFromFile(filename, FileMode.Open);
using (mapFile)
{
var view = mapFile.CreateViewAccessor();
for (long i = fileLen - 1; i >= 0; i--) //iterate backwards
{
try
{
byte b = view.ReadByte(i);
lastBytePos = i;
switch (b)
{
case 13: //CR
if (lastReadByteWasLF)
{
{
//A line has been read
var bArray = currentLine.ToArray();
if (bArray.LongLength > 1)
{
//Add line string to lines collection
lines.Insert(0, Encoding.UTF8.GetString(bArray, 1, bArray.Length - 1));
//Clear current line list
currentLine.Clear();
//Add CRLF to currentLine -- comment this out if you don't want CRLFs in lines
currentLine.Add(13);
currentLine.Add(10);
linesRead++;
}
}
}
lastReadByteWasLF = false;
break;
case 10: //LF
lastReadByteWasLF = true;
currentLine.Insert(0, b);
break;
default:
lastReadByteWasLF = false;
currentLine.Insert(0, b);
break;
}
if (linesToRead == linesRead)
{
break;
}
}
catch
{
lastReadByteWasLF = false;
currentLine.Insert(0, (byte) '?');
badPositions.Insert(0, i);
}
}
}
if (linesToRead > linesRead)
{
//Read last line
{
var bArray = currentLine.ToArray();
if (bArray.LongLength > 1)
{
//Add line string to lines collection
lines.Insert(0, Encoding.UTF8.GetString(bArray));
linesRead++;
}
}
}
//Print results
lines.ForEach( o => Console.WriteLine(o));
Console.ReadKey();
}
}
}