Git Product home page Git Product logo

filewatch's Introduction

Filewatch

Branch Status
Master Master

Single header folder/file watcher in C++11 for windows and linux, with optional regex filtering

Install:

Drop FileWatch.hpp in to your include path, and you should be good to go.

Compiler Support:

Works on:

  • Clang 4 and higher
  • GCC 4.8 and higher
  • Visual Studio 2015 and higher should be supported, however only 2019 is on the ci and tested

Examples:

On linux or none unicode windows change std::wstring for std::string or std::filesystem (boost should work as well).

Simple:
filewatch::FileWatch<std::wstring> watch(
	L"C:/Users/User/Desktop/Watch/Test"s, 
	[](const std::wstring& path, const filewatch::Event change_type) {
		std::wcout << path << L"\n";
	}
);
Change Type:
filewatch::FileWatch<std::wstring> watch(
	L"C:/Users/User/Desktop/Watch/Test"s, 
	[](const std::wstring& path, const filewatch::Event change_type) {
		std::wcout << path << L" : ";
		switch (change_type)
		{
		case filewatch::Event::added:
			std::cout << "The file was added to the directory." << '\n';
			break;
		case filewatch::Event::removed:
			std::cout << "The file was removed from the directory." << '\n';
			break;
		case filewatch::Event::modified:
			std::cout << "The file was modified. This can be a change in the time stamp or attributes." << '\n';
			break;
		case filewatch::Event::renamed_old:
			std::cout << "The file was renamed and this is the old name." << '\n';
			break;
		case filewatch::ChangeType::renamed_new:
			std::cout << "The file was renamed and this is the new name." << '\n';
			break;
		};
	}
);
Regex:

Using the standard regex libary you can filter the file paths that will trigger. When using wstring you will have to use std::wregex

filewatch::FileWatch<std::wstring> watch(
	L"C:/Users/User/Desktop/Watch/Test"s,
	std::wregex(L"test.*"),
	[](const std::wstring& path, const filewatch::Event change_type) {
		std::wcout << path << L"\n";
	}
);
Using std::filesystem:
filewatch::FileWatch<std::filesystem::path> watch(
	L"C:/Users/User/Desktop/Watch/Test"s, 
	[](const std::filesystem::path& path, const filewatch::Event change_type) {
		std::wcout << std::filesystem::absolute(path) << L"\n";		
	}
);
Works with relative paths:
filewatch::FileWatch<std::filesystem::path> watch(
	L"./"s, 
	[](const std::filesystem::path& path, const filewatch::Event change_type) {
		std::wcout << std::filesystem::absolute(path) << L"\n";		
	}
);
Single file watch:
filewatch::FileWatch<std::wstring> watch(
	L"./test.txt"s, 
	[](const std::wstring& path, const filewatch::Event change_type) {
		std::wcout << path << L"\n";		
	}
);

filewatch's People

Contributors

jlbuenolopez avatar leweaver avatar pezcode avatar thomasmonkman avatar thomasmonkmanholition avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

filewatch's Issues

Windows, locked file

Hi, I assume by looking at the type of events that I should be able to edit a file and save it? I'm watching from a dir like:

filewatch::FileWatch<std::string> shaderFolderWatch(
		"../../src/shaders", [](const std::string& file, filewatch::Event event) {
			printf("%s\n", file.c_str());
		}
	);

Looking at the implementation it's exposing the flags to allow other processes to read/write.. Not sure exactly what would the issue be in this case...
This is compiled on VS2019, win10 SDK 10.0.18362.0.
What happens is that my text editor claims that it can't save the file:

Failed to save 'FullScreenTriangle.fs': Unable to write file 'src\shaders\FullScreenTriangle.fs' (Unknown (FileSystemError): Error: EBUSY: resource busy or locked

Seems doesnt work in Windows?

#include <FileWatch.hpp>
#include <iostream>
int main(int argc, char** args) {
	//FileWatch API, see here:
	//https://github.com/ThomasMonkman/filewatch
	std::string FileName ="E:\\233.txt";
	filewatch::FileWatch<std::string>(
		FileName ,
		[](const std::string& path, const filewatch::Event change_type) {
			switch(change_type) {
			case filewatch::Event::added:
				std::cout << "The file was added to the directory." << '\n';
				break;
			case filewatch::Event::removed:
				std::cout << "The file was removed from the directory." << '\n';
				break;
			case filewatch::Event::modified:
				std::cout << "The file was modified. This can be a change in the time stamp or attributes." << '\n';
				break;
			case filewatch::Event::renamed_old:
				std::cout << "The file was renamed and this is the old name." << '\n';
				break;
			case filewatch::Event::renamed_new:
				std::cout << "The file was renamed and this is the new name." << '\n';
				break;
			}
		}
		);
	std::cin.get();
}

This is the code I put in Visual Studio 2017.
But it says cannot cast from initializer list to std::basic_string<char,std::char_traits,std::allocator> (which is the class of std::string) on line 366.

Multiple file modified events fired per file save

Hi,

I'm testing out this nice library in an UE4 setting and noticing that while it is working quite well for add and remove, modified is firing twice whenever I update a file (save it in a text editor). Is this a known thing, or is there some way I can avoid it?

Also, when I add a new file to my watched directory, I see two events: one add and one modified - perhaps this is a hint to the problem. Here is the code I'm testing with in a C++ Actor. Note I'm also printing the current frame, which is sometimes the same for the redundant modified event, sometimes it is a frame later.

// Fill out your copyright notice in the Description page of Project Settings.


#include "FileMonitorTest.h"
#include "./FileWatch.hpp"
#include <string>

#define PRINT_DISPLAY_TIME 3.0f
#define printf(format, ...)                 if (GEngine) GEngine->AddOnScreenDebugMessage(-1, PRINT_DISPLAY_TIME, FColor::White, FString::Printf(TEXT(format), ##__VA_ARGS__), false)

// Sets default values
AFileMonitorTest::AFileMonitorTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

namespace {
const char* watchEventTypeToString( const filewatch::Event change_type )
{
	switch (change_type) {
		case filewatch::Event::added:			return "added";
		case filewatch::Event::removed:			return "removed";
		case filewatch::Event::modified:		return "modified";
		case filewatch::Event::renamed_old:		return "renamed_old";
		case filewatch::Event::renamed_new:		return "renamed_new";
		default: break;
	};

	return "(unknown)";
}
}

// Called when the game starts or when spawned
void AFileMonitorTest::BeginPlay()
{
	Super::BeginPlay();
	
	// we'll add a watcher for file changes in this directory
	std::wstring scanDir( L"E:/epic/Unreal Projects/FileMonitoring/data/scans" );

	IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
	bool dirExists = PlatformFile.DirectoryExists(scanDir.c_str());
	printf("scanDir: %s, exists: %d", scanDir.c_str(), dirExists );

	if( dirExists ) {
		// print out contents of folder using ue4 stuffs
		TArray<FString> fileNames;
		PlatformFile.FindFiles( fileNames, scanDir.c_str(), NULL );
		printf("num files: %d", fileNames.Num() );
		for( int i = 0; i < fileNames.Num(); i++ ) {
			printf( "%s", *fileNames[i] );
		}

		// watch for file changes within scanDir
		static filewatch::FileWatch<std::wstring> watch(
			scanDir, 
			[](const std::wstring& path, const filewatch::Event change_type ) {
				FString changeTypeStr = watchEventTypeToString( change_type );using char* directly prints rubbish
				printf("path: %s, event type: %s, frame: %d", path.c_str(), *changeTypeStr, GFrameNumber );
			}
		);
	}
}

// Called every frame
void AFileMonitorTest::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

warning: unused variable 'listen_filters' [-Wunused-variable]

Hi,

I get the above compiler warning

filewatch/FileWatch.hpp:443:15: warning: unused variable 'listen_filters' [-Wunused-variable]
  443 |    const auto listen_filters = _listen_filters;

The local variable indeed seems to be unused.
Are we good to remove that? Will open a PR if that is correct.

MacOS Support

Great library!

Is there any work being done to support Mac, and if not, would you be willing to accept PRs adding MacOS support?

Filewatch not triggering a command.

I have an issue where occasionally, filewatch will detect a change in file, but will not proceed to perform any action against the change. This happens randomly.

Here’s the entry in the log

2024-04-04 23:42:25 INFO Filter: The match pattern '.mkv' is a match for file Barbie The Pearl Princess (2014)\Barbie The Pearl Princess (2014) {imdb-tt3504064} [WEBDL-1080p][AC3 2.0][h264]-TWA.mkv.
2024-04-04 23:42:26 INFO Filter: The match pattern '
.mkv' is a match for file Barbie The Pearl Princess (2014)\Barbie The Pearl Princess (2014) {imdb-tt3504064} [Bluray-1080p][EAC3 5.1][x265]-iVy.mkv.

if it works, it looks like this

2024-04-04 10:15:26 INFO Filter: The match pattern '*.mp4' is a match for file Godzilla The Planet Eater (2018)\Godzilla The Planet Eater (2018) {imdb-tt8478602} [Bluray-1080p][AC3 5.1][x264]-BHDStudio.mp4.
2024-04-04 10:15:26 INFO Waiting for 30000 milliseconds.
2024-04-04 10:15:57 INFO Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or
2024-04-04 10:15:57 INFO Internet Explorer's first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again.
2024-04-04 10:15:57 INFO At C:\FileWatcher\startscan-movies.ps1:29 char:16
2024-04-04 10:15:57 INFO + $results = Invoke-WebRequest -Uri $plexURI -Method 'GET'
2024-04-04 10:15:57 INFO + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2024-04-04 10:15:57 INFO + CategoryInfo : NotImplemented: (:) [Invoke-WebRequest], NotSupportedException
2024-04-04 10:15:57 INFO + FullyQualifiedErrorId : WebCmdletIEDomNotSupportedException,Microsoft.PowerShell.Commands.InvokeWebRequestComman
2024-04-04 10:15:57 INFO d
2024-04-04 10:15:57 INFO
2024-04-04 10:15:57 INFO The execution 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file C:\FileWatcher\startscan-movies.ps1 "Godzilla The Planet Eater (2018)"' has exited. Exit code: 0.

the xml looks like this

C:\FileWatcher\logs\filewatcher.log 2 5 F:\ServerFolders\data\Media\Audiobooks\Books *.mp3 *.m4b *.m4a Create Change C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file C:\FileWatcher\startscan.ps1 "[path]" 300000 F:\ServerFolders\data\Media\Movies\Network *.mkv *.avi *.m4v *.mp4 Create Change C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file C:\FileWatcher\startscan-movies.ps1 "[path]" 30000

Filewatch fails to build after latest pull-request

Because of the new line add_subdirectory(example) in the main CMakeLists.txt, filewatch fails to build as one of my dependencies. The example's CMakeLists.txt has a target_include_directories(main PRIVATE ${CMAKE_SOURCE_DIR}) that sets some include directory, but when filewatch is included as a library/dependency, this does not add the right directory, and hence main.cpp has a fatal error C1083: Cannot open include file: 'FileWatch.hpp' for me.

Easy fix would be to remove the add_subdirectory(example), or use something else than ${CMAKE_SOURCE_DIR} (maybe ${CMAKE_CURRENT_SOURCE_DIR}?).

build issue on Ubuntu 18.04

filewatch.hpp:460:40: error: cannot convert ‘const wchar_t*’ to ‘const char*’ for argument ‘2’ to ‘int inotify_add_watch(int, const char*, uint32_t)’

ubuntu18.04 + gcc7

Regex

Allow regex filtering of results.

if against single file, check regex is possible, or just completely ignore

Watching Multiple Files

Is it possible to watch multiple files with a single file watcher instance? Files are not in same directory.

Why it doesn't work when be used in another function than main?

Why this works?

int main() 
{
	// App Code
	filewatch::FileWatch<wstring> file_watcher(
		_T(watching_folder),
		[](const std::wstring& path, const filewatch::Event change_type) {
			std::wcout << L"File [ " << path << L" ] -> ";
			switch (change_type)
			{
			case filewatch::Event::added:
				std::cout << "File Added" << '\n';
				break;
			case filewatch::Event::removed:
				std::cout << "File Removed" << '\n';
				break;
			case filewatch::Event::modified:
				std::cout << "File Modified." << '\n';
				break;
			case filewatch::Event::renamed_old:
				std::cout << "Renamed." << '\n';
				break;
			case filewatch::Event::renamed_new:
				std::cout << "Renamed New." << '\n';
				break;
			};
		}
	);
	log("Watching...");
	getchar();
}

And Why this doesn't work??

void fileWatcher() 
{
	// App Code
	filewatch::FileWatch<wstring> file_watcher(
		_T(watching_folder),
		[](const std::wstring& path, const filewatch::Event change_type) {
			std::wcout << L"File [ " << path << L" ] -> ";
			switch (change_type)
			{
			case filewatch::Event::added:
				std::cout << "File Added" << '\n';
				break;
			case filewatch::Event::removed:
				std::cout << "File Removed" << '\n';
				break;
			case filewatch::Event::modified:
				std::cout << "File Modified." << '\n';
				break;
			case filewatch::Event::renamed_old:
				std::cout << "Renamed." << '\n';
				break;
			case filewatch::Event::renamed_new:
				std::cout << "Renamed New." << '\n';
				break;
			};
		}
	);
	log("Watching...");
}

int main() 
{
	fileWatcher();
	getchar();
}

The removed even is not triggered when a folder is deleted.

Having this hierarchy

  • New Folder
    • Inner Folder

when Inner Folder is deleted, the modified event on New Folder is triggered. I believe the "removed" event also should be activated.

filewatch::FileWatch<std::string> watch{"./project",
    [this](const std::filesystem::path& path, const filewatch::Event event) {
        const auto workingPath = AssetManager::ASSET_PATH / path;
        if(std::filesystem::is_directory(workingPath)) {
            std::cout << filewatch::event_to_string(event) << "\n";
        }
    } 
};

It may be because of the folder is already removed: if(std::filesystem::is_directory(workingPath)) at this point. I'm not sure, though.

FileWatch with std::filesystem::path does not compile

OS: Windows
Compiler: MSVC - the latest one, don't know the number

#include <filesystem>
#include <FileWatch.hpp>
#include <iostream>
#include <string>
#include <iostream>

int main()
{
	filewatch::FileWatch<std::filesystem::path> watch(
		"./",
		[](const std::filesystem::path& path, const filewatch::Event change_type) {
		std::cout << path << "\n";
	}
	);

	while (true) {

	}
}

Severity Code Description Project File Line Suppression State
Error C2440 '': cannot convert from 'initializer list' to 'StringType' D:\Projects\Test\filewatch\FileWatch.hpp 741

however this code works:

#include <filesystem>
#include <FileWatch.hpp>
#include <iostream>
#include <string>
#include <iostream>

int main()
{
	filewatch::FileWatch<std::string> watch(
		"./",
		[](const std::filesystem::path& path, const filewatch::Event change_type) {
			std::cout << path << "\n";
		}
	);

	while (true) {

	}
}

example with single file on macOS triggers only remove event

Hi,

The example with '.' directory works as expected on macOS (x86_64), however when changed to a in-directory single text file which is opened with a text editor (sublimetext), the only event triggered is Event::removed even though some text to the file and it was saved.

This is inconsistent with the file watcher behavior when the directory is specified and which works as expected.

How to stop the file watcher?

I want to stop watching a directory, for example i am watching C:\test\someFolder, and i want to stop watching it and start watching C:\another\test

so how could I do it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.