I have the following code which i can loop through all the .dwg files inside a folder.
Private Sub CommandButton1_Click()
'open file to extract
Dim MyFolderext As String
Dim MyFileext As String
'ficheiro origem
MyFolderext = "C:\Users\abc\test"
MyFileext = Dir(MyFolderext & "\*.dwg")
Do While MyFileext <> ""
Application.Documents.Open MyFolderext & "\" & MyFileext
'check sub if not enough inputs were placed on the user console
check
'unlock drawing layers
ThisDrawing.Layers("MC_BLOCO_INFO_AREAS").Lock = False
ThisDrawing.Layers("MC_BLOCO_TEXTOS_COMERCIAL").Lock = False
ThisDrawing.Layers("MC_BLOCO_TEXTOS_INV").Lock = False
'sub of the program
program
MyFileext = Dir
Loop
'when finished
MsgBox "Done!"
'sub to clean to console for next operation
clean
End Sub
While it works in all the files inside a folder, I cannot make it work with subfolders and I still would need to filter some of them.
So what I am asking is: can you help me changing the code to open all the folders inside the mother folder "C:\Users\abc\test" but skip folders "ignore"?
Edit:
I have come up with this, but still not working:
Sub FileSearch(ByRef Folder As Object)
Dim MyFileext As String
Dim File As Object
Dim SubFolder As Object
MyFileext = Dir(MainFolder & "\*.dwg")
Do While MyFileext <> ""
Application.Documents.Open MainFolder & "\" & MyFileext
For Each File In Folder.Files
programa
Next File
Loop
For Each SubFolder In Folder.SubFolders
If SubFolder.Name <> "extras" Then
FileSearch SubFolder 'Recursion
End If
Next SubFolder
End Sub
Private Sub CommandButton1_Click()
check
Dim MainFolder As Object
Set MainFolder = CreateObject("Scripting.FileSystemObject").GetFolder("C:\Users\abc\test")
FileSearch MainFolder
MsgBox "Done!"
clean
End Sub
You will need to use FileSystemObject to set the folder and files as objects in order to determine if they have subfolders and to be able to check if the subfolders meet your criteria.
Here is an example of how to loop through a folder's files and its subfolders and their files:
Sub test()
Dim MainFolder As Object, File As Object, SubFolder As Object
Set MainFolder = CreateObject("Scripting.FileSystemObject").GetFolder("C:\Users\abc\test\")
For Each File In MainFolder.Files
'do stuff
Next File
For Each SubFolder In MainFolder.Subfolders
'If SubFolder Meets Your Criteria Then
For Each File In SubFolder.Files
'do stuff
Next File
'End If
Next SubFolder
End Sub
That example only searches one level deep in subfolders. Here's an example that searches everything:
Sub test()
Dim MainFolder As Object
Set MainFolder = CreateObject("Scripting.FileSystemObject").GetFolder("C:\Users\abc\test\")
FileSearch MainFolder
End Sub
Sub FileSearch(ByRef Folder As Object)
Dim File As Object, SubFolder As Object
For Each File In Folder.Files
'do stuff
Next File
For Each SubFolder In Folder.SubFolders
FileSearch SubFolder 'Recursion
Next SubFolder
End Sub
In response to your comments, here is another example that is my best guess at how to implement my suggestions into your original code.
Const FileExt As String = ".dwg" 'Module-Level Constant
Private Sub CommandButton1_Click()
'open file to extract
Dim MainFolder As Object
Set MainFolder = CreateObject("Scripting.FileSystemObject").GetFolder("C:\Users\abc\test\")
FileSearch MainFolder
Clean 'is this a sub of yours?
End Sub
Sub FileSearch(ByRef Folder As Object)
Dim File As Object, SubFolder As Object
For Each File In Folder.Files
If File.Name Like "*" & FileExt Then
ProcessDwg File
End If
Next File
For Each SubFolder In Folder.SubFolders
If Not LCase(SubFolder.Name) Like "*ignore*" Then
FileSearch SubFolder 'Recursion
End If
Next SubFolder
End Sub
Sub ProcessDwg(ByRef dwgFile As Object)
Dim ThisDrawing As Object
Set ThisDrawing = Application.Documents.Open(dwgFile.Path)
check 'is this a sub of yours?
ThisDrawing.Layers("MC_BLOCO_INFO_AREAS").Lock = False
ThisDrawing.Layers("MC_BLOCO_TEXTOS_COMERCIAL").Lock = False
ThisDrawing.Layers("MC_BLOCO_TEXTOS_INV").Lock = False
program 'is this a sub of yours?
End Sub
Related
Recently, my organization changed the name of our One Drive causing hyperlinks in my documents linking to other files in the One Drive to become obsolete.
I am trying to create a VBA script that will ask the user for a directory, go through each word doc in the folder and subfolder (and subfolder's subfolder, etc...) and replace a section of all the hyperlinks. I am new to VBA so please, don't hesitate to point out anything.
So far, this is what I have but I can't get it to change what's in the file, let alone go through all the subfolders:
Sub getDirectory()
Dim xFd As FileDialog
Dim xFdItem As Variant
Dim xFileName As String
Dim FileSystem As Object
Dim HostFolder As String
Set xFd = Application.FileDialog(msoFileDialogFolderPicker)
'Get the directory from user
If xFd.Show = -1 Then
xFdItem = xFd.SelectedItems(1) & Application.PathSeparator
xFileName = Dir(xFdItem & "*.doc*")
End If
'convert directory into string
With xFd
.Filters.Clear
.AllowMultiSelect = False
.Show
Path = .SelectedItems(1)
End With
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(Path)
End Sub
Sub DoFolder(Folder)
'loop through folders after calling LoopThroughFiles
Dim SubFolder
Dim File
For Each SubFolder In Folder.SubFolders
DoFolder SubFolder
Next
For Each File In Folder.Files
' Operate on each file
Call LoopThroughFiles
Next
End Sub
Sub LoopThroughFiles()
Dim xFd As FileDialog
Dim xFdItem As Variant
Dim xFileName As String
Dim h As Hyperlink
Dim sOld As String
Dim sNew As String
Set xFd = Application.FileDialog(msoFileDialogFolderPicker)
Do While xFileName <> ""
With Documents.Open(xFdItem & xFileName)
Application.ScreenUpdating = False
'Replace this:
sOld = "AAAA"
'With this:
sNew = "BBBB"
'Example: C:\Users\Me\AAAA\file.doc ---> C:\Users\Me\BBBB\file.doc
'replace hyperlinks
For Each h In ActiveDocument.Hyperlinks
h.Address = Replace(h.Address, sOld, sNew)
Next h
Application.ScreenUpdating = True
End With
xFileName = Dir
Loop
End Sub
I have a question about reading files within folders. I found this code:
sub sample()
Dim FileSystem As Object
Dim HostFolder As String
HostFolder = "C:\"
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(HostFolder)
end sub
Sub DoFolder(Folder)
Dim SubFolder
For Each SubFolder In Folder.SubFolders
DoFolder SubFolder
Next
Dim File
For Each File In Folder.Files
' Operate on each file
Next
End Sub
But how would you go about avoiding a specific folder which is within the original one?
Let's say the you have a folder A which in turn has several folder Bs. within these folders, there are the file required but also another folder, always with the same name, let's say C.
How would you filter out folders Cs?
Thank you for your time
You can try something like this:
' List of complete path of files in folder / subfolders
' Needs to add "Microsoft Scripting Runtime" reference to your file
Sub FolderFilesPath(ByVal pFolder As String, ByRef pColFiles As Collection, _
Optional ByVal pGetSubFolders As Boolean, Optional ByVal pFilter As Collection)
Dim sFolder As String
Dim oFSO As New FileSystemObject
Dim oFolder, oSubFolder As Folder
Dim oFile As File
sFolder = IIf(Right(pFolder, 1) <> "\", pFolder & "\", pFolder)
Set oFolder = oFSO.GetFolder(sFolder)
If Not ExistsInCollection(pFilter, sFolder) Then
For Each oFile In oFolder.Files
pColFiles.Add oFile
Next oFile
If pGetSubFolders Then
For Each oSubFolder In oFolder.SubFolders
FolderFilesPath oSubFolder.Path, pColFiles, pGetSubFolders, pFilter
Next
End If
End If
End Sub
' Vba collection contains
Function ExistsInCollection(col As Collection, key As Variant) As Boolean
On Error GoTo err
ExistsInCollection = True
IsObject (col.Item(key))
Exit Function
err:
ExistsInCollection = False
End Function
'------------------------------------------------------------------------------
Sub TestMe()
Dim colFiles As New Collection, sFilePath As Variant
Dim colExcludedFolders As New Collection
Dim sHostFolder As String
sHostFolder = "C:\temp"
With colExcludedFolders
' add folders you want to exclude
.Add sHostFolder & "\C\", sHostFolder & "\C\"
End With
FolderFilesPath ThisWorkbook.Path, colFiles, True, colExcludedFolders
' colFiles contains filtered files
For Each sFilePath In colFiles
With sFilePath
' do what you want with filtered files
Debug.Print .Path & " - " & .Name & " - " & .DateCreated
End With
Next sFilePath
End Sub
I am inserting a bunch of Word documents into one file for post-processing. When all the files are in one folder, I got my script to work. However to make it robust for future work, I'd like to insert Word files from all folders and subfolders (and possible futher subs) from a certain starting point. I followed this Youtube tutorial: https://www.youtube.com/watch?v=zHJPliWS9FQ to consider all folders and subfolders and of course amended it for my particular use.
Sub CombineDocs()
On Error Resume Next
MsgBox "Opening"
On Error GoTo 0
Dim foldername As String 'parent folder
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
On Error Resume Next
foldername = .SelectedItems(1)
Err.Clear
On Error GoTo 0
End With
Documents.Add
Selection.Style = ActiveDocument.Styles("Heading 1")
Selection.TypeText Text:="Opening text"
Selection.TypeParagraph
Selection.InsertNewPage
Selection.InsertBreak Type:=wdSectionBreakNextPage
ActiveDocument.GoTo(What:=wdGoToPage, Count:=2).Select
Dim fso As Scripting.FileSystemObject
Dim file As Scripting.file
getfolders foldername
End sub
Sub getfolders(foldername)
Set fso = New Scripting.FileSystemObject
Call pastedoc(foldername)
Set fso = Nothing
End Sub
Sub pastedoc(StartFolderPath as String)
Dim file As Scripting.file
Dim subfol As Scripting.folder
Dim mainfolder As Scripting.folder
Set mainfolder = fso.GetFolder(StartFolderPath )
For Each file In mainfolder.Files
If ((InStr(1, LCase(fso.GetExtensionName(file.Path)), "doc", vbTextCompare) > 0) Or _
(InStr(1, LCase(fso.GetExtensionName(file.Path)), "docx", vbTextCompare) > 0)) And _
(InStr(1, file.Name, "~$") = 0) Then
Selection.InsertFile FileName:= _
file.Path _
, Range:="", ConfirmConversions:=False, Link:=False, Attachment:=False
Selection.InsertBreak Type:=wdSectionBreakNextPage
End If
Next file
For Each subfol In mainfolder.SubFolders
pastedoc subfol.Path
Next subfol
End Sub
A difference between my code and the tutorial's is that I define the parent folder in the main code and the tutorial does it in the sub script. As a result I get an
'object required'
error in the 'set mainfolder' line. I tried defining all objects and names between the main code and calling the subs but I still can't get it to work. Any guidance what could fix the code?
One option: assuming the End Sub for CombineDocs was after the getfolders call, you can:
Remove getfolders entirely
In CombineDocs, say pastedoc foldername instead of getfolders foldername
Change the beginning of pastedoc to:
Sub pastedoc(StartFolderPath as String)
Dim fso As Scripting.FileSystemObject ' ** Added
Set fso = New Scripting.FileSystemObject ' ** Added
Dim file As Scripting.file
Dim subfol As Scripting.folder
Dim mainfolder As Scripting.folder
Set mainfolder = fso.GetFolder(StartFolderPath )
' ... (everything else the same)
In general, you need to Dim variables either in the Sub where they are used, or at the top of your module, outside any subs. Please put the Dims inside the Subs whenever you can, since that makes your code much easier to change and maintain.
This is what I have so far, might be good might not haha!
I have been trying to save a word document to about 400+ folders without having to go through them all, can this be done through VB Macros? I got it working to just save it to the directory, but I cannot save it to all the Subfolders.
Dim FileSystem As Object
Dim HostFolder As String
Sub DoFolder(folder)
HostFolder = ("H:\test2")
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(HostFolder)
Dim SubFolder
For Each SubFolder In folder.SubFolders
DoFolder SubFolder
Next
Dim File
For Each File In folder.Files
Set FileSystem = CreateObject("Scripting.FileSystemObject")
' Operate on each file
ActiveDocument.Save
Next
End Sub
I recommended reading: Chip Pearson -Recursion And The FileSystemObject
Make a recursive subroutine to iterate over all the subfolders (and their subfolders) in the root directory.
getAllSubfolderPaths: returns an array that lists all the sub folders in a folder.
Function getAllSubfolderPaths(FolderPath As String, Optional FSO As Object, Optional List As Object)
Dim fld As Object
If FSO Is Nothing Then
Set FSO = CreateObject("Scripting.Filesystemobject")
Set List = CreateObject("SYstem.Collections.ArrayList")
End If
List.Add FolderPath
For Each fld In FSO.GetFolder(FolderPath).SubFolders
getAllSubfolderPaths fld.Path, FSO, List
Next
getAllSubfolderPaths = List.ToArray
End Function
Test
Sub Test()
Const RootFolder As String = "C:\Users\Owner\Pictures"
Const SourcePath As String = "C:\Users\Owner\Documents\Youcam"
Const SourceFileName As String = "Capture.PNG"
Dim fld As Variant, FolderArray As Variant
Dim Destination As String, Source As String
FolderArray = getAllSubfolderPaths(RootFolder)
For Each fld In FolderArray
Destination = fld & "\" & SourceFileName
Source = SourcePath & "\" & SourceFileName
'Delete old copy of file
If Destination <> Source And Len(Dir(Destination)) Then Kill Destination
VBA.FileCopy Source:=Source, Destination:=Destination
Next
End Sub
Gotta love auditing requirements... You're basically on the right path, but you really only need one FileSystemObject. About the only errors I see are that you need the .Path of the folder here...
For Each SubFolder In folder.SubFolders
DoFolder SubFolder.Path '<---Here.
Next
...and you don't need to loop through all the files here (you may be overthinking this one a bit):
For Each File In folder.Files
Set FileSystem = CreateObject("Scripting.FileSystemObject")
' Operate on each file
ActiveDocument.Save
Next
Also, I'd suggest using early binding instead of late binding (although the example below can easily be switched). I'd do something a bit more like this:
Private Sub SaveDocToAllSubfolders(targetPath As String, doc As Document, _
Optional root As Boolean = False)
With New Scripting.FileSystemObject
Dim current As Scripting.folder
Set current = .GetFolder(targetPath)
If Not root Then
doc.SaveAs .BuildPath(targetPath, doc.Name)
End If
Dim subDir As Scripting.folder
For Each subDir In current.SubFolders
SaveDocToAllSubfolders subDir.Path, doc
Next
End With
End Sub
The root flag is just whether or not to save a copy in the host folder. Call it like this:
SaveDocToAllSubfolders "H:\test2", ActiveDocument, True
can you help me?
i want a macro vba that search for a SPECIFIC subfolder for example (Xfolder) between all the folders and subfolders that exist and move their files.
P:\Desktop\Folder1\subfolder\SUBFOLDER1\Xfolder
I'm using the VBA Scripting Runtime objects
Set oSourceFolder = fso.GetFolder(source)
If Dir(destinationFolder, 16) = "" Then MkDir (destinationFolder)
For Each oFile In oFolder.Files
If Dir(destinationFolder,16) = "" Then
fso.MoveFile oFile.Path, destinationFolder
End If
Next oFile
fso.DeleteFolder oFolder.Path
Next oFolder
Here's a solution:
Dim fsoFileSystem As New FileSystemObject
Dim foFolder As Folder, foSubFolder As Folder
Dim fFile As File
Dim strStartFolder As String, strMoveFolder As String, strTargetFolder As String
strStartFolder = "\\A\B\C"
strMoveFolder = "SearchFolder"
strTargetFolder = "\\B\D\E"
Set foFolder = fsoFileSystem.GetFolder(strStartFolder)
For Each foSubFolder In foFolder.SubFolders
If foSubFolder.Name = strMoveFolder Then
For Each fFile In foSubFolder.Files
fsoFileSystem.MoveFile fFile, strTargetFolder & "\"
Next
End If
Next
strStartFolder is the folder to Screen for subfolders.
strMoveFolder is the name of the Folder to look for.
strTargetFolder is the Folder to where all the strMoveFolder's files shall be moved.
To found some folder use something like this
Sub findFolder()
Dim searchFolderName As String
searchFolderName = "somePath"
Dim FileSystem As Object
Set FileSystem = CreateObject("Scripting.FileSystemObject")
doFolder FileSystem.getFolder(searchFolderName)
End Sub
Sub doFolder(Folder)
Dim subFolder
On Error Resume Next
For Each subFolder In Folder.subfolders
If Split(subFolder, "\")(UBound(Split(subFolder, "\"))) = "testFolder" Then
MsgBox "gotcha"
End
End If
doFolder subFolder
Next subFolder
End Sub
And then you can do whatever with that folder and its content. So with i little use of google (one maybe two words) you can achieve what you wana