I am relatively amateur at VBA and am using a code provided by tech on the net.
I have an Excel document with files names in column B (not always one file type) which I am trying to ensure I have copies and the correct revision in a designated folder.
Currently, the code works perfectly for a specific folder location, but the files referenced in the Excel spreadsheet exist in various other folders and thus I need to create a code that can search a main folder and loop through the various sub-folders.
See current code below for reference.
Sub CheckIfFileExists()
Dim LRow As Integer
Dim LPath As String
Dim LExtension As String
Dim LContinue As Boolean
'Initialize variables
LContinue = True
LRow = 8
LPath = "K:\location\main folder\sub folder \sub folder"
LExtension = ".pdf"
'Loop through all column B values until a blank cell is found
While LContinue
'Found a blank cell, do not continue
If Len(Range("B" & CStr(LRow)).Value) = 0 Then
LContinue = True
'Check if file exists for document title
Else
'Place "No" in column E if the file does NOT exist
If Len(Dir(LPath & Range("B" & CStr(LRow)).Value & LExtension)) = 0 Then
Range("E" & CStr(LRow)).Value = "No"
'Place "Yes" in column E if the file does exist
Else
Range("E" & CStr(LRow)).Value = "Yes"
End If
End If
LRow = LRow + 1
Wend
End Sub
There are over 1000 documents, so simple windows searches is not ideal, and I have reviewed several previous questions and cannot find an answer that helps.
Okay, my answer is going to revolve around 2 comments from your question. This will serve only as a basis for you to improve upon and adapt to how you need it.
N.B SKIP TO THE BOTTOM OF MY ANSWER TO SEE THE FULL WORKING CODE
The first comment is:
I need to create a code that can search a main folder and loop through the various sub-folders.
The code i will explain below will take a MAIN FOLDER, that you will need to specify, and then it will loop through ALL subfolders of the parent directoy. So you will not need to worry about specific sub folders. As long as you know the name of the file you want to access, the code will find it regardless.
The second is a line of your code:
LPath = "K:\location\main folder\sub folder \sub folder"
This line of code will form part of a UDF (User Defined Function) that i will display below.
Step 1
Re-label LPath to be the what is called the "Host Folder". This is the MAIN FOLDER.
For Example: Host Folder = "K:\User\My Documents\" (Note the backslash at the end is needed)
Step 2
Set a reference to Microsoft Scripting Runtime in 2 places:
i) In the code
Set FileSystem = CreateObject("Scripting.FileSystemObject")
ii) In the VBA Editor. (To a basic google search on how to find the reference library in the VBA editor)
Step 3
This is the main element, this is a sub routine that will find the file no matter where it is, providing a file name and host folder has been provided.
Sub DoFolder(Folder)
Dim SubFolder
For Each SubFolder In Folder.SubFolders
DoFolder SubFolder
Next
Dim File
For Each File In Folder.Files
If File.Name = "Specify Name.pdf" Then
Workbooks.Open (Folder.path & "\" & File.Name), UpdateLinks:=False
Workbooks(File.Name).Activate
Exit Sub
End If
Next
End Sub
The code above will simply open the file once it has found it. This was just my own specific use; adapt as necessary.
MAIN CODE
Option Explicit
Dim FileSystem As Object
Dim HostFolder As String
Sub FindFile()
HostFolder = "K:\User\My Documents\"
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
If File.Name = "Specify Name.pdf" Then
Workbooks.Open (Folder.path & "\" & File.Name), UpdateLinks:=False
Workbooks(File.Name).Activate
Exit Sub
End If
Next
End Sub
You can chop this up how you see fit, you can probably throw it into your sub CheckIfFileExists() or just use it on its own.
Let me know how you get along so i can help you understand this further
Related
I need to loop over some word documents, and extract images from a word document and save them in a separate folder.
I've tried the method of saving them as an HTML document, but it is not a good fit for my requirement.
Now, I'm looping through the images using inlineshapes object and then copy-pasting them on a publisher document and then saving them as an image. However, I'm facing a Runtime Automation error when I'm running the script.
For using the Publisher runtime library I've tried both early and late binding but I'm facing the error on both of them.
Can anyone please let me know what is the problem? Also, if anyone can explain why I'm facing this error, that'd be great. As per my understanding, it is due to memory allocation, but I'm not sure.
Here is the code block that I've been working on (fp, dp are folder paths, while filename is the word document name. I'm calling this sub in another sub that is looping over all the files in a folder):
Sub test(ByVal fp As String, ByVal dp As String, ByVal filename As String)
Dim doc As Document
Dim pubdoc As New Publisher.Document
Dim shp As InlineShape
'Application.Screenupdating = False
'Dim pubdoc As Object
'Set pubdoc = CreateObject("Publisher.Document")
Set doc = Documents.Open(fp)
With doc
i = .InlineShapes.Count
Debug.Print i
End With
For j = 1 To i
Set shp = doc.InlineShapes(j)
shp.Select
Selection.CopyAsPicture
pubdoc.Pages(1).Shapes.Paste
pubdoc.Pages(1).Shapes(1).SaveAsPicture (dp & Application.PathSeparator & j & ".jpg")
pubdoc.Pages(1).Shapes(1).Delete
Next
doc.Close (wdDoNotSaveChanges)
pubdoc.Close
'Application.Screenupdating = True
End Sub
Apart from this, if anyone has any suggestions to make this faster, I'm all ears. Thanks in advance!
Just add .zip to the end of the file name, expand the file and look in the word/media folder. All the files will be there, no programming necessary.
Extracting the pictures from a Filtered HTML document that was created from your original source document would be faster. However, you said that was not a good fit for you needs so ... here is example code that will locate pictures in your source document and paste them into a second document.
The speed problem of this type of code is caused by the CopyPicture working from a Selection command, so I recommend using a range instead. Of course the For/Next loop that is required is slower no matter what.
Sub CopyPasteAsPicture()
Dim doc As Word.Document, iShp As Word.InlineShape, shp As Word.Shape
Dim i As Integer, nDoc As Word.Document, rng As Word.Range
Set doc = ActiveDocument
If doc.Shapes.Count > 0 Then
For i = 1 To doc.Shapes.Count
Set shp = doc.Shapes(i)
If shp.Type = msoLinkedPicture Or shp.Type = msoPicture Then
'if you want only pictures extracted then you have
'to specify the type
shp.ConvertToInlineShape
'if you want all extracted pictures to be in the sequence
'they appear in the document then you have to convert
'floating shapes to inline shapes
End If
Next
End If
If doc.Content.InlineShapes.Count > 0 Then
Set nDoc = Word.Documents.Add
Set rng = nDoc.Content
For i = 1 To doc.Content.InlineShapes.Count
doc.Content.InlineShapes(i).Range.CopyAsPicture
rng.Paste
rng.Collapse Word.WdCollapseDirection.wdCollapseEnd
rng.Paragraphs.Add
rng.Collapse Word.WdCollapseDirection.wdCollapseEnd
Next
End If
End Sub
If you want to place all shapes (floating or inline) into a folder as image files, then the best way is to save the source document as a filtered HTML document. Here is the command:
htmDoc.SaveAs2 FileName:=LGPWorking & strFileName, AddToRecentFiles:=False, FileFormat:=Word.WdSaveFormat.wdFormatFilteredHTML
In the above the active document is assigned to the variable htmDoc. I am giving this new document a specific name and location. The output from this is not only the HTML file but also a directory by the same name with an appended "_Files" label. In the "x_Files" directory are all the image files.
If you only want selective images pulled from your original source document, or if you want images pulled from multiple source documents ... then you need to use the above code that I shared for placing only the images you want from one or more source document into a new Word document and then save that new document as an Filtered HTML.
When your routine is done, you can Kill the HTML document and only leave the Files directory.
I had to change a few things around, but this will allow to save a single image on a word document and go through a couple of cycles before it turns into a jpg on the other side, without any white space
filename = ActiveDocument.FullName
saveLocaton = "z:\temp\"
FolderName = "test"
On Error Resume Next
Kill "z:\temp\test_files\*" 'Delete all files
RmDir "z:\temp\test_files" 'Delete folder
ActiveDocument.SaveAs2 filename:="z:\temp\test.html", FileFormat:=wdFormatHTML
ActiveDocument.Close
Kill saveLocaton & FolderName & ".html"
Kill saveLocaton & FolderName & "_files\*.xml"
Kill saveLocaton & FolderName & "_files\*.html"
Kill saveLocaton & FolderName & "_files\*.thmx"
Name saveLocaton & FolderName & "_files\image00" & 1 & ".png" As saveLocaton & FolderName & "_files\" & test2 & "_00" & x & ".jpg"
Word.Application.Visible = True
Word.Application.Activate
Can anyone help please with the following requirements?
Requirement A:
I'd like to create a loop to run a list of command strings in CMD as long as there's a non-zero value in column C. I think I need to define a variable i for my starting row as this will always be the same, and then run Shell(), pulling the command string from the corresponding cell in Row i, Column F. While Cells(i, "C") is not blank, keep going, increasing i by 1.
Requirement B:
I'd also like to link this macro to work in a directory deposited in a cell by an earlier macro that listed all the files in a selected directory.
This is what I have, without any looping..
Sub Run_Renaming()
Dim CommandString As Long
Dim i As Integer
i = 5
'Other steps:
'1 - need to pick up variable (directory of files listed, taken from first macro
'when doing manually, I opened command, went to correct directory, then pasted
'the commands. I'm trying to handle pasting the commands. I'm not sure if I need
'something to open CMD from VBA, then run through the below loop, or add opening
'CMD and going to the directory in each iteration of the below loop...
'2 - Need to say - Loop below text if Worksheets("Batch Rename of Files").Cells(i, "C").Value is no blank
CommandString = Worksheets("Batch Rename of Files").Cells(i, "F").Value
Call Shell("cmd.exe /S /K" & CommandString, vbNormalFocus)
'Other steps:
'3 - need to increase i by 1
'4 - need to check if C column is blank or not
'5 - need to end of C column is blank
End Sub
Background:
I'm creating a file renaming tool for a friend. They can use excel, but no programming languages or command prompt. Because of this, I don't want to have any steps, like creating a batch file suggested here, that would complicate things for my friend.
I've created an excel file with:
Tab 1 - a template sheet to create a new file name list. Works by concatenating several cells, adding a filetype, and outputting to a range of cells. Tab two links to this range when creating the renaming command strings for CMD
Tab 2 -
Button 1 - Sub rename() below. VBA to list files in a selected directory in Column C
Column F creates a command line that will rename File A as File B based on inputs to Tab 1 i.e. ren "File 1" "A1_B1_C1.xlsx"
Button 2 - Refers to a renaming macro (requirement 1 and 2 above) that picks up the selected directory from Button 1 and runs through all the renaming command strings while in that directory
Sub rename()
Dim xRow As Long
Dim xDirect$, xFname$, InitialFoldr$
InitialFoldr$ = "C:\"
Worksheets("Batch Rename of Files").Activate
Worksheets("Batch Rename of Files").Range("C4").Activate
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & "\"
.Title = "Please select a folder to list Files from"
.InitialFileName = InitialFoldr$
.Show
If .SelectedItems.Count <> 0 Then
xDirect$ = .SelectedItems(1) & "\"
xFname$ = Dir(xDirect$, 7)
Do While xFname$ <> ""
ActiveCell.Offset(xRow) = xFname$
xRow = xRow + 1
xFname$ = Dir
Loop
End If
End With
End Sub
Caveats:
1) I am not entirely clear on how you data etc is laid out so i am offering a way of achieving your goal that involves the elements i am clear on.
2) To be honest, personally, i would do as much using arrays or a dictionary as possible rather than going backwards and forwards to worksheets.
However...
Following the outline of your requirements and a little rough and ready, we have:
1) Using your macro rename (renamed as ListFiles and with a few minor tweaks) to write the chosen folder name out to Range("A1") in Worksheets("Batch Rename of Files") and the file names to Column C.
2) Using a second macro RenameFiles to pick up the rename shell commands from Column F of Worksheets("Batch Rename of Files"); write these out to a batch file on the desktop; add an additional first line command that sets the working directory to the chosen folder given in Range("A1") (Requirement A). The shell command executes the .bat file, completes the renaming (Requirement B) and then there is a line to remove the .bat file.
I am guessing this is a more efficient way of achieving your goal than looping the column F range executing a command one at a time.
I have not sought to optimize code in any further ways (i have added a few existing typed functions.) There are a number of other improvements that could be made but this was intended to help you achieve your requirements.
Let me know how it goes!
Tab1 layout (Sheet containing new file names):
Batch Rename of Files layout (Sheet containing output of the first macro and the buttons ):
Layout of Worksheet Batch Rename of File
In a standard module called ListFiles:
Option Explicit
Public Sub ListFilesInDirectory()
Dim xRow As Long
Dim xDirect$, xFname$, InitialFoldr$ 'type hints not really needed
Dim wb As Workbook
Dim wsTab2 As Worksheet
Set wb = ThisWorkbook
Set wsTab2 = wb.Worksheets("Batch Rename of Files")
InitialFoldr$ = "C:\"
Dim lastRow As Long
lastRow = wsTab2.Cells(wsTab2.Rows.Count, "C").End(xlUp).Row
wsTab2.Range("C4:C" & lastRow).ClearContents 'Get rid of any existing file names
wsTab2.Range("C4").Activate
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & "\"
.Title = "Please select a folder to list Files from"
.InitialFileName = InitialFoldr$
.Show
If .SelectedItems.Count <> 0 Then
xDirect$ = .SelectedItems(1) & "\"
xFname$ = Dir(xDirect$, 7)
wsTab2.Range("A1") = xDirect$
Do While xFname$ <> vbNullString
ActiveCell.Offset(xRow) = xFname$
xRow = xRow + 1
xFname$ = Dir
Loop
End If
End With
End Sub
In a standard module called FileRenaming:
Option Explicit
Sub RenameFiles()
Dim fso As New FileSystemObject
Dim stream As TextStream
Dim strFile As String
Dim strPath As String
Dim strData As Range
Dim wb As Workbook
Dim wsTab2 As Worksheet
Dim currRow As Range
Set wb = ThisWorkbook
Set wsTab2 = wb.Worksheets("Batch Rename of Files")
strPath = wsTab2.Range("A1").Value2
If strPath = vbNullString Then
MsgBox "Please ensure that Worksheet Batch Rename of Files has a directory path in cell A1"
Else
If Right$(Trim$(strPath), 1) <> "\" Then strPath = strPath & "\"
strFile = "Rename.bat"
Dim testString As String
Dim deskTopPath As String
deskTopPath = Environ$("USERPROFILE") & "\Desktop" 'get desktop path as this is where .bat file will temporarily be saved
testString = fso.BuildPath(deskTopPath, strFile) 'Check if .bat already exists and delete
If Len(Dir(testString)) <> 0 Then
SetAttr testString, vbNormal
Kill testString
End If
Set stream = fso.CreateTextFile(deskTopPath & "\" & strFile, True) 'create the .bat file
Dim lastRow As Long
lastRow = wsTab2.Cells(wsTab2.Rows.Count, "C").End(xlUp).Row
Set strData = wsTab2.Range("F4:F" & lastRow) 'Only execute for as many new file names as present in Col C (in place of your until blank requirement)
stream.Write "CD /D " & strPath & vbCrLf
For Each currRow In strData.Rows 'populate the .dat file
stream.Write currRow.Value & vbCrLf
Next currRow
stream.Close
Call Shell(testString, vbNormalFocus)
Application.Wait (Now + TimeValue("0:00:01")) 'As sometime re-naming doesn't seem to happen without a pause before removing .bat file
Kill testString
MsgBox ("Renaming Complete")
End If
End Sub
Buttons code in Worksheet Batch Rename of Files
Private Sub CommandButton1_Click()
ListFilesInDirectory
End Sub
Private Sub CommandButton2_Click()
RenameFiles
End Sub
Example .bat file contents:
VERSION 2
And here is a different version using a dictionary and passing parameters from one sub to another. This would therefore be a macro associated with only one button push operation i.e. there wouldn't be a second button. The single button would call ListFiles which in turn calls the second macro. May require you to go in to tools > references and add in Microsoft Scripting Runtime reference.
Assumes you have a matching number of new file names in Col D of tab 1 as the number of files found in the folder (as per your script to obtain files in folder). I have removed the obsolete type references.Shout out to the RubberDuck VBA add-in crew for the add-in picking these up.
In one standard module:
Option Explicit
Public Sub ListFiles()
Dim xDirect As String, xFname As String, InitialFoldr As String
Dim wb As Workbook
Dim ws As Worksheet
Dim dict As New Scripting.Dictionary
Dim counter As Long
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Tab1") 'Worksheet where new file names are
counter = 4 'row where new file names start
InitialFoldr = "C:\"
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & "\"
.Title = "Please select a folder to list Files from"
.InitialFileName = InitialFoldr
.Show
If .SelectedItems.Count <> 0 Then
xDirect = .SelectedItems(1) & "\"
xFname = Dir(xDirect, 7)
Do While xFname <> vbNullString
If Not dict.Exists(xFname) Then
dict.Add xFname, ws.Cells(counter, "D") 'Or which ever column holds new file names. This add to the dictionary the current name and new name
counter = counter + 1
xFname = Dir
End If
Loop
End If
End With
RenameFiles xDirect, dict 'pass directory path and dictionary to renaming sub
End Sub
In another standard module:
Public Sub RenameFiles(ByVal folderpath As String, ByRef dict As Dictionary)
Dim fso As New FileSystemObject
Dim stream As TextStream
Dim strFile As String
Dim testString As String
Dim deskTopPath As String
strFile = "Rename.bat"
deskTopPath = Environ$("USERPROFILE") & "\Desktop"
testString = fso.BuildPath(deskTopPath, strFile)
'See if .dat file of same name already on desktop and delete (you could overwrite!)
If Len(Dir(testString)) <> 0 Then
SetAttr testString, vbNormal
Kill testString
End If
Set stream = fso.CreateTextFile(testString, True)
stream.Write "CD /D " & folderpath & vbCrLf
Dim key As Variant
For Each key In dict.Keys
stream.Write "Rename " & folderpath & key & " " & dict(key) & vbCrLf 'write out the command instructions to the .dat file
Next key
stream.Close
Call Shell(testString, vbNormalFocus)
Application.Wait (Now + TimeValue("0:00:01")) 'As sometime re-naming doesn't seem to happen without a pause before removing .bat file
Kill testString
' MsgBox ("Renaming Complete")
End Sub
Scripting run time reference:
Adding runtime reference
Additional method for finding the desktop path. Taken from Allen Wyatt:
In a standard module add the following:
Public Function GetDesktop() As String
Dim oWSHShell As Object
Set oWSHShell = CreateObject("WScript.Shell")
GetDesktop = oWSHShell.SpecialFolders("Desktop")
Set oWSHShell = Nothing
End Function
Then in the rest of the code replace any instances of deskTopPath =..... e.g.:
deskTopPath = Environ$("USERPROFILE") & "\Desktop"
With
desktopPath = GetDesktop
I am trying to open excel files from a folder and copy and paste details into a master folder. Within each first level folder, there are some .xlsm files available to open, but there are also some within a second level folder within the first level folder (so an extra \filepath).
Right now, I am trying to figure out how to loop through the first level folder and open the "loose" workbooks (files in the first level folder that ARE NOT in a second level folder).
This is what I have. Please note I will eventually add another "level" of folders, hence the large amount of variables:
Sub Compile_RFQ_Parts()
Dim RFQ_Ecoat As String 'file path for RFQ folder in ecoat folder
Dim RFQ_VendorFolder As String 'file path for specific vendor
Dim RFQ_FileFolder As String 'file path for RFQ folder within a vendor folder
Dim RFQ_File As String 'file within RFQ #### style folder in vendor folder
Dim RFQ_FileLooseVendor As String 'loose file in vendor folder
Dim RFQ_FileLooseEcoat As String 'loose file in ecoat RFQ folder
Dim RFQ_Num As String 'Number of RFQ from formula
Dim DumpLocation As String 'Bulk workbook
Dim DumpSheet As String 'Target sheet in bulk workbook
Dim NextOpenCellRow As Integer 'next open cell at the dump location
Dim RFQcell As Range 'counter for each cell in "part number" range in RFQ file
Dim RFQrange As Range 'range to look for part numbers in RFQ file
Define Variables
RFQ_Ecoat = "S:\FACILITY\Sales\RFQ"
RFQ_VendorFolder = RFQ_Ecoat & "\Jensen Metals"
RFQ_FileLooseVendor = Dir(RFQ_VendorFolder & "\*.xlsm") 'wildcard to open spreadsheets
DumpLocation = "RFQ_Compile test target.xlsx"
DumpSheet = "Sheet1"
Begin Loop
'######loop through each .xlsm file in a Vendor folder (not in RFQ folder but loose in vendor folder)######
Do While RFQ_FileLooseVendor <> ""
Application.DisplayAlerts = False
Workbooks.Open Filename:=RFQ_VendorFolder & "\" & RFQ_FileLooseVendor, UpdateLinks:=False
Application.DisplayAlerts = True
'vvvvvv%%%%%%%%%Copy and pasting operations%%%%%%%%%vvvvvv
Next File in loop within Folder
Next
'#########close RFQ and loop to the next RFQ_FileLooseVendor#########
Application.DisplayAlerts = False
Workbooks(RFQ_FileLooseVendor).Close
Application.DisplayAlerts = True
RFQ_FileLooseVendor = Dir() '<<<This clears my RFQ_FileLooseVendor string, which ends my Do While loop before getting to other files
Loop
End Sub
When I get to the RFQ_FileLooseVendor=dir() line, it clears that variable (makes it = ""). I have seen this on countless other forums and I can't understand how it does not immediately end the Do While loop for everyone else like it does for me.
ISSUE WAS RESOLVED: It turns out it was something I used in my for loop within the do while loop. I used a Dir() function to equal the value of a cell. Creating a new variable as a string and having equate to my Dir() function solved it.
Was:
Workbooks(DumpLocation).Sheets(DumpSheet) _
.Range("A" & NextOpenCellRow + 1).Value =Dir(RFQ_VendorFolder, vbDirectory)
is now:
Workbooks(DumpLocation).Sheets(DumpSheet) _
.Range("A" & NextOpenCellRow + 1).Value = RFQ_Vendor
list file image
i want to copyfile from a list in excel sheet if there isn t any file their . But i have an error 5 in fso.CopyFile filepath, Destination .
I do not know what is the problem , can you help me
Set fso = CreateObject("scripting.filesystemobject")
Destination = "C:\Users\test\"
Set oFolder = fso.GetFolder(Destination)
Set workboo = Workbooks.Open("C:\Users\listing.xlsx")
Set worksh = workboo.Worksheets("List_File")
For j = 1 To 10
numrows = worksh.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To numrows
icol = 2 * j - 1
filepath = worksh.Cells(i, icol).Value
If Not fso.FileExists(Destination) Then
fso.CopyFile filepath, Destination
End If
Next
Next
workboo.Close
End Sub
Your code expect Destination to be a file, but it is a directory. FSO documentation tells you that:
If source contains wildcard characters or destination ends with a path separator (), it is assumed that destination is an existing
folder in which to copy matching files. Otherwise, destination is
assumed to be the name of a file to create. In either case, three
things can happen when an individual file is copied.
If destination does not exist, source gets copied. This is the usual case.
If destination is an existing file, an error occurs if overwrite is False. Otherwise, an attempt is made to copy source over the
existing file.
If destination is a directory, an error occurs.
Make sure either Destinationis set to a filename, not a directory, or that filepath is set to multiple files using wildcards.
BTW, if Destination is expected to remains a directory, you shouldn't test fso.FileExists(Destination).
You can use BuildPath() and GetFileName() to construct the destination filename if needed:
Public Sub SomeName()
Set fso = CreateObject("scripting.filesystemobject")
Destination = "C:\Users\test\"
Set oFolder = fso.GetFolder(Destination)
Set workboo = Workbooks.Open("C:\Users\listing.xlsx")
Set worksh = workboo.Worksheets("List_File")
For j = 1 To 10
numrows = worksh.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To numrows
icol = 2 * j - 1
filepath = worksh.Cells(i, icol).Value
filedest = fso.BuildPath(Destination,fso.GetFileName(filepath))
If Not fso.FileExists(filedest) Then
fso.CopyFile filepath, filedest
End If
Next
Next
workboo.Close
End Sub
I didn't edit much your code, but defining you variable with Dim ... should be a good idea.
As per information gathered from you, I have designed the program. I have kept source Folder and file string separately. To extract file name, I have used TRIM and MID functions.
sFile = Trim(Mid((worksh.Cells(i, icol).Text), 39, 99))
You may check the length of the Source Folder "P:\Desktop\Nouveau dossier (4)\Source\" exactly by LEN function and then add 1 to that length for start of file name. Further I have kept total number of characters tentatively 99 which you may adjust according to maximum file name length you are using. Please also ensure that source and destination folders are correct in the program and match with your physical folder paths on your computer. I have tested it on my computer and it is working fine on sample data.I have also set reference to Microsoft Scripting Runtime Library.
Sub CopyingFiles_Q37539919()
'Declaration
Dim FSO
Dim sFile As String
Dim sSFolder As String
Dim sDFolder As String
Dim i As Integer, j As Integer
Dim icol As Long
Dim numrows As Long
Set workboo = Workbooks.Open("C:\Users\listing.xlsx")
Set worksh = workboo.Worksheets("List_File")
numrows = worksh.Range("A" & Rows.Count).End(xlUp).Row
Debug.Print numrows
'Change to match the source folder path.
sSFolder = "C:\mydir_s\" '
'Change to match the destination folder path.
sDFolder = "C:\Users\test\"
For j = 1 To 10
For i = 2 To numrows
icol = 2 * j - 1
sFile = Trim(Mid((worksh.Cells(i, icol).Text), 39, 99)) ' Adjust the figure 39 for start of file name and 99 for maximum length of file name
Debug.Print sFile
Debug.Print sSFolder & sFile
'Create Object for File System
Set FSO = CreateObject("Scripting.FileSystemObject")
If Not FSO.FileExists(sSFolder & sFile) Then
MsgBox "Specified File Not Found in Source Folder", vbInformation, "Not Found"
End If
'Copying If the Same File is Not Located in the Destination Folder
If Not FSO.FileExists(sDFolder & sFile) Then
FSO.CopyFile (sSFolder & sFile), sDFolder, True
MsgBox "Specified File Copied to Destination Folder Successfully", vbInformation, "Done!"
Else
MsgBox "Specified File Already Exists In The Destination Folder", vbExclamation, "File Already Exists"
End If
Next
Next
End Sub
On seeing your code i agree with Trimax the area of problem he is pointing. Apart from that you need to make sure followings:
1. Make sure "filepath" variable is fully qualified path for the file like "d:\yourdirctoryname\yourfilename.extension"
2. Make sure file exists at source location if not the same validation you can write for "filepath" as you did for "destination"
3. if you have same extension files to be copied then you should use wildcard to copy file to the destination it will reduce system effort. For more detail follow https://msdn.microsoft.com/en-us/library/e1wf9e7w(v=vs.84).aspx for wildcard code.
I believe it will resolve the issue.
I'm fairly new to VBA and macro's, so I'm writing a post here to hopefully get some help and tips for my solution. My problem is as follows:
I need to copy an uncertain amount of cells containing data from excel-files in folders and subfolders to paste in an excel-"mother"-file:
"All files that contain data is in one folder and it's subfolders. the cells to be copied in theese files ALWAYS start at row 40, and are in cells A, B, C and D. How many rows that need to be copied however is uncertain."
What I'm looking for is code that loops through a folder and it's subfolders looking for files to get data from. I'm also thinking that inside this loop I will later write code to collect data from each individual file.
SO, what I'm looking for is:
- Code to loop through a folder and subfolders to collect data from file.
- Code that finds last row with data and copies all data from start to this last row. I'm thinking something like: "A40:D & UncertainRange"
All help is greatly appreciated.. afterall I'm still a VBA Noob.
Have a great weekend, and may all of your problems be solved by scripting.
Good day.
Here's a command to identify the last row in an Excel sheet that has data:
lastRow = ActiveWorkbook.ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
To loop through your data beginning on row 40 of each file you can then use something like this:
lastRow = ActiveWorkbook.ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For iRow = 40 to lastRow
destinationSheet.Cells(outputRow, 1) = sourceSheet.Cells(iRow, 1)
destinationSheet.Cells(outputRow, 2) = sourceSheet.Cells(iRow, 2)
destinationSheet.Cells(outputRow, 3) = sourceSheet.Cells(iRow, 3)
destinationSheet.Cells(outputRow, 4) = sourceSheet.Cells(iRow, 4)
outputRow = outputRow + 1
Next iRow
To loop through files, use something like this:
Sub mySub()
Dim strFolder As String
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = "C:\"
.title = "Please select a folder..."
.Show
If .SelectedItems.Count > 0 Then
strFolder = .SelectedItems(1) & "\"
Else
Exit Sub
End If
End With
Dim myobject As Object
Set myobject = CreateObject("Scripting.FileSystemObject")
Set mysource = myobject.GetFolder(strFolder)
Application.Workbooks.Open ("c:\motherWorkbook.xlsx")
For Each MyFile In mysource.Files
''' Do Something with files in main folder
Next
' Subfolders
For Each mySubFolder In mysource.Subfolders
Set mysource = myobject.GetFolder(mySubFolder.Path)
For Each MyFile In mysource.Files
''' Do Something with files in sub folders
Next
Next
End Sub
have a look at this link: http://online-vba.de/vba_readfolder.php - change sRootPath with your directory without \ at the end