pythonpython-3.xoopwatchdogpython-watchdog

How to create a copy of a file after observing the event using File Listener (watchdog) in Python?


I have below code which is listening to any excel file in one my directory. Below code is working file. However, I would like to modify the code such that as soon as new file arrives in the path it creates a copy of the same file in another folder. Let's say folder name is "today". I am not sure how to create a copy of same file as soon as new event is observed ? The copied file should be of same extension. In this case it will be excel

I am new to OOP so any help is much appreciated!

from watchdog.observers import Observer  
from watchdog.events import PatternMatchingEventHandler
import time

class FileWatcher(PatternMatchingEventHandler):
    patterns = ["*.xlsx"] 

    def process(self, event):
        
       # event.src_path will be the full file path
       # event.event_type will be 'created', 'moved', etc.
       print('{} observed on {}'.format(event.event_type, event.src_path))

    def on_created(self, event):
        self.process(event)

if __name__ == '__main__':
    obs = Observer() 
    obs.schedule(FileWatcher(), path='path/')
    print("Monitoring started....")
    obs.start() # Start watching

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        ob.stop()

    obs.join()

Solution

  • Not sure why this is a problem. But if I understand correctly, you only need to

    import os, shutil
    

    and in

    def on_created(self, event):
        self.process(event)
        destination = os.path.join(os.getcwd(), 'today', event.src_path.split('\\')[-1])
        shutil.copyfile(event.src_path, destination)
    

    if you want "today" to be a subfolder of your curernt script's working directory. If not set the path to something else

    UPDATE

    Problem 1: Pausing the watchdog, wasn't so hard. It queues consequtive triggers (Events) and executes them

    Problem 2: The trigger is executed, when the file is created. That doesn't mean the OS is finished writing it, hence the I/O Exception when trying to access / copy it. You have to wait for the file to be completely written. The EventHandler has no means of telling, so you have to implement a workaround. I have added the code below, that should do the trick.

    from watchdog.observers import Observer  
    from watchdog.events import PatternMatchingEventHandler
    import time, os, shutil
    
    class FileWatcher(PatternMatchingEventHandler):
        patterns = ["*.xlsx"] 
    
       def process(self, event):
            
            # event.src_path will be the full file path
            # event.event_type will be 'created', 'moved', etc.
            print('{} observed on {}'.format(event.event_type, event.src_path))
    
        def on_created(self, event):
            self._is_paused = True
            
            # WAITING FOR FILE TRANSFER
            file = None
            while file is None:
                try:
                    file = open(event.src_path)
                except OSError:
                    file = None                    
                    time.sleep(1) # WAITING FOR FILE TRANSFER
                    continue
            
            self.process(event)
            destination = os.path.join(os.getcwd(), 'today', event.src_path.split('\\')[-1])
            shutil.copyfile(event.src_path, destination)        
            self._is_paused = False
    
    if __name__ == '__main__':
        
        obs = Observer() 
        obs.schedule(FileWatcher(), path='.\\')
        print("Monitoring started....")
        obs.start() # Start watching
    
        try:
            while obs.isAlive():
                obs.join()
        finally:
            obs.stop()
            obs.join()