5

I am new to VBA (and have only a bit of training in java), but assembled this bit of code with the help of other posts here and have hit a wall.

I am trying to write code that will cycle through each file in a folder, testing if each file meets certain criteria. If criteria are met, the file names should be edited, overwriting (or deleting prior) any existing files with the same name. Copies of these newly renamed files should then be copied to a different folder. I believe I'm very close, but my code refuses to cycle through all files and/or crashes Excel when it is run. Help please? :-)

Sub RenameImages()

Const FILEPATH As String = _
"C:\\CurrentPath"
Const NEWPATH As String = _
"C:\\AditionalPath"


Dim strfile As String
Dim freplace As String
Dim fprefix As String
Dim fsuffix As String
Dim propfname As String

Dim FileExistsbol As Boolean

Dim fso As Object
Set fso = VBA.CreateObject("Scripting.FileSystemObject")

strfile = Dir(FILEPATH)

Do While (strfile <> "")
  Debug.Print strfile
  If Mid$(strfile, 4, 1) = "_" Then
    fprefix = Left$(strfile, 3)
    fsuffix = Right$(strfile, 5)
    freplace = "Page"
    propfname = FILEPATH & fprefix & freplace & fsuffix
    FileExistsbol = FileExists(propfname)
      If FileExistsbol Then
      Kill propfname
      End If
    Name FILEPATH & strfile As propfname
    'fso.CopyFile(FILEPATH & propfname, NEWPATH & propfname, True)
  End If

  strfile = Dir(FILEPATH)

Loop

End Sub

If it's helpful, the file names start as ABC_mm_dd_hh_Page_#.jpg and the goal is to cut them down to ABCPage#.jpg

Thanks SO much!

Joe K
  • 85
  • 1
  • 1
  • 9
  • 2
    I think it's a good idea to first collect all of the filenames in an array or collection before starting to process them, particularly if you're going to be renaming them. If you don't there's no guarantee you won't confuse Dir(), leading it to skip files or process the "same" file twice. Also in VBA there's no need to escape backslashes in strings. – Tim Williams Nov 09 '14 at 02:43
  • Thanks Tim! I'm not sure how to do that in VBA, but I think what you're saying makes intuitive sense based on my minimal knowledge of java. I will try that if I can't get my current code working. Any chance you can easily provide assistance with creating the array the way you're talking about? – Joe K Nov 13 '14 at 18:11

3 Answers3

3

EDIT: See update below for an alternative solution.

Your code has one major problem.. The last line before the Loop end is

   ...
   strfile = Dir(FILEPATH)  'This will always return the same filename

Loop
...

Here is what your code should be:

   ...
   strfile = Dir()  'This means: get the next file in the same folder

Loop
...

The fist time you call Dir(), you should specify a path to list files, so before you entered the loop, the line:

strfile = Dir(FILEPATH)

is good. The function will return the first file that matches the criteria in that folder. Once you have finished processing the file, and you want to move to the next file, you should call Dir() without specifying a parameter to indicate that you are interested in iterating to the next file.

=======

As an alternative solution, you can use the FileSystemObject class provided to VBA instead of creating an object by the operating system.

First, add the "Microsoft Scripting Runtime" library by going to Tools->References->Microsoft Scripting Runtime

enter image description here enter image description here

In case, you did not see [Microsoft Scripting Runtime] listed, just browse to C:\windows\system32\scrrun.dll and that should do the same.

Second, change your code to utilize the referenced library as follows:

The following two lines:

Dim fso As Object
Set fso = VBA.CreateObject("Scripting.FileSystemObject")

should be replaced by this single line:

Dim fso As New FileSystemObject

Now run your code. If you still face an error, at least this time, the error should have more details about its origin, unlike the generic one provided by the vague object from before.

Ahmad
  • 12,336
  • 6
  • 48
  • 88
  • Thanks Ahmad! Unfortunately though what you've said makes sense and I've actually tried it before, I get the following error message, with the aforementioned line highlighted as the problem code: "Run-Time Error 5': Invalid Procedure call or argument" Suggestions? – Joe K Nov 13 '14 at 18:08
  • @JoeK so you get this error on the same line? the `dir()` with no parameters? – Ahmad Nov 15 '14 at 07:33
  • @JoeK I have updated my answer. Please check and let me know. – Ahmad Nov 17 '14 at 07:51
3

I think it's a good idea to first collect all of the filenames in an array or collection before starting to process them, particularly if you're going to be renaming them. If you don't there's no guarantee you won't confuse Dir(), leading it to skip files or process the "same" file twice. Also in VBA there's no need to escape backslashes in strings.

Here's an example using a collection:

Sub Tester()

    Dim fls, f

    Set fls = GetFiles("D:\Analysis\", "*.xls*")
    For Each f In fls
        Debug.Print f
    Next f

End Sub



Function GetFiles(path As String, Optional pattern As String = "") As Collection
    Dim rv As New Collection, f
    If Right(path, 1) <> "\" Then path = path & "\"
    f = Dir(path & pattern)
    Do While Len(f) > 0
        rv.Add path & f
        f = Dir() 'no parameter
    Loop
    Set GetFiles = rv
End Function
Tim Williams
  • 154,628
  • 8
  • 97
  • 125
  • Hmm ok I think I can make sense of most of this, with the exception of the "pattern" variable. Can you clarify this for me? I don't even understand why it exists. Thanks so much! – Joe K Nov 17 '14 at 00:56
  • 2
    Dir() takes a string with a path to the location where you want it to look for items, and that string can optionally include a pattern (which can use wildcards) to describe the filenames/types you want to list. In this case were passing "*.xls*" which matches any file name with extension .xls, .xlsx, .xlsm etc. If you don't pass a value for `pattern` it will return all files in `path` location. – Tim Williams Nov 17 '14 at 02:37
  • Thanks so much! It took me a bit to figure it out, but I think I got my code working with your help/suggestions! I'm sure Ahmad's tips would've worked, but this seemed like the "right" way to do it and I have to be able to distribute this code amongst my coworkers, so thank you! ~Joe – Joe K Dec 01 '14 at 23:15
1

In case anyone is wondering, here is my finished code. Thanks to Tim and Ahmad for their help!

Sub RenameImages()

Const FILEPATH As String = "C:\CurrentFilepath\"
Const NEWPATH As String = "C:\NewFilepath\"


Dim strfile As String
Dim freplace As String
Dim fprefix As String
Dim fsuffix As String
Dim propfname As String
Dim fls, f

Set fls = GetFiles(FILEPATH)
For Each f In fls
    Debug.Print f
    strfile = Dir(f)
      If Mid$(strfile, 4, 1) = "_" Then
        fprefix = Left$(strfile, 3)
        fsuffix = Right$(strfile, 5)
        freplace = "Page"
        propfname = FILEPATH & fprefix & freplace & fsuffix
        FileExistsbol = FileExists(propfname)
          If FileExistsbol Then
          Kill propfname
          End If
        Name FILEPATH & strfile As propfname
        'fso.CopyFile(FILEPATH & propfname, NEWPATH & propfname, True)
      End If
Next f
End Sub

Function GetFiles(path As String, Optional pattern As String = "") As Collection
    Dim rv As New Collection, f
    If Right(path, 1) <> "\" Then path = path & "\"
    f = Dir(path & pattern)
    Do While Len(f) > 0
        rv.Add path & f
        f = Dir() 'no parameter
    Loop
    Set GetFiles = rv
End Function

Function FileExists(fullFileName As String) As Boolean
    If fullFileName = "" Then
        FileExists = False
    Else
        FileExists = VBA.Len(VBA.Dir(fullFileName)) > 0
    End If
End Function
cssyphus
  • 37,875
  • 18
  • 96
  • 111
Joe K
  • 85
  • 1
  • 1
  • 9
  • 1
    This works great. However, the script is missing the function `FileExists()`, a working example [can be found here](https://stackoverflow.com/questions/11573914/check-if-the-file-exists-using-vba/33279642#33279642). *Update: Edited question to add the missing function code.* – cssyphus Jun 08 '18 at 22:42