MoveFileTo, failing at times

  1. 3 days ago

    Hi,

    I am new to Xojo. I have to move a number (around 100 to 300) of files stored in a folder to a set of subfolders (around 30 to 60) acording to a certain patern. The files are 250Mb or so in size and my code is the following:

    -----------------------------------------------------------------------
    // ****Move files to subfolders****

    For j = 1 To number_of_stacks

    slice_counter = 0

    For i = j To number_of_files Step number_of_stacks

    slice_counter = slice_counter + 1

    // move file
    source_file = new FolderItem(source_folder +"\" + Format(i, "000000") + ".tif", folderItem.PathTypeNative)

    // to subfolder
    destination_file = new FolderItem (source_folder +"\" + Str(j) + "\"+ Str(slice_counter ) + ".tif", folderItem.PathTypeNative)

    source_file.MoveFileTo(destination_file)

    Next i

    Next j
    -----------------------------------------------------------------------

    If I run the code on exactly the same set of files and subfolders repeated times, the result is the spected one 90% of the time but for an unknown reason, the 10% of the time a file fails to move into its corresponding subfolder.
    I am really stuck with this, any Ideas?

    Thanks for your help!!

    Manuel

  2. Julian S

    Nov 14 Pre-Release Testers, Xojo Pro UK

    It might be a number of reasons, shadowcopy, virus checker, windows defender etc.

    The documentation doesn't say if MoveFileTo raises an error or not if it fails, however it does say that LastErrorCode is changed if an error occurs so I would suggest checking that after your MoveFileTo operation and see if/why it errors.

    See the code at the bottom of :

    https://docs.xojo.com/index.php/FolderItem.LastErrorCode

    I would system.debuglog that or you could have a lot of msgbox's you need to close ;)

  3. Julian,

    Today it seems to fail less often... Anyway, this is what I have found:

    1. MoveFileTo don't seem to throw an error when it fails
    2. destiny_file.LastErrorCode has always a value of 101 (the file was not found) no matter if the move to has been a success or a faliure.
    3. Luckly, Source_file.LastErrorCode takes a value of 104 (the file is in use) when the problem happens.

    Obviously I could try something like:
    -----------------------------------------------------------------
    Do
    source_file.MoveFileTo(destination_file)
    Loop Until Source_file.LastErrorCode = 0
    -----------------------------------------------------------------
    but it would be a very ugly solution.... :(
    Some very similar code was working flawlessly in an old VB6 app of mine. What is really happening? how can I fix it?

    Thanks for your help!!

    Manuel

  4. Julian S

    Nov 14 Pre-Release Testers, Xojo Pro UK

    Yes, Source_file will store the LastErrorCode, sorry I didn't mention that in my post :)

    I doubt that its caused by Xojo or more people would be reporting it (though I may be wrong) but more likely is a 3rd party program locking the file as you try the move.

    Have you tried that VB6 code recently? If you tried the VB6 program a few weeks/month ago things might have changed on your PC in the meantime. Does it definitely work without missing any files?

    Do you have an anti-virus program installed? Have you tried stopping it to test that it's not that?

    If you don't have any luck, run Process Monitor at the same time and see what it happening, it should point out what application is causing the lock on the file that your code is trying to move.

    If you are totally stuck after working through the things above, try the following:

    // https://blog.samphire.net/2017/01/22/windows-to-xojo-data-type-conversion/
    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365239%28v=vs.85%29.aspx
    Declare Function MoveFile Lib "Kernel32.dll" Alias "MoveFileW" (lpExistingFileName As WString, lpNewFileName As WString) As Int32
    Dim result As Int32
    
    // ****Move files to subfolders****
    
    For j = 1 To number_of_stacks
    
    slice_counter = 0
    
    For i = j To number_of_files Step number_of_stacks
    
    slice_counter = slice_counter + 1
    
    // move file 
    //source_file = new FolderItem(source_folder +"\" + Format(i, "000000") + ".tif", folderItem.PathTypeNative)
    
    // to subfolder 
    //destination_file = new FolderItem (source_folder +"\" + Str(j) + "\"+ Str(slice_counter ) + ".tif", folderItem.PathTypeNative)
    
    //source_file.MoveFileTo(destination_file)
    
    result = MoveFile(source_folder +"\" + Format(i, "000000") + ".tif", source_folder +"\" + Str(j) + "\"+ Str(slice_counter ) + ".tif")
    
    Next i
    
    Next j

    This will bypass the FolderItem object, it will be quicker but I don't know by how much (I've not performed speed tests on it).

    Let me know how you get on and which thing fixes the problem, if at all? :)

  5. 2 days ago

    Julian,

    I have tried stopping the AVG antivirus, the MoveFile() Windows function and the VB6 code. Sadly all of them, sooner or later, end up failing to move a file. I see that to detect the error and retry is the only practical [and ugly] solution to the problem as of now.

    Today I will try to learn how to use Process Monitor and see if I can find what is going on...

    Manuel

  6. Some of the things which you should try first:

    1. Try to make demo for doing single file copy and/or moving and see the results;

    2. Try to run app/code as administrator user or as user who have administrator privileges;

    3. Check input values which ur sending to declare function;

  7. Edited 2 days ago

    In old good VB6 you can do moving files in couple of different ways here you go 2 examples

    Name "C:\elpower.log" As "C:\log\elpower.log"
    Option Explicit
    
    'Move all files in a folder to another folder using API
    
    Private Declare Function MoveFile Lib "kernel32.dll" Alias _
    "MoveFileA" (ByVal lpExistingFileName As String, ByVal _
    lpNewFileName As String) As Long
    '
    '
    Private Sub DoMoveFiles()
    ' The original file will no longer exist.
    'Access all files within a folder
        Dim stFile As String
        Dim stDir As String
        Dim myNewDir As String
        Dim retval As Long
        
    ' see if the directory exist and if not make it
        If Dir("C:\Log", vbDirectory) <> "" Then MkDir ("C:\Log")
    
        stDir = "C:\OldLogLocation\"  'old dir
        stFile = Dir$(stDir & "*.txt")  'use all text files from oldloglocation
        myNewDir = "C:\Log\"    ' new dir
    'move the file to your log destination
        Do While stFile <> ""
           retval = MoveFile(sfile, myNewDir)   'move file
           stFile = Dir
        Loop
    End Sub
    
    
    OR 
    
    Private Declare Function MoveFileW Lib "kernel32.dll" (ByVal lpExistingFileName As Long, ByVal lpNewFileName As Long) As Long
    
    Public Function MoveFile(pOldPath As String, pNewPath As String)
    
        MoveFileW StrPtr(pOldPath), StrPtr(pNewPath)
        
    End Function
    
  8. Thanks Bogdan. I am trying to make a minimal app that is yet able to show the problem. As of now I am moving a file out of a folder and then back again into it. After 30 minutes of running, no failure has been detected yet... lets see.

    My old VB6 app was using the statement: Name source_file_path As destiny_file_path that can move and rename a file
    see: https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/name-statement

  9. Also on above list one more thing also which can be issue is filename text encoding - ascii vs unicode vs utf-8 and etc.

  10. I have found that the problem is that I need to wait at least 45 seconds or so just after my 128 files (250Mb each) have been copied to the folder that my Xojo app is watching before it can move them to other locations successfully without errors.
    Is there a way in Xojo to know when the files have been copied and are eady to be moved?
    I have tried "FolderItem.count" but it doesn't seem to work... :(

  11. Julian S

    2 days ago Pre-Release Testers, Xojo Pro UK
    Edited 2 days ago

    @Manuel Franquelo I have tried "FolderItem.count" but it doesn't seem to work...

    This should work remember to point it at the folder, not at a file inside the folder, try:

    Dim f As New FolderItem
    f = SelectFolder
    MsgBox(f.NativePath + " " + Str(f.Count))

    If you have bought MBS plugins, that can do it using WindowsDirectoryWatcherMBS.

    Or you could use the Xojo Windows Functionality Suite which has

    StartWatchingForChangesWFS(extends f as FolderItem, watchSubDirs as Boolean)

    and

    HasChangedWFS(extends f as FolderItem) As Boolean

    which you can poll on a timer to see if something new has appeared in your watch folder.

    Or you could borrow Karen's code (taken from WFS) from https://forum.xojo.com/conversation/post/111418 which returns an array of strings and process that on a timer.

    The only way to check for a lock it to try and open the file for a write, but MoveFileTo will return a similar error so you could just use that instead and try the file a few seconds later on that timer.

    Many options :)

  12. I have ended up checking "moveFileTo" for error and retrying every 10 sec . After all the most obvious way to check if a file can be moved is to try to move it... ;)

or Sign Up to reply!