Best way to close threaded writer and open reader

We write data to a file using a threaded (WAV file) writer, and call flush() on it when done, and immediately open a (WAV file) reader. But sometimes, it seems that maybe the OS hasn’t finished writing and closing the file, so the input file then reports its size as 0, causing our creation of an input stream to fail. What is the safest way to open a file for reading that was just closed for writing? There does not appear to be a way to ask the OS if it’s done flushing and closing. We can get around the problem (in out tests so far) by delaying opening the reader for about a second. But is there some way to ensure it will not fail because of this condition?

Delaying for a second is going to be prone to failure anyway depending on “reasons”.

If there isn’t some sure-fire way of knowing that the OS has finished flushing, then I would approach this by only starting the load back process on successful save (which you’re probably doing anyway), perhaps delaying it by some small value initially, and on each failure backing off that delay time. Once the delay time and/or number of attempts to open the file has reached some value(s) you determine as unreasonable, then you can show a failure message and give up trying to load.

One idea would be to wrap your writer class in a scoped inner code switch point such that it goes out of scope and is therefore destructor’ed before you get to your reading code.

Could be as simple as adding another set of {}'s to force the scope change… but of course this depends on making sure there are no hanging references to anything in the class ..

I think it’s the OS that is not finished with the file. Our code has completed destroying the containing object, so it’s. no longer existing, but the opening for reading says the size is 0, even though the file exists (in Finder) and it says it’s a valid file.

If the object is really destructor’ed long after the flush(), and the file is really properly closed(), this’d be a bug, imho. Although it does appear to be intentional behaviour [0]

I’d urge you to be sure your class object isn’t hanging around somewhere, maybe with a file handle still referencing the file. The {} inner bracing would be the first thing I do, to be absolutely sure that there are no stale references/pointers/handles to the file on the disk.

Which OS and other JUCE details, btw?

[0] - I’m guessing you already saw this comment in juce_FileOutputStream.cpp and are therefore explicitly doing your own flush() prior to deconstruction ..

Destroying a FileOutputStream object does not force the operating system to write the buffered data to disk immediately. If this is required you should call flush() before triggering the destructor.

EDIT: one other thing to think about is whether this is Windows Defender or some other thingy keeping the file handle open longer than expected ..

1 Like

I wonder if this thread has any bearing (particularly the commit made): URL::DownloadTask::Listener::finished is called with file handle still open

The flush() was removed and the FileOutputStream gets reset() instead.