Dropbox and folderItems / BinaryStreams

I have an app which opens and closes files, writing to them using binary streams. I’m getting reports that when user are working on files inside a DropBox-managed folder that there are frequent nilObjectException errors and other problems. Obviously I should improve my error handling code, but I’m curious : What is DropBox doing that’s causing these problems? Is it just a Xojo issue or a more widespread OS-level problem?

I don’t know of anything offhand, but it’d be interesting to know what you discover when you add additional error handling.

[Unofficial Guess]
When Dropbox receives an update from the server it deletes the local file and makes a new one. This is probably breaking the link created with a FolderItem.

I’ve also seen this behavior with other file sync programs such as Adobe’s. I’ll have to do some testing to see what’s going on here.

If they do “delete & replace” thats quite possibly causing issues

Another thing is that DropBox doesn’t support symlinks.
As an example, try to put your build App in DropBox and look at the size. Now look at the same App on another computer. It’s larger because the symlinks are gone and DropBox made copies of the files instead (and made it impossible to sign).

Ok, I think I see what the problem is. When my app does this sequence of events inside a DropBox folder (Windows 10):

  • Create a folder
  • Copy some files to it
  • Rename the folder
  • Try to create a file within the newly renamed folder

It fails. However if I step through it in the debugger slowly, then it works. I can pretty much see that the Dropbox file changes are happening, but they don’t seem to be happening in real time. So when operating inside a DropBox folder, it’s almost as if file operations are asynchronous.

That’s very, not easy to program for. Hmm.

Dropbox is doing it’s best to keep up, but you’re fiddling with files while it’s trying to sync.

Do all your work in SpecialFolder.Temporary, and move to Dropbox last and only when you’re done.

So, actually this may not be exclusive to dropbox.

Try this code on Windows 10:

  dim f as FolderItem = SpecialFolder.Desktop
  
  dim g as FolderItem = f.child("foo")
  g.CreateAsFolder
  dim g2 as FolderItem = g.child("data")
  dim bs as BinaryStream = BinaryStream.Create(g2)
  dim mb as new MemoryBlock(1024*1024*32)
  bs.write mb
  g.name = "foo2"     
  dim h as FolderItem = g.child("bar")
  h.CreateAsFolder  

While stepping through the debugger, on the line after
g.name=“foo2”
I’m seeing that “g.exists” = false, and g.child(“bar”) returns nil.

However, without the binaryStream copy, it works:

  dim f as FolderItem = SpecialFolder.Desktop
  dim g as FolderItem = f.child("foo")
  g.CreateAsFolder
  g.name = "foo2"     
  dim h as FolderItem = g.child("bar")
  h.CreateAsFolder  

I do still have DropBox installed, but I’m not operating inside the DropBox folder, so I’m not sure what to make of this.

Ok, more testing and it looks like it’s timing dependent, AND may also depend on some caching behavior of the OS.

Here’s a version which seems to fail about 25% of the time when run in C:\users\username\DropBox but usually success when run in C:\Users\username\Desktop

  dim f as folderItem = GetFolderItem("C:\\Users\\username\\Desktop")
  dim g as FolderItem = f.child("foo" + str(rnd*1000,"#") )
  
  g.CreateAsFolder
  
  if TRUE then
    dim g2 as FolderItem = g.child("data")
    dim bs as BinaryStream = BinaryStream.Create(g2)
    dim mb as new MemoryBlock(1024*1024*32)
    bs.write mb
  end if
  
  g.name = g.name+"-renamed"
  
 
  if not g.Exists then
    MsgBox "Failed"
    return
  end if
  
  dim h as FolderItem = g.child("bar")
  h.CreateAsFolder  
  

I can’t recall exactly what/how but I remember having FolderItem Nil issues and using TrueChild/TrueItem solved it for me.

Another odd thing, the Language Reference says that changing FolderItem.Name “will rename files if the user has permission to rename them, they are not in use, and it is not a folder or temporary file. The file must exist in order to be assigned a name.”

I think that’s a documentation error, rather than a true feature limitation.

I know one company which makes a copy to a temp folder for any folder in a dropbox (and similar services).
Because else it may happen that while you work, the file is swapped.

For SQLite this is highly recommended, because if file is updated by dropbox, the SQLite cache would no longer match the file on disk.

After more testing, I’m not able to reliably work around this DropBox issue. I’ve tried combinations of adding delays, re-creating the folderItem when needed, etc., but it seems as if it always manages to fail occasionally.

I think I’m going to do what others have suggested: set my app to do all its complicated work inside a TemporaryFolderItem and only copy to the final DropBox destination folder at the very last step.

As I understand it, Dropbox does sector-by-sector copying and writing, and in the process those sectors may be unreadable by other processes when that is happening. I have a popular app that reads and writes to a shared .xml file, and many of my customers try to put that shared file on Dropbox, but a small percentage of the time the read/write operations fail.

At one point I was hoping to use Dropbox to hold a database file that I would be the only one with write access, while other users would have read access to it, but what I’ve heard about Dropbox would make this a dicey proposition. Your testing seems to bear that out…:frowning: