I'm trying to write a simple VBA Subroutine that:
creates a new workbook in the same directory of the excel file that contains the code ("original file" from here onward)
saves the new workbook as _export.xlsx
copies some predefined sheets from the original file to the "*_export" one.
This is what I've got at the time being:
Sub export()
Dim myPath, folderPath, fileName, exportFileFullPath As String
Dim arrayOfSheetsToCopy As Variant
folderPath = Application.ActiveWorkbook.Path
fullPath = Application.ActiveWorkbook.FullName
fileName = Replace(Application.ActiveWorkbook.Name, ".xlsm", "")
exportFileFullPath = folderPath & "\" & fileName & "_export.xlsx"
Workbooks.Add
ActiveWorkbook.SaveAs fileName:=exportFileFullPath, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
arrayOfSheetsToCopy = Array("originalSheet1", "originalSheet2", "originalSheet3")
Workbooks(fullPath).Sheets(arrayOfSheetsToCopy).Copy After:=Workbooks(exportFileFullPath).Sheets(Sheets.Count)
End Sub
The code seems to run until a "Subscript out of range" error at Sheets(arrayOfSheetsToCopy).Copy...
Initially I though to some kind of syntax error in the definition of the Array of Sheets, so I tried to write a separate .Copy instruction for each Sheet. The same code interrupts at the same point with the same error.
Any idea? Thank you!
Workbook.FullName does not return a valid argument for the Workbooks collection.
You can test this by running ?Workbooks(ActiveWorkbook.FullName).FullName in the Immediate Window - it will error. On the other hand, Workbook.Name does work, so ?Workbooks(ActiveWorkbook.Name).FullName will not error. In other words Workbooks("C:\Users\fabbius\Documents\SomeFile.xlsx") is not valid, while Workbooks("SomeFile.xlsx") is valid, so long as a file by that name is open.
However, I fail to see the benefit of using FullName over using properly defined Workbook Objects:
Sub export()
Dim exportFileFullPath As String, arrayOfSheetsToCopy As Variant
Dim wsExportFrom As Workbook, wsExportTo As Workbook
Set wsExportFrom = ActiveWorkbook
Set wsExportTo = Workbooks.Add
exportFileFullPath = Replace(wsExportFrom.FullName, ".xlsm", "_export.xlsx", Len(wsExportFrom.Path))
'The Len() is in case the File Path contains ".xlsm" for some reason
wsExportTo.SaveAs fileName:=exportFileFullPath, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
arrayOfSheetsToCopy = Array("originalSheet1", "originalSheet2", "originalSheet3")
wsExportFrom.Sheets(arrayOfSheetsToCopy).Copy after:=wsExportTo.Sheets(wsExportTo.Sheets.Count)
End Sub
Of course, if this Macro is being run from the workbook you intend to export from, then With and ThisWorkbook make things even simpler:
Sub export()
Dim exportFileFullPath As String, arrayOfSheetsToCopy As Variant
exportFileFullPath = Replace(ThisWorkbook.FullName, ".xlsm", "_export.xlsx", Len(ThisWorkbook.Path))
'The Len() is in case the File Path contains ".xlsm" for some reason
arrayOfSheetsToCopy = Array("originalSheet1", "originalSheet2", "originalSheet3")
With Workbooks.Add
.SaveAs fileName:=exportFileFullPath, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
ThisWorkbook.Sheets(arrayOfSheetsToCopy).Copy after:=.Sheets(.Sheets.Count)
End With
End Sub
Final note: You are saving the file before you add the worksheets to it. Should those lines be the other way around?
This works for me
Sub export()
Dim myPath, folderPath, fileName, exportFileFullPath As String
Dim arrayOfSheetsToCopy As Variant
Dim sht As Worksheet
Dim newWorkBook As Workbook
folderPath = Application.ActiveWorkbook.Path
fullPath = Application.ActiveWorkbook.FullName
fileName = Replace(Application.ActiveWorkbook.Name, ".xlsm", "")
fileName = Replace(fileName, ".xlsx", "")
exportFileFullPath = folderPath & "\" & fileName & "_export.xlsx"
Set newWorkBook = Workbooks.Add
Call newWorkBook.SaveAs(fileName:=exportFileFullPath, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False)
For Each sht In ThisWorkbook.Sheets
Call sht.Copy(after:=newWorkBook.Sheets(Sheets.Count))
Next sht
Call newWorkBook.Close(saveChanges:=True)
End Sub
or if you want to use predefined sheetnames
For Each sheetName In Array("originalSheet1", "originalSheet2", "originalSheet3")
Call ThisWorkbook.Sheets(sheetName).Copy(after:=newWorkBook.Sheets(Sheets.Count))
Next sheetName
Related
I currently have this code that finds all files and folders and writes it to a table. The problem is is that is it sometimes slow.
The code below is modified so that it writes to an array but I am having issues passing the array on when the code loops.
Ultimately, I would like the array to pass on to the first sub so that I can transpose it into the table at once.
Sub FileAndFolder()
Dim FSOLibrary As Object
Dim FSOFolder As Object
Dim FolderName As String
Dim FilesTbl As ListObject
Set FilesTbl = Range("FilesTbl").ListObject
'Set the folder name to a variable
FolderName = Left$(ActiveWorkbook.Path, InStrRev(ActiveWorkbook.Path, "\"))
'Set the reference to the FSO Library
Set FSOLibrary = CreateObject("Scripting.FileSystemObject")
'Another Macro must call LoopAllSubFolders Macro to start
LoopAllFolders FSOLibrary.GetFolder(FolderName)
'return TempArray here and paste into table
'Range(FilesTbl.ListColumns("File Name").DataBodyRange(1)) = TempArray
End Sub
Sub LoopAllFolders(FSOFolder As Object)
'Don’t run the following macro, it will be called from the macro above
Dim FSOSubFolder As Object
Dim FSOFile As Object
Dim FolderPath As String
Dim FileName As String
Dim TempArray() As String
'For each subfolder call the macro
For Each FSOSubFolder In FSOFolder.SubFolders
LoopAllFolders FSOSubFolder
Next
'For each file, print the name
For Each FSOFile In FSOFolder.Files
'Insert the actions to be performed on each file
FileName = FSOFile.Name
FolderPath = FSOFile.ParentFolder
If Left(FileName, 2) = "~$" Then GoTo NEXTINLOOP
ReDim Preserve TempArray(0 To 3, 0 To i)
TempArray(0, i) = FileName
TempArray(1, i) = FolderPath & "\" & FileName 'file
TempArray(2, i) = FolderPath 'folder
TempArray(3, i) = FolderPath & "\" & FileName 'showpath
i = i + 1
NEXTINLOOP:
Next
End Sub 'TempArray and i clears here
Thanks.
You either need to declare a variable at the module level so that the list of folder information is available to all methods in the module, or change 'LoopAllFolders' to a Function so that you can return the information you have collated.
The function below will return a Variant which contains an array of arrays (normally called a jagged array). You access the jagged array using this nomenclature
Varname(x)(y)
You will need a variable in the calling method to receive the jagged array
e.g.
Dim myFileInfo as Variant
MyFileInfo = LoopAllFolders(FSOLibrary.GetFolder(FolderName))
Here is the updated function
Public Function LoopAllFolders(FSOFolder As Scripting.FileSystemObject) As Variant
'Don’t run the following macro, it will be called from the macro above
Dim FileInfo As Scripting.Dictionary: Set myFileInfo = New Scripting.Dictionary
'For each subfolder call the macro
Dim FSOSubFolder As Scripting.Folder
For Each FSOSubFolder In FSOFolder.SubFolders
LoopAllFolders FSOSubFolder
Next
'For each file, print the name
Dim FSOFile As Scripting.File
For Each FSOFile In FSOFolder.Files
'Insert the actions to be performed on each file
Dim FileName As String
FileName = FSOFile.Name
Dim FolderPath As String
FolderPath = FSOFile.ParentFolder
If Not Left(FileName, 2) = "~$" Then
myFileInfo.Add Array(FileName, FolderPath & "\" & FileName, FolderPath, FolderPath & "\" & FileName)
End If
Next
LoopAllFolders = myFileInfo.Items
End Function
The above code may not be perfect but at least it points you in the right direction.
Based on your question, you might do well by working through a VBA tutorial as functions are fairly fundamental, and if you are unaware of them......
To help you on your journey I'd also recommend installing the fantastic and free RubberDuck addin.
Create a List of Files all subfolders of a Folder
I do not understand what you're doing with FilesTbl, so I modified your solution to create a new workbook with the result. Surely you will figure out how to apply it to the table.
A Quick Fix
Option Explicit
Sub FileAndFolder()
Dim FSOLibrary As Object
Dim FSOFolder As Object
Dim FolderName As String
Dim FilesTbl As ListObject
'Set FilesTbl = Range("FilesTbl").ListObject
'Set the folder name to a variable
FolderName = Left$(ActiveWorkbook.Path, InStrRev(ActiveWorkbook.Path, "\"))
'Set the reference to the FSO Library
Set FSOLibrary = CreateObject("Scripting.FileSystemObject")
Dim TempArray() As Variant ' ByRef
'Another Macro must call LoopAllSubFolders Macro to start
LoopAllFolders FSOLibrary.GetFolder(FolderName), TempArray
'return TempArray here and paste into table
With Workbooks.Add
With ActiveSheet.Range("A1").Resize(UBound(TempArray, 2), UBound(TempArray))
.Value = Application.Transpose(TempArray)
End With
.Saved = True
End With
'Range(FilesTbl.ListColumns("File Name").DataBodyRange(1)) = TempArray
End Sub
Sub LoopAllFolders(FSOFolder As Object, ByRef TempArray As Variant)
'Don’t run the following macro, it will be called from the macro above
Dim FSOSubFolder As Object
Dim FSOFile As Object
Dim FolderPath As String
Dim FileName As String
Dim i As Long
'Dim TempArray() As String
'For each subfolder call the macro
For Each FSOSubFolder In FSOFolder.SubFolders
LoopAllFolders FSOSubFolder, TempArray
Next
'For each file, print the name
For Each FSOFile In FSOFolder.Files
'Insert the actions to be performed on each file
FileName = FSOFile.Name
FolderPath = FSOFile.ParentFolder
If Left(FileName, 2) = "~$" Then GoTo NEXTINLOOP
i = i + 1
ReDim Preserve TempArray(1 To 4, 1 To i)
TempArray(1, i) = FileName
TempArray(2, i) = FolderPath & "\" & FileName 'file
TempArray(3, i) = FolderPath 'folder
TempArray(4, i) = FolderPath & "\" & FileName 'showpath
NEXTINLOOP:
Next
End Sub 'TempArray and i clears here
Want to check if there is a worksheet with the same name as the file.
At the moment I have filnam opening the files as an array but want it to cycle through the code and see if there is a worksheet with the same name.
I have used a split to remove the path name and the extension but cant get it to check.
I apologise for the messiness of the code. Been trying to get it sorted then Ill tidy it up. There is more code but that isnt required for this as I want it to run that code if there isnt a match.
Please can you help?
Sub sort_it_out()
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim Sheet As Worksheet
Dim filnam As Variant
On Error GoTo errorhandler
Set wb1 = ActiveWorkbook
ChDir Application.ActiveWorkbook.path
'get files
filnam = Application.GetOpenFilename(FileFilter:="2D Table Formats (*.htm;*.xlsm;*.html),*.htm;*.xlsm;*.html", Title:="Select 2D Table", MultiSelect:=True)
'set the array
If IsArray(filnam) Then 'if at least one file is selected, this will be an Array
'define j as the array
For j = LBound(filnam) To UBound(filnam)
'remove path and extension
Dim s As String, a() As String, p As String
s = filnam(j)
a() = Split(s, "\")
p = Split(a(UBound(a)), ".")(0)
MsgBox "p " & p
'check if worksheet exists
For Each ws_check In ThisWorkbook.Worksheets()
If ws_check.Name = p Then
MsgBox "Its there"
Exit Sub
Else
End If
Next ws_check
'continue code from here
This then runs the code... but its not looping the array for some reason. Only one file at at a time. Can you please help?
It is a little hard to follow your code but does this do what you are trying to do?
I think you were storing the file name in the p variable so my code below would check each worksheet in the workbook to see if they have the same name as the p variable.
Public Sub CompareWorksheetNamesToFiles()
Dim file_name As String
file_name = ActiveWorkbook.Name
Dim ws_check As Worksheet
For Each ws_check In ThisWorkbook.Worksheets()
If ws_check.Name = p Then
Debug.Print ("Do Something")
End If
Next ws_check
End Sub
I have worked it all out now.
This will now open file locations, shorten their paths to just the filename minus the extension, then ws check checks the sheets against the filename and then looper jumps to the next.
Thank you to alwaysdata for helping me out.
Sub sort_it_out()
Dim filnam As Variant
'open file locations
filnam = Application.GetOpenFilename(FileFilter:="2D Table Formats (*.htm;*.xlsm;*.html),*.htm;*.xlsm;*.html", Title:="Select 2D Table", MultiSelect:=True)
'if at least one file is selected, this will be an Array
If IsArray(filnam) Then
For j = LBound(filnam) To UBound(filnam)
'remove pathway and extension from entire filename and path. ie C:\open.txt becomes open.
Dim s As String, a() As String, p As String
s = filnam(j)
a() = Split(s, "\")
p = Split(a(UBound(a)), ".")(0)
'check if worksheet exists against p ... ie if theres a worksheet called open it will goto the next option if not it will continue through code
For Each ws_check In ThisWorkbook.Worksheets()
If ws_check.Name = p Then
MsgBox p & " has already been transfered across. ", vbExclamation 'lets the user know this is already there.
GoTo looper
Else
End If
Next ws_check
'do something here with the code if not found. IE MSGBOX " NOT FOUND "
'jump to this point if there is a match.
looper:
Next
Else
Exit Sub
End If
End Sub
Currently have a working script that uses FSO, but it also opens .xlsm files within my working directory. I would like to to only open .txt files.
I found this code that should work, however I can't figure out how to apply it to my situation:
Sub test()
' Loop thru all files in the folder
folder = ActiveWorkbook.path
path = folder & "\*.txt"
Filename = Dir(path)
Do While Filename <> ""
'insert other functions here
Loop
End Sub
My Code (Works, but also opens .xlsm files, which I don't want it to do):
Option Explicit
Sub Initialize_barcode_lookup_Array_test()
Dim fso As FileSystemObject
Dim folder As String, path As String, count_txt_files As Long, Filename As String
Dim folder2 As folder
Dim file As file
Dim FileText As TextStream
Dim TextLine As String
Dim Items() As String
Dim ShippingPlanArray() As String
Dim i As Long, j As Long, k As Long
Dim cl As Range
Dim fName
Dim row As Long, column As Long
Dim shipping_plan As Long 'Number of shipping plans text files imported
Dim barcode_Lookup() As String
Dim lastRow As Long
Dim longest_lastRow As Long
Dim counter As Long
Dim FNSKU_Input As String
'<<<< Creating FSO Object >>>>>
'Define longest_lastRow
longest_lastRow = 0
'Define i (References the text file open)
i = 0
' Get a FileSystem object
Set fso = New FileSystemObject
' get the directory you want
Set folder2 = fso.GetFolder(ActiveWorkbook.path)
' Loop only while the files being opened are .txt files:
For Each file In folder2.Files
row = 0
column = 0
Set FileText = file.OpenAsTextStream(ForReading)
Do Until FileText.AtEndOfStream
fName = FileText.ReadLine
'Parse data by tabs (text-tab delimited) into Items() array
Items() = Split(fName, vbTab)
' Redimension Preserve the ShippingPlanArray()
' NOTE: You can only Redimension preserve the last dimension of a multi-dimensional array
' (In this case: row)
ReDim Preserve ShippingPlanArray(9, row)
'Read Data into an Array Variable
For column = LBound(Items) To UBound(Items)
'MsgBox Items(column)
ShippingPlanArray(column, row) = Items(column)
Next column
row = row + 1
Loop
Next file
End Sub
I don't know if fso support an overloaded method for GetFolder where you can specify the pattern. If it does, use that i.e. GetFolder(Path, "*.txt"). If it doesn't, can you not just add a simple condition to check the file extension in your 'for each' loop and only process the ones that ends in '.txt'.
Update:
Try this:
For Each file In folder2.Files
Dim extension As String
extension = LCase(Mid$(file, InStrRev(file, ".")))
If extension = ".txt" Then
Debug.Print "TEST"
End If
Next
I've tested it and it works as expected.
I get this error:
Error 424: Object required
on this line:
ActiveSheet.Paste Destination:=Worksheets("Sheet1").Range(Cells(erow, 1), Cells(erow, 1))
in the code below. Why?
Sub LoopThroughDirectory()
Dim MyFile As String
Dim erow
Dim Filepath As String
Filepath = "C:\Users\Julio Jesus Sanchez\Desktop\MRSK TXT\"
MyFile = Dir("C:\Users\Julio Jesus Sanchez\Desktop\MRSK TXT\")
Do While Len(MyFile) > 0
If MyFile = "MRSK DATABASE.xlsm" Then
Exit Sub
End If
Workbooks.Open (Filepath & MyFile)
Range("A1:K1").Copy
ActiveWorkbook.Close
erow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Paste Destination:=Worksheets("Sheet1").Range(Cells(erow, 1), Cells(erow, 1))
MyFile = Dir
Loop
End Sub
You close the ActiveWorkbook and then refer to ActiveSheet, which ActiveSheet do you mean? If it is the master book you refer to then you should explicitly tell it that by setting it as an object, also is your VBA in a MS Access module or in Excel? You just tagged this as Database and VBA, I guess Excel as you don't have any reference to the Excel object.
Dim sh as Worksheet
Set sh = Workbooks("NameOfWorkBook.xlsx").WorkSheets("WorksheetName")
Then whenever you refer to the sheet:
sh.Paste Destination:=sh.Range(Cells(erow, 1), Cells(erow, 1))
I have a VBA code with which I import a txt file into one cell.
Here's the code (it's not that important):
Sub ReadFile()
' Requires a reference to Microsoft Scripting Runtime (Tools > References)
Dim FSO As FileSystemObject
Dim FSOFile As File
Dim FSOStream As TextStream
Dim Rand
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set FSO = New FileSystemObject
Set FSOFile = FSO.GetFile("C:\Users\sdagfsgedg\Desktop\20121122.log")
Set FSOStream = FSOFile.OpenAsTextStream(ForReading, TristateUseDefault)
Rand = 1
Do While Not FSOStream.AtEndOfStream
ws.Cells(Rand, 1).Value = FSOStream.ReadAll
Loop
End Sub
The text file 20121122.log has about 20.000 lines which are all imported in one cell. How can I split that cell into 20.000 cells (if the log has 20.000 lines). I don't want to read the text file line by line... I want to read it all (it's way more faster) then split every line on a separate row.
LATER EDIT:
Or if there is another solution to read the log file and paste the text as line to row (not everything in one cell as I do right now)
// Code is not tested
Sub ReadFile()
Dim FSO As FileSystemObject
Dim FSOFile As File
Dim FSOStream As TextStream
Dim Rand
Dim row
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set FSO = New FileSystemObject
Set FSOFile = FSO.GetFile("C:\Users\sdagfsgedg\Desktop\20121122.log")
Set FSOStream = FSOFile.OpenAsTextStream(ForReading, TristateUseDefault)
Rand = 1
Dim content As String
Dim lines As Variant
Dim intIndex As Integer
content = FSOStream.ReadAll
lines = split(content, Chr(10))
For intIndex = LBound(lines) To UBound(lines)
ws.Cells(Rand, 1).Value = lines(intIndex)
Rand = Rand + 1
Next
End Sub