天天看點

c# 倒序讀取txt檔案

倒序讀取txt檔案,基本思路:

1.使用 FileStream 檔案流,可以設定流的位置 position;

2.每次讀取一行:行的标記就是兩個 \n 之間的内容,占位符在流中的值為 ;

byte n = 0xD;//回車符

byte r = 0xA;//換行符

3.讀取時每一行從後向前讀,是以輸出的字元串為倒的,故讀完一行後要将内容反轉;

4.倒序讀行時同理,行的記錄也是倒的,需要将行記錄反轉;

調用方法:

1.擷取檔案夾下的所有檔案資訊

var files = GetFile("c:\logs");

2.擷取指定檔案最後200行記錄

var result = LastLog("c:\\logs\log.txt",0);

result.data ;//檔案内容

result.position; //本次讀取流的起始位置

主要方法:

/// <summary>
/// 擷取目錄下所有檔案資訊
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private List<LogFileModel> GetFile(string path)
{
  List<LogFileModel> list = new List<LogFileModel>();
  var files = Directory.GetFiles(path);
  
  if (files.IsNullOrDbNull())
    return null;
  LogFileModel item;
  FileInfo f;
  Func<long, string> getFileSize = (x) =>
  {
    if (x <= 0)
      return "0KB";
    var d = Math.Round(x*1.0/1024/1024, 2);
    return string.Format("{0}KB", d);
  };
  var fileInfos = new List<FileInfo>();
  files.All(x =>
  {
    fileInfos.Add(new FileInfo(x));
    return true;
  });
  int i = 1;
  //按照建立時間倒序
  fileInfos
    .OrderByDescending(x=>x.CreationTime)
    .ToList()
    .ForEach(x =>
  {
    item = new LogFileModel
    {
      name = x.Name,
      size=x.Length,
      desc = getFileSize(x.Length)
    };

    list.Add(item);
    
    if (i++ >= 20)
      return ;
  });
  return list;
}

/// <summary>
/// 倒序讀取文本檔案
/// </summary>
/// <param name="file">檔案路徑</param>
/// <param name="position">讀取流的起始位置</param>
/// <returns></returns>
public LastLogResult LastLog(string file, long position)
{
  if (!File.Exists(file))
  {
    result.msg = "檔案路徑無效!";
    return result;
  }
  StringBuilder txt = new StringBuilder();
  long ps = position;
  using (var fs = new FileStream(file,FileMode.Open,FileAccess.Read))
  {
    if (ps <= 0)
      ps = fs.Length;
    //讀取200行
    for (int i = 0; i < 200; i++)
    {
      ps = InverseReadRow(fs, ps, ref txt);
      if (ps <= 0)
        break;
    }
  }
  result.data = txt.ToString();
  result.position = ps;
  result.success = true;
  return result;
}


/// <summary>
/// 從後向前按行讀取文本檔案,最多讀取 10kb
/// </summary>
/// <param name="fs"></param>
/// <param name="position"></param>
/// <param name="s"></param>
/// <param name="maxRead">預設每次最多讀取10kb資料</param>
/// <returns>傳回讀取位置</returns>
long InverseReadRow(FileStream fs
  , long position
  , ref StringBuilder s
  , int maxRead = 10240)
{
  byte n = 0xD;//回車符
  byte r = 0xA;//換行符
  if (fs.Length == 0)
    return 0;
  var newPos = position - 1;
  int curVal = 0;
  var readLength = 0;
  List<byte> arr = new List<byte>();
  var str = "";
  //bool brk = false;
  do
  {
    readLength++;
    if (newPos <= 0)
      newPos = 0;

    fs.Position = newPos;
    curVal = fs.ReadByte();
    if (curVal == -1)
      break;

    arr.Insert(0, (byte)curVal);

    if (newPos <= 0)
      break;
    //
    if (readLength == maxRead)
      break;


    if (curVal != n)
      newPos--;

  } while (curVal != n);
  str = Encoding.UTF8.GetString(arr.ToArray());
  s.Insert(0, str);

  return newPos;
}      

使用的對象

public class LogFileModel
{
  public string name { set; get; }
  public long size { set; get; }
  public string desc { set; get; }
}
public class ResultModel<T>
{
  public ResultModel()
  {
    data = default(T);
  }

  public string msg { set; get; }
  public bool success
  {
    set;
    get;
  }
  public T data { set; get; }
}

public class LastLogResult : ResultModel<string>
{
  public long position { set; get; }
}      

繼續閱讀