FileSystemWatcher not firing upon text file change and how to get appended lines into panel - filesystemwatcher

I'm after some help or guidance if possible.
I'm trying to monitor a text file in real time and copy the appended text into panel within windows forms.
The text file is being updated via an exe file so it might be few lines appended in quick sessions or nothing for few minutes.
I have tried FileSystemWatcher but it does not seem to work which I cannot understand and also I'm very new to this event handlers etc and still learning in progress :(
private FileSystemWatcher watcher = new FileSystemWatcher();
public async void StandardOutputHandler(object sender, DataReceivedEventArgs outLine)
{
if (outLine.Data != null && !String.IsNullOrWhiteSpace(outLine.Data)) //checks if line coming from CMD is blank or empty
{
// check if cmd output was redirected into a log file
if (outLine.Data.Contains(">>"))
{
BeginInvoke(new MethodInvoker(() =>
{
//get log path and name
string[] commandLine = outLine.Data.Split('>');
this.logFileFullPath = commandLine[3];
this.logFileFullPath = this.logFileFullPath.Replace('"', ' ').Trim();
string[] split = logFileFullPath.Split('\\');
this.logFileName = split[6];
this.path = split[0] + "\\" + split[1] + "\\" + split[2] + "\\" + split[3] + "\\" + split[4] + "\\" + split[5];
//// Create a new FileSystemWatcher and set its properties.
watcher.Path = this.path + "\\";
watcher.Filter = this.logFileName;
//watch for changes to a a log file
watcher.NotifyFilter = (NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.LastAccess | NotifyFilters.CreationTime);
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
// Begin watching.
watcher.EnableRaisingEvents = true;
}));
}
}
// Define the event handlers.
private void OnChanged(object source, FileSystemEventArgs e)
{
MessageBox.Show("Im here");// not showing
//how to copy appended lines into panel??
}
The message box in OnChanged method is not coming up. I have manually amended the file or delete it and create it but the event is not being fired.
I believe this might be related to file being used by another process which in this case is an exe file updating it when necessary. Also, I think, the risk is that I might get only partial text if exe updates the log at the same time as I read the appended lines.
Is there a better way to monitor the text file updates and copy the content onto the panel within GUI application??
UPDATE:
I have moved the code into click event or initial method and it makes no difference. Message box is not appearing
public BatchRun()
{
InitializeComponent();
watcher.Path = "C:\\Test\\Projects\\99999\\Logs";
watcher.Filter = "*.log";
watcher.NotifyFilter = (NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.LastAccess | NotifyFilters.CreationTime);
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}

It seems that you only begin watching the file in the call to StandardOutputHandler.
If this method is only called after writing to the file, then the watcher won't notice any changes to the file.
You probably want to have all the code in your MethodInvoker action somewhere it is called when the application starts (or at least when it needs to monitor the file).
Then in your OnChanged method you may have to invoke MessageBox.Show() on the UI thread.

Related

Kotlin use variable used in a while loop

I want to use a function in loop condition and reuse it in the loop, like this code in Java, but I want it in kotlin :
while ( (data = in.readLine()) != null ) {
System.out.println("\r\nMessage from " + clientAddress + ": " + data);
}
I tried copying this code in android studio to automatically convert to Kotlin and the code looks like this :
while (reader.readLine().also { line = it } != null) {
Log.d("Line", line)
lines.add(line)
}
So I managed to get the lines with var line = "" before the loop, but the loop doesn't stop when the reader is done getting the message sent from the socket.
My wish is to send 2 messages through the socket, so I try to get all lines of one message, and when the second one arrives, I have to clear my lines variable to get the next message, but I can't.
Thanks !
You can use reader.lineSequence() function:
reader.lineSequence().forEach {
Log.d("Line", it)
lines.add(it)
}
Or as suggested in documentation, you can improve it by using File.useLines() which automatically closes the File reader so you don't have to do it manually

It takes to long to stop VlcMediaPlayer

I have a simple WPF application. The application records an RTSP stream to a file. For this purpose Vlc.DotNet library is used.
I have tested the application with two computers and the results are the same for both.
The application code is given below.
public partial class MainWindow : Window
{
private IPath _pathWrapper;
private IDirectoryInfo _vlcLibDirectory;
private VlcMediaPlayer _videoRecorder;
public MainWindow()
{
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
if (_videoRecorder != null && _videoRecorder.IsPlaying())
{
_videoRecorder.Stop();
Button.Background = Brushes.Blue;
_videoRecorder = null;
return;
}
string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
_pathWrapper = new PathWrap();
_vlcLibDirectory = new DirectoryInfoWrap(_pathWrapper.Combine(currentDirectory, "libvlc", IntPtr.Size == 4 ? "win-x86" : "win-x64"));
var options = new string[]
{
"--file-logging",
"--logfile=OnvifVideoRecording.log",
"-vvv"
};
_videoRecorder = new VlcMediaPlayer(_vlcLibDirectory.DirectoryInfo, options);
//string fileDestination = "\\\\\\BuildSrv\\Videos\\A, A, 1\\test.mp4";
string fileDestination = #"D:\Media\Video\A, A, 1\test.mp4";
if (File.Exists(fileDestination))
{
File.Delete(fileDestination);
}
string[] mediaOptions =
{
":sout=#file{dst='" + fileDestination + "'}",
":sout-keep"
};
_videoRecorder.SetMedia("rtsp://192.168.1.110:5504/channel=0,stream=0", mediaOptions);
_videoRecorder.Play();
Button.Background = Brushes.Red;
}
}
The application has a window. The window has a button. When this button is pressed for the first time, recording a video file is started and the button turns red. I usually record video files for 10 minutes. When the button is pressed for the second time, recording a video file is stopped and the button turns blue.
If I record a file to the local destination (to the same computer where the program is run, for example, D:\Media\Video\A, A, 1\test.mp4), everything is ok. Recording video file is started and stopped quickly, almost immediately.
The problems occur when I try to record a file to the remote computer (for example, \BuildSrv\Videos\A, A, 1\test.mp4). Recording a video file starts immediately. However, _videoRecorder.Stop() takes approximately 30 seconds – 1 minute. Resource monitor shows very high network use (90% in case of one computer and 100% in case of another) after the button is pressed for the second time (recording video is stopped). The longer the recorded video file is, the more time is needed to stop VlcMediaPlayer.
Why does stopping VlcMediaPlayer takes so much time in case of recording an RTSP stream to the remote computer? Can this problem be solved somehow?

Building a Handler to Log over SFTP

I'm attempting to build a Handler to perform a put operation with every logging event on a log file over Sftp. Currently, I've built a new logger in line of my Groovy script that uses an SftpConnector artifact's ChannelSftp to perform a put and append to a log file. When I run my code I receive an error message saying it's an Invalid Type=105. If I append to a string and at the end of my script upload the strings contents to my log file then there are no issues. I'm guessing that the error I'm receiving is due to multiple put operations on the same file in rapid secession?
def LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)
def handler = new Handler() {
///String outputBuffer
#Override
void publish(LogRecord record) {
ProgressMonitor monitor = new ProgressMonitor()
String aRecord = new SimpleDateFormat("MMM dd, YYYY hh:mm:ss aaa").format(new Date()).toString() + " " + record.level.toString() + ":" + " " + record.message.toString()
def stream = IOUtils.toInputStream(aRecord,"UTF-8")
connector.getChannelSftp().put(stream ,props.getProperty("sftp.log"),monitor,2)
while(!monitor.isFinished()){
//just pause until logging is done.
}
stream.close()
//outputBuffer = outputBuffer + new SimpleDateFormat("MMM dd, YYYY hh:mm:ss aaa").format(new Date()).toString() + " " + record.level.toString() + ":" + " " + record.message.toString() + "\n"
}
#Override
void flush() {
}
#Override
void close() throws SecurityException {
}
void push(){
connector.getChannelSftp().put(IOUtils.toInputStream(outputBuffer, "UTF-8"),
props.getProperty("sftp.log"), 2)
connector.getChannelSftp().put(IOUtils.toInputStream('\n'),
props.getProperty("sftp.log"),2)
}
}
//SftpHandler handler = new SftpHandler(props)
//def handler = new FileHandler(new
File(props.getProperty("log.location")).absolutePath, true) //provides a writer for log file.
handler.setFormatter(new SimpleFormatter()) //defines the logger file
format. must be declared
LOG.addHandler(handler) //adding the handler.
I figured out the problem:
When attempting a put on the open ChannelSftp it works fine so long as the previous put operation has completed. If there are multiple puts on the same channel over the same session the server will execute and lock the file.
The way to get around this is to open a new channel, execute the put, and close the channel after inside the custom handler. Each put command is executed over a different session and will be queued if the file is locked rather than simply rejected.

Extracting attachments from lotus notes api using EmbeddedObject, Creating eo*tm file in system folder

I am trying to extract attachments using EmbeddedObjects, I am able to extract attachments but create em*tm temp files in system temp folder.
EmbeddedObject embeddedObject=document.getAttachment(attachmentName);
InputStream inputStream=embeddedObject.getInputStream();
.....
......
inputStream.close();
embeddedObject..recycle();
document..recycle();
After closing input Stream its not deleting temp file form system temp folder.
Is it any thing wrong in my code or its setting issue with lotus notes.
Can you please help me in this?
Thanks for the help.
This is a common issue, and it relates to the incorrect closure/recycle of objects (either missing or out of sequence). E0*TM files will be created while the objects are alive and cleaned up when recycled.
If they are correct then check to see if any Antivirus software running that is blocking deletion.
The following sample code I used to test this before works, so compare to yours.
try {
System.out.println("Start");
String path = "test.txt";
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
System.out.println("Get DB");
Database db = session.getCurrentDatabase();
System.out.println("View + doc");
View vw = db.getView("main");
Document doc = vw.getFirstDocument();
System.out.println("Embedded object");
EmbeddedObject att = doc.getAttachment(path);
InputStream is = att.getInputStream();
ByteArrayOutputStream fos = new ByteArrayOutputStream();
byte buffer[] = new byte[(int) att.getFileSize()];
int read;
do {
read = is.read(buffer, 0, buffer.length);
if (read > 0) {
fos.write(buffer, 0, read);
}
} while (read > -1);
fos.close();
is.close();
// recycle the domino variables
doc.recycle();
vw.recycle();
db.recycle();
att.recycle();
} catch (Exception e) {
e.printStackTrace();
}
My suggestion would be to first comment out all the code that you represented in your post as
.....
......
Does the temp file still get left behind? If so, it looks like it's a bug in the Notes back end classes for 8.x that needs to be reported to IBM.
If not, then something in the commented-out code is preventing the the close() call from succeeding. InputStream is an abstract class, so perhaps you are binding inputStream to another type of stream object that must be closed in order to prevent the file from staying open.

How do I tell my C# application to close a file it has open in a FileInfo object or possibly Bitmap object?

So I was writing a quick application to sort my wallpapers neatly into folders according to aspect ratio. Everything is going smoothly until I try to actually move the files (using FileInfo.MoveTo()). The application throws an exception:
System.IO.IOException
The process cannot access the file because it is being used by another process.
The only problem is, there is no other process running on my computer that has that particular file open. I thought perhaps that because of the way I was using the file, perhaps some internal system subroutine on a different thread or something has the file open when I try to move it. Sure enough, a few lines above that, I set a property that calls an event that opens the file for reading. I'm assuming at least some of that happens asynchronously. Is there anyway to make it run synchronously? I must change that property or rewrite much of the code.
Here are some relevant bits of code, please forgive the crappy Visual C# default names for things, this isn't really a release quality piece of software yet:
private void button1_Click(object sender, EventArgs e)
{
for (uint i = 0; i < filebox.Items.Count; i++)
{
if (!filebox.GetItemChecked((int)i)) continue;
//This calls the selectedIndexChanged event to change the 'selectedImg' variable
filebox.SelectedIndex = (int)i;
if (selectedImg == null) continue;
Size imgAspect = getImgAspect(selectedImg);
//This is gonna be hella hardcoded for now
//In the future this should be changed to be generic
//and use some kind of setting schema to determine
//the sort/filter results
FileInfo file = ((FileInfo)filebox.SelectedItem);
if (imgAspect.Width == 8 && imgAspect.Height == 5)
{
finalOut = outPath + "\\8x5\\" + file.Name;
}
else if (imgAspect.Width == 5 && imgAspect.Height == 4)
{
finalOut = outPath + "\\5x4\\" + file.Name;
}
else
{
finalOut = outPath + "\\Other\\" + file.Name;
}
//Me trying to tell C# to close the file
selectedImg.Dispose();
previewer.Image = null;
//This is where the exception is thrown
file.MoveTo(finalOut);
}
}
//The suspected event handler
private void filebox_SelectedIndexChanged(object sender, EventArgs e)
{
FileInfo selected;
if (filebox.SelectedIndex >= filebox.Items.Count || filebox.SelectedIndex < 0) return;
selected = (FileInfo)filebox.Items[filebox.SelectedIndex];
try
{
//The suspected line of code
selectedImg = new Bitmap((Stream)selected.OpenRead());
}
catch (Exception) { selectedImg = null; }
if (selectedImg != null)
previewer.Image = ResizeImage(selectedImg, previewer.Size);
else
previewer.Image = null;
}
I have a long-fix in mind (that's probably more efficient anyway) but it presents more problems still :/
Any help would be greatly appreciated.
Since you are using your selectedImg as a Class scoped variable it is keeping a lock on the File while the Bitmap is open. I would use an using statement and then Clone the Bitmap into the variable you are using this will release the lock that Bitmap is keeping on the file.
Something like this.
using ( Bitmap img = new Bitmap((Stream)selected.OpenRead()))
{
selectedImg = (Bitmap)img.Clone();
}
New answer:
I looked at the line where you do an OpenRead(). Clearly, this locks your file. It would be better to provide the file path instead of an stream, because you can't dispose your stream since bitmap would become erroneous.
Another thing I'm looking in your code which could be a bad practice is binding to FileInfo. Better create a data-transfer object/value object and bind to a collection of this type - some object which has the properties you need to show in your control -. That would help in order to avoid file locks.
In the other hand, you can do some trick: why don't you show streched to screen resolution images compressing them so image size would be extremly lower than actual ones and you provide a button called "Show in HQ"? That should solve the problem of preloading HD images. When the user clicks "Show in HQ" button, loads that image in memory, and when this is closed, it gets disposed.
It's ok for you?
If I'm not wrong, FileInfo doesn't block any file. You're not opening it but reading its metadata.
In the other hand, if you application shows images, you should move to memory visible ones and load them to your form from a memory stream.
That's reasonable because you can open a file stream, read its bytes and move them to a memory stream, leaving the lock against that file.
NOTE: This solution is fine for not so large images... Let me know if you're working with HD images.
using(selectedImg = new Bitmap((Stream)selected))
Will that do it?

Resources