How do I watch a file for changes?

前端 未结 25 2660
孤街浪徒
孤街浪徒 2020-11-21 07:13

I have a log file being written by another process which I want to watch for changes. Each time a change occurs I\'d like to read the new data in to do some processing on it

相关标签:
25条回答
  • 2020-11-21 07:52

    It should not work on windows (maybe with cygwin ?), but for unix user, you should use the "fcntl" system call. Here is an example in Python. It's mostly the same code if you need to write it in C (same function names)

    import time
    import fcntl
    import os
    import signal
    
    FNAME = "/HOME/TOTO/FILETOWATCH"
    
    def handler(signum, frame):
        print "File %s modified" % (FNAME,)
    
    signal.signal(signal.SIGIO, handler)
    fd = os.open(FNAME,  os.O_RDONLY)
    fcntl.fcntl(fd, fcntl.F_SETSIG, 0)
    fcntl.fcntl(fd, fcntl.F_NOTIFY,
                fcntl.DN_MODIFY | fcntl.DN_CREATE | fcntl.DN_MULTISHOT)
    
    while True:
        time.sleep(10000)
    
    0 讨论(0)
  • 2020-11-21 07:52

    For watching a single file with polling, and minimal dependencies, here is a fully fleshed-out example, based on answer from Deestan (above):

    import os
    import sys 
    import time
    
    class Watcher(object):
        running = True
        refresh_delay_secs = 1
    
        # Constructor
        def __init__(self, watch_file, call_func_on_change=None, *args, **kwargs):
            self._cached_stamp = 0
            self.filename = watch_file
            self.call_func_on_change = call_func_on_change
            self.args = args
            self.kwargs = kwargs
    
        # Look for changes
        def look(self):
            stamp = os.stat(self.filename).st_mtime
            if stamp != self._cached_stamp:
                self._cached_stamp = stamp
                # File has changed, so do something...
                print('File changed')
                if self.call_func_on_change is not None:
                    self.call_func_on_change(*self.args, **self.kwargs)
    
        # Keep watching in a loop        
        def watch(self):
            while self.running: 
                try: 
                    # Look for changes
                    time.sleep(self.refresh_delay_secs) 
                    self.look() 
                except KeyboardInterrupt: 
                    print('\nDone') 
                    break 
                except FileNotFoundError:
                    # Action on file not found
                    pass
                except: 
                    print('Unhandled error: %s' % sys.exc_info()[0])
    
    # Call this function each time a change happens
    def custom_action(text):
        print(text)
    
    watch_file = 'my_file.txt'
    
    # watcher = Watcher(watch_file)  # simple
    watcher = Watcher(watch_file, custom_action, text='yes, changed')  # also call custom action function
    watcher.watch()  # start the watch going
    
    0 讨论(0)
  • 2020-11-21 07:53

    The best and simplest solution is to use pygtail: https://pypi.python.org/pypi/pygtail

    from pygtail import Pygtail
    import sys
    
    while True:
        for line in Pygtail("some.log"):
            sys.stdout.write(line)
    
    0 讨论(0)
  • 2020-11-21 07:56

    Simplest solution for me is using watchdog's tool watchmedo

    From https://pypi.python.org/pypi/watchdog I now have a process that looks up the sql files in a directory and executes them if necessary.

    watchmedo shell-command \
    --patterns="*.sql" \
    --recursive \
    --command='~/Desktop/load_files_into_mysql_database.sh' \
    .
    
    0 讨论(0)
  • 2020-11-21 07:57

    Have you already looked at the documentation available on http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html? If you only need it to work under Windows the 2nd example seems to be exactly what you want (if you exchange the path of the directory with one of the files you want to watch).

    Otherwise, polling will probably be the only really platform-independent option.

    Note: I haven't tried any of these solutions.

    0 讨论(0)
  • 2020-11-21 07:58
    ACTIONS = {
      1 : "Created",
      2 : "Deleted",
      3 : "Updated",
      4 : "Renamed from something",
      5 : "Renamed to something"
    }
    FILE_LIST_DIRECTORY = 0x0001
    
    class myThread (threading.Thread):
        def __init__(self, threadID, fileName, directory, origin):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.fileName = fileName
            self.daemon = True
            self.dir = directory
            self.originalFile = origin
        def run(self):
            startMonitor(self.fileName, self.dir, self.originalFile)
    
    def startMonitor(fileMonitoring,dirPath,originalFile):
        hDir = win32file.CreateFile (
            dirPath,
            FILE_LIST_DIRECTORY,
            win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
            None,
            win32con.OPEN_EXISTING,
            win32con.FILE_FLAG_BACKUP_SEMANTICS,
            None
        )
        # Wait for new data and call ProcessNewData for each new chunk that's
        # written
        while 1:
            # Wait for a change to occur
            results = win32file.ReadDirectoryChangesW (
                hDir,
                1024,
                False,
                win32con.FILE_NOTIFY_CHANGE_LAST_WRITE,
                None,
                None
            )
            # For each change, check to see if it's updating the file we're
            # interested in
            for action, file_M in results:
                full_filename = os.path.join (dirPath, file_M)
                #print file, ACTIONS.get (action, "Unknown")
                if len(full_filename) == len(fileMonitoring) and action == 3:
                    #copy to main file
                    ...
    
    0 讨论(0)
提交回复
热议问题