initial checkin of yaulw (locally)
This commit is contained in:
190
File/Tail.cs
Normal file
190
File/Tail.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Yaulw.File
|
||||
{
|
||||
/// <remarks>
|
||||
/// A File SystemWatcher utility that functions like the infamous unix tail utility,
|
||||
/// with a callback when the file get's created or updated.
|
||||
/// </remarks>
|
||||
public class Tail
|
||||
{
|
||||
#region Public Events
|
||||
|
||||
/// <summary>
|
||||
/// Event Delegate for the Incoming Data Event
|
||||
/// </summary>
|
||||
/// <param name="sender">object reference to the sending Tail Object</param>
|
||||
/// <param name="newData">change data / or full data if bIsNewFile is true</param>
|
||||
/// <param name="bIsNewFile">true if a new file was created</param>
|
||||
public delegate void IncomingDataHandler(object sender, string newData, bool bIsNewFile);
|
||||
|
||||
/// <summary>
|
||||
/// Caller must subscribe to the Incoming Data Event
|
||||
/// </summary>
|
||||
public event IncomingDataHandler IncomingData = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Members
|
||||
|
||||
private string _FileNameNPath = "";
|
||||
private FileSystemWatcher _fileSystemWatcher = null;
|
||||
private long _previousSeekPosition = 0;
|
||||
private object _lockingObj = new Object();
|
||||
private const int MAX_BYTE_TO_READ_IN_ONE_TIME = 1024 * 16;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new Tail Object to monitor the specified file
|
||||
/// </summary>
|
||||
/// <param name="FileNameNPath">File to Monitor with Tail</param>
|
||||
public Tail(string FileNameNPath)
|
||||
{
|
||||
_previousSeekPosition = 0;
|
||||
_FileNameNPath = FileNameNPath;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Start Monitoring the File
|
||||
/// </summary>
|
||||
public void StartMonitoring()
|
||||
{
|
||||
// Get File Information * Setup System Watcher *
|
||||
FileInfo targetFile = new FileInfo(_FileNameNPath);
|
||||
_fileSystemWatcher = new FileSystemWatcher();
|
||||
_fileSystemWatcher.IncludeSubdirectories = false;
|
||||
_fileSystemWatcher.Path = targetFile.DirectoryName;
|
||||
_fileSystemWatcher.Filter = targetFile.Name;
|
||||
_fileSystemWatcher.Created += new FileSystemEventHandler(TargetFile_Created);
|
||||
_fileSystemWatcher.Changed += new FileSystemEventHandler(TargetFile_Changed);
|
||||
|
||||
// Perform an Initial read, if the file exists
|
||||
if (targetFile.Exists)
|
||||
TargetFile_Created(null, null);
|
||||
|
||||
// Start up File System Watcher
|
||||
_fileSystemWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop Monitoring the File
|
||||
/// </summary>
|
||||
/// <param name="bDispose">set to false, if you are running into trouble during a shutdown</param>
|
||||
public void StopMonitoring(bool bDispose = true)
|
||||
{
|
||||
_fileSystemWatcher.EnableRaisingEvents = false;
|
||||
if(bDispose)
|
||||
_fileSystemWatcher.Dispose();
|
||||
_fileSystemWatcher = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To read a file from Beginning to End. Call this function,
|
||||
/// if you want to reset the position counter and start reading again from the beginning.
|
||||
/// </summary>
|
||||
/// <returns>the Contents of the File</returns>
|
||||
public StringBuilder ReadFromBeginningToEndOfFile()
|
||||
{
|
||||
_previousSeekPosition = 0;
|
||||
return ReadFileContentsTillEndStartingFromPreviousSeekPosition();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// Handled File System Watcher's Created Callback
|
||||
/// </summary>
|
||||
/// <param name="source">SystemWatcher object</param>
|
||||
/// <param name="e">SystemWatcher event args</param>
|
||||
private void TargetFile_Created(object source, FileSystemEventArgs e)
|
||||
{
|
||||
// Read the File Contents
|
||||
StringBuilder sb = ReadFromBeginningToEndOfFile();
|
||||
|
||||
//call delegate with the string
|
||||
if (IncomingData != null && sb.Length > 0)
|
||||
IncomingData(this, sb.ToString(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handled File System Watcher's Changed Callback
|
||||
/// </summary>
|
||||
/// <param name="source">SystemWatcher object</param>
|
||||
/// <param name="e">SystemWatcher event args</param>
|
||||
private void TargetFile_Changed(object source, FileSystemEventArgs e)
|
||||
{
|
||||
// File size size changed to less! ~someone must have
|
||||
// changed content inside of it
|
||||
FileInfo targetFile = new FileInfo(_FileNameNPath);
|
||||
bool bIsNew = false;
|
||||
if (targetFile.Length < _previousSeekPosition)
|
||||
{
|
||||
_previousSeekPosition = 0;
|
||||
bIsNew = true;
|
||||
}
|
||||
|
||||
// Read the File Contents
|
||||
StringBuilder sb = ReadFileContentsTillEndStartingFromPreviousSeekPosition();
|
||||
|
||||
//call delegate with the string
|
||||
if(IncomingData != null && sb.Length > 0)
|
||||
IncomingData(this, sb.ToString(), bIsNew);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper Function to read a file from _previousSeekPosition to End.
|
||||
/// </summary>
|
||||
/// <returns>contents of file starting from _previousSeekPosition</returns>
|
||||
private StringBuilder ReadFileContentsTillEndStartingFromPreviousSeekPosition()
|
||||
{
|
||||
lock (_lockingObj)
|
||||
{
|
||||
// Open the file
|
||||
FileStream fs = new FileStream(_FileNameNPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
|
||||
// Read File Contents into a StringBuilder
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool bReadOrContinueReadingFile = true;
|
||||
while (bReadOrContinueReadingFile)
|
||||
{
|
||||
// Position the file
|
||||
_previousSeekPosition = (int)fs.Seek(_previousSeekPosition, SeekOrigin.Begin);
|
||||
|
||||
//read from current seek position to end of file
|
||||
byte[] bytesRead = new byte[MAX_BYTE_TO_READ_IN_ONE_TIME];
|
||||
int numBytes = fs.Read(bytesRead, 0, MAX_BYTE_TO_READ_IN_ONE_TIME);
|
||||
_previousSeekPosition += numBytes;
|
||||
|
||||
// Append Data to the String Builder
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
sb.Append((char)bytesRead[i]);
|
||||
|
||||
// If we have read up to MAX_BYTE_TO_READ_IN_ONE_TIME, then there could be more data...
|
||||
bReadOrContinueReadingFile = (numBytes == MAX_BYTE_TO_READ_IN_ONE_TIME);
|
||||
}
|
||||
|
||||
// Close File
|
||||
fs.Dispose();
|
||||
fs = null;
|
||||
|
||||
// Return SB object
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user