In this article we will see how to detect file changes using Python.
There are plenty of daily programming scenarios where we need to monitor file changes. Recently I was in a situation which called for a way to detect file updates. WatchDog was an obvious solution to my problem. But because it fired multiple events on a single update I decided to write my own code.
In this article we will write a class called FileModificationHandler. This class will allow us to execute a callback when someone changes the file. So let’s start the coding process.
Start your Python IDE
First start your favorite IDE. For me that would be PyCharm.
Create a new Python File called FileModificationHandler.py
This class will host all of the code related to file change detection process. So let’s start by importing the libraries we are going to be using:
import os import time import traceback
Then we declare the class with it’s constructor like so:
class FileModified(): def __init__(self, file_path, callback): self.file_path = file_path self.callback = callback self.modifiedOn = os.path.getmtime(file_path)
The class has two mandatory parameters. A file path pointing to the file we will be monitoring, and a callback. A callback is simply a function. In Python, functions are just more objects, and so we can pass them around as arguments.
This function is provided by the consumer of the class. A file change will invoke this callback. Thus, notifying the consumer about the change. This way the consumer may process the event accordingly.
Detect File Changes
In this next section we will implement the file monitoring code.
def start(self): try: while (True): time.sleep(0.5) modified = os.path.getmtime(self.file_path) if modified != self.modifiedOn: self.modifiedOn = modified if self.callback(): break except Exception as e: print(traceback.format_exc())
First we will create an infinite while loop. As long as the script is running, it will check for file updates. The OS module in Python provides functions for interacting with the operating system. The OS module contains a sub module called path. What we are looking for is the getmtime method. This method is used to get the last time of last modification of the specified path. It returns a floating point value. This value represents the number of seconds since the epoch.
As you can imagine, if this value is different on the next check then we can comfortably fire the callback, because the file has changed. I must mention that the callback in my example is actually a predicate. A predicate is nothing more then a function returning True or False. This way I allow the consumer to control the flow of the process. If the predicate returns a True value then we are breaking out of the infinite while cycle. In other words, we stop the file monitoring process.
This may be valuable when we want to detect the first three changes to a file, for example. But, as long as the predicate returns False the file monitoring process will continue.
There is one more caveat I want to mention. As you can see we do suspend the running thread by using time.sleep(0.5) for a half a second. This statement allows other threads to receive control over the CPU.
Detecting File Changes
To detect file changes we must first instantiate an object of our FileModifiedHandler class. But, before we do that we must import that class
from FileModificationHandler import FileModified
Then we need to define our callback function
def file_modified(): print("File Modified!") return False
Remember the callback is a predicate which means that it needs to return True or False. If for some reason you would like to stop monitoring the file, just return True.
For the purposes of this demo I will simply write “File Modified!” to the console and continue the file monitoring process until the script is terminated.
Now let’s create an instance of out FileModified class like so:
fileModifiedHandler = FileModified(r"test file.txt",file_modified)
Where “test file.txt” is just a text file I have placed inside my script folder. We will detect file changes on that particular path.
Finally, let’s start the process by invoking the start method
This is the code listing in my PyCharm IDE:
So every time I make a change on the “test file.txt” I get notified that the file is updated and a appropriate message is printed in the output window.