La solution comporte deux parties. Pour la première partie, vous devez lire la carte mémoire en arrière pour saisir les lignes, jusqu'à ce que vous ayez lu le nombre de lignes que vous voulez (20 dans ce cas). Pour la deuxième partie, vous voulez tronquer le fichier par les vingt dernières lignes (en les affectant à string.Empty). Je ne suis pas sûr si vous pouvez le faire avec une carte mémoire.
Vous devrez peut-être faire une copie du fichier quelque part et écraser l'original avec les données source sauf les xxx derniers octets (qui représentent les vingt dernières lignes)
Le code ci-dessous va extraire les vingt dernières lignes et l'afficher .
Vous obtiendrez également la position (lastBytePos variable) où commencent les vingt dernières lignes. Vous pouvez utiliser cette information pour savoir où tronquer le fichier.
MISE À JOUR: tronquer le fichier (appel FileStream.SetLength lastBytePos)
Je ne savais pas ce que vous vouliez dire par les 20 dernières lignes sont mauvais. Dans le cas où le disque est physiquement corrompu et que les données ne peuvent pas être lues, j'ai ajouté une liste badPositions qui contient les positions où la carte mémoire a eu des problèmes de lecture des données.
Je n'ai pas de fichier + 2GB à tester, mais cela devrait fonctionner (croiser les doigts).
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();
}
}
}
Vous connaissez un moyen ordinaire et vous en cherchez maintenant un cool? – khachik
Je ne connais aucun moyen en ce moment. J'espérais par défaut de «cool». À l'heure actuelle, je lis le fichier en utilisant un flux old-school sur l'objet File et readline jusqu'à la fin et juste montrer la fin, je ne suis même pas sur la partie supprimer. – Snowy