C#.NET 中实现 Linux "tail -f" 命令






2.78/5 (8投票s)
2006年8月31日

64444

979
打印文件最后 10 行。
引言
这是一个非常基础的实用工具,你肯定需要它。我最初使用的是 GNU 工具 for Windows,但后来我想用 .NET 编写这些工具,所以 tail.exe 是第一个。
我查阅了许多 .NET 中 tail 命令的实现,但它们都不是 GNU 对应版本的完整移植。
代码
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;
using System.Threading;
namespace GNUtools
{
class Program
{
static int Main(string[] args)
{
int noOfLines = 0;
int returnStatus = 0;
string newline = "\n";//Environment.NewLine;??
int charSize = encoding.IsSingleByte ? 1 : 2;
byte[] buffer = null;
bool printed = false;
string temp = string.Empty;
ParseArgs(args);
FileStream stream=null;
try
{
stream = new FileStream(fileName, FileMode.Open,
FileAccess.Read, FileShare.Write);
long endPos = stream.Length / charSize, oldPos = 0;
long posLength;
do
{
printed = false;
noOfLines = 0;
buffer = new byte[charSize];
endPos = stream.Length / charSize;
if (endPos <= oldPos) oldPos = endPos; // if file's content is
//deleted, reset position
posLength = endPos - oldPos;
for (long pos = charSize; pos <= posLength; pos += charSize)
{
stream.Seek(-pos, SeekOrigin.End);
stream.Read(buffer, 0, charSize);
temp = encoding.GetString(buffer);
if (temp == newline)
{
noOfLines++;
}
if (noOfLines == noOfLinesWanted || pos == noOfCharsWanted)
{
buffer = new byte[endPos - stream.Position];
stream.Read(buffer, 0, buffer.Length);
Console.WriteLine(encoding.GetString(buffer));
printed = true;
oldPos = endPos;
break;
}
}
if (!printed)
{
buffer = new byte[endPos - oldPos];
stream.Seek(-1, SeekOrigin.Current);
stream.Read(buffer, 0, buffer.Length);
Console.WriteLine(encoding.GetString(buffer));
oldPos = endPos;
}
if (loop && endPos == stream.Length / charSize) Thread.Sleep(0);
} while (true);
}
catch (ArgumentException)
{
printUsage();
}
catch (IOException)
{
printUsage();
returnStatus = -5;
}
catch (Exception)
{
Console.WriteLine("Encountered some error.");
returnStatus = -1;
}
finally
{
if (stream != null)
stream.Close();
}
return returnStatus;
}
static void printUsage()
{
Console.Write("Usage : ");
Console.WriteLine("tail [OPTION]... [FILE]");
Console.WriteLine("");
Console.WriteLine("Print the last 10 lines of FILE to console.");
Console.WriteLine("");
Console.WriteLine("OPTION :");
Console.WriteLine("");
Console.WriteLine("-f : keep scanning the file till user aborts");
Console.WriteLine("-n=[no. of lines] : from end to read. Default is 10.");
Console.WriteLine("-c=[no. of chars] : from end to read.
Default is 800 ascii chars. ");
Console.WriteLine("-e=[ascii/unicode] : type of encoding to use
while reading the file. Default is ASCII.");
Console.WriteLine("");
}
static void ParseArgs(string[] args)
{
string[] option = null;
if (args.Length == 0)
{
throw new ArgumentException();
}
foreach (string arg in args)
{
option = arg.Split(new char[]{'='}, StringSplitOptions.None);
switch (option[0])
{
case "-f":
loop = true;
break;
case "-n":
noOfLinesWanted = int.Parse(option[1]);
if (noOfLinesWanted < 1 || noOfLinesWanted > 40)
noOfLinesWanted = 10;
break;
case "-c":
noOfCharsWanted = int.Parse(option[1]);
if (noOfCharsWanted < 1 || noOfCharsWanted > 800)
noOfCharsWanted = 800;
break;
case "-e":
encoding=Encoding.GetEncoding(option[1]);
break;
default:
fileName = arg;
break;
}
}
}
private static string fileName;
private static int noOfLinesWanted = 10;
private static int noOfCharsWanted = 10 * 80 * 1; //10 lines, 80 chars per line,
//1 ascii char
private static Encoding encoding = Encoding.ASCII;
private static bool loop = true;
}
}
待办事项
我有一些想做的事情
- 从文件中读取一个数据块。这样会更有效率。
- 如果可能的话,使用文件更改事件。
肯定存在一些测试用例会破坏这段代码。我知道,我还没有充分测试它。所以请告诉我这些场景,我希望能尝试修复它。
另外,如果你认为我应该支持某些功能,请告诉我。
更新/修复
- 更新以处理 "
-n
" 和 "-c
" 的无效输入
最后
请评论这篇文章并评分。:)