DirectoryContentsList


#1

Hi,

What is the usual way to monitor a given DirectoryContentsList to update my FileListComponent
if something has changed in the shown directory?
Adding a changeListener works if you change i.e. the path of that list
but it doesn’t trigger any change message if I change the content of the
directory of that list i.e. copying a new file into it.

Thank you!
Joerg


#2

Nobody can help?

May I do something wrong in my code but I thought that the thread assigned to the directorylist
should notice a change inside the directory and should raise a flag…

Joerg


#3

I needed something like this some time ago, and i ended using inotify-cxx (i’m on linux).

Probably Julian can come up with some cool cross platform classes that can abstract directory/file change async notification:

  • Linux: inotify (example in this wrapper inotify-cxx)
  • Windows: WaitForSingleObject and FindFirstChangeNotification (simple examples here, but on msdn too)
  • Macosx: FSEvents (sample here)

Probably we can do this while Julian is on holiday so he get something to look at when he’s back !


#4

Thank you kraken,

Thought it was already done in juce :frowning:
I’ll wait for a cross platform solution. I know the windows only way but
went for juce because of cross platform capability.
I hope, Jules will provide something soon.

Thank you!
Joerg


#5

[quote=“kraken”]
Probably we can do this while Julian is on holiday so he get something to look at when he’s back ![/quote]

kraken,

If you are able to help here? I am not really…

Joerg


#6

Any news? I’m also trying to use DirectoryContentsList, but it seems bugged… Once the intial snapshot of directory content is done, fileFindHandle goes to NULL and then following calls to checkNextFile return false with hasChanged unchanged :roll:

It should be something quite simple to fix, should I wait for a next release of Juce, or should I fix it and suggest changes? :?:


#7

That’s how it’s supposed to work - it becomes null to indicate that it’s finished searching for all the files. It’s not designed to keep looking at the folder and watching for changes, you’d need to call refresh() to make it do that.


#8

Hey Julian, what about adding a cross platform class that can abstract directory/file change async notification ?
are you willingly to accept patches in this regard ? all the platforms can support this, but they all do this differently, and sometimes this is very handy.

I can start dig some code, have you an idea on how you would like this kind of class ? i think about a manager with registrable listeners, but you may think something different…


#9

Sure, I’m always happy to accept code! Don’t think a manager would be a good design though - my approach would probably be something like a FileChangeWatcher class that you give a list of files to watch, and which calls its listeners when any of its files change.


#10

Watcher, Manager… that’s the same idea, only name semantics change here :slight_smile:

what about a FileChangeWatcher in which you register one or more FileChangeEvent (which file/dir and which kind of operation to watch… delete, change, add, chmod) and a list of FileChangeListeners that listen to that event specifically ? Well probably it’s better to specify only which files to monitor… it makes sense to also specify the event of the change ?


#11

Sort of… but a “manager” implies that you might use it as a singleton. I think this would work better if you created local watcher objects for particular files or small sets of files, rather than having a singleton.


#12

Sort of… but a “manager” implies that you might use it as a singleton. I think this would work better if you created local watcher objects for particular files or small sets of files, rather than having a singleton.[/quote]

yes that sound sensible


#13

Hey i got code for this running on linux and windows, but i for mac i need some folk to test what i worked out from Apple reference of FSevent API.
i’ve coded it blindly (it was better than trying to start xcode on my G4 !!) so i don’t know if it will even compile straight away.

For now the class is only 2 files with all the platform specific code inside (to ease testing), but probably we should make an own specific platform file after we work out all the lacking code for the mac.

On linux it uses inotify (tha powa!!) and a thread that poll a file descriptor with a specific timeout. Fast and slick to write and test.

On windows i used ReadDirectoryChangeW that is the only way to know which file is changed, as FindFirstChangeNotification works only for folders and you don’t know exactly what changed inside them. Actually this limitation forces you to monitor the whole parent directory when you want to be notified of a single file change, and check if any of the changes you have in that directory is actually one of the files you want to be notified.
Anyway It uses asynchronous IO with OVERLAPPED read / write (it took me some gray hairs before getting it to work!), so we achieve a similar approach to the linux file descriptor based implementation.

The mac code is a starting point only, it create a stream and teach it to monitor a set of files, then a callback will be triggered. From what i read in the docs, there is no way to add files to the stream unless you stop and start a new stream, but probably this has to be tested and tweaked.

This class is pretty simple but powerful to use. An example:

class MyClass : public FileChangeListener
{
    FileChangeWatcher* watcher;

public:

    MyClass()
    {
        watcher = new FileChangeWatcher();
        watcher->addFile (File ("/home/kraken/Desktop/"));
        watcher->addListener (this);
        watcher->start();
    }

    void fileChangedCallback(const File& file)
    {
        std::cout << "File " << file.getFullPathName().toUTF8() << " has changed !" << std::endl;
    }
};

#14

Cool, thanks, I’ll take a look asap.

For the mac, I’d have thought you’d want to use posix calls similar to linux, or cocoa calls. The old FSEvent stuff is deprecated, so not a good choice!


#15

There was a cocoa file watching API released with 10.5 or so, I seem to remember. Never used it, but it exists. Probably came along with Time Machine or something.

Bruce


#16

or by using kqueue ? QFilesystemWatcher of the QT framework has one implementation:

http://www.koders.com/cpp/fidA6FDFC1CAF84BD5C42323BEB4ED522C5B28E86CD.aspx?s=mdef%3Ainsert

Probably worth a check !


#17

Yes, sounds like kqueue is the way to do it on BSD.

Seems a shame to have to use a thread to monitor the file - I expected the OS functions to at least provide some sort of callback. If you’re going to run a thread, it seems like you might as well just write a cross-platform loop that watches the file’s modification time, rather than messing about with these obscure OS functions. Or write a Timer that checks it, and avoid the overhead of having an extra thread. Seems like the only advantage of the kqueue stuff is that your thread is woken immediately when it changes, rather than waiting a few ms until the next time you check it…


#18

well, those obscure functions typically wait on the events, if there is no events, then no signal on that thread. the only drawback in windows is that you need to monitor each directory individually, so the wait on a directory change should timeout to allow other directory to check for their state too, unless you monitor a complete filesystem.

probably polling on the stat of those files you want to check could be generally enough, but does this work if something change inside a directory ?


#19

I think it’s the opposite. For what I’ve understood so far about inotify et al, is that they are here to avoid exactly this.
Please notice that file modification time is unreliable as, for example a file archiver will restore archive’s initial time.
Also, you can’t monitor “being read” file with such loop (so for example, if I want to make sure I can delete a file in Windows, I can’t use such FileChangeWatcher).

I don’t know about Mac, but on linux, you already have a main loop using select. It’s probably not hard to add the epoll file descriptor in there too, so you don’t go for (CPU consuming) timeout based iteration.
If I remember correctly, under Windows, you’ve a limit on the number of object you can monitor at a time with MsgWaitForMultipleObjects, but that’s the function to look for in MSDN. Again, please reuse the message dispatch loop for this as file event don’t happen often compared to all other message, so creating a thread is overkill here.

In FreeBSD, kqueue works like epoll, so the same code might fix both system.


#20

Is there any progress on this?

I would really like to see something like QFileSystemWatcher for JUCE.

I am about to move forward with the Timer solution mentioned by Jules unless somebody sugests something else (mainly because it’s easy, and I don’t mind a little delay).