I have a code for Excel 2007 that runs without failing.
But it is extremely & unusually slow - making my computer unresponsive for the 1-2 minutes it runs.
The files are about 14,000 kb's - so not too large.
If possible I'd like someone to tell me what I could do to make it run without causing my computer to hang. Thanks in advance.
Sub ReadFileIntoExcel()
Dim fPath As String
Const fsoForReading = 1
Dim readlength As Integer
Dim readstart As Integer
readlength = Worksheets("READFILE").Cells(1, "E").Value
readstart = Worksheets("READFILE").Cells(1, "D").Value
fPath = Worksheets("READFILE").Cells(1, "C").Value
Dim objFSO As Object
Dim objTextStream As Object, txt, allread, rw
Set objFSO = CreateObject("scripting.filesystemobject")
If objFSO.FileExists(fPath) Then
Set objTextStream = objFSO.OpenTextFile(fPath, fsoForReading)
rw = 1
Do Until objTextStream.AtEndOfStream
txt = objTextStream.ReadLine
allread = Trim(Mid(txt, readstart, readlength))
With ActiveWorkbook.Sheets("READFILE").Cells(rw, 7).Resize(1, 1)
.NumberFormat = "#" 'format cells as text
.Value = Array(allread)
End With
rw = rw + 1
Loop
objTextStream.Close
Set objTextStream = Nothing
Set objFSO = Nothing
Exit Sub
I updated your code to use an array rather than cell by cell wrote and it ran instantly
Optimisations made
Avoid cell range loops, especially writing cell by cell. Use arrays instead. This is the big one
Resize(1,1) does nothing as it keeps the cell as a single cell
Long is more efficient than Integer
Use the string functions Mid$ rather than their slower variant alternatives Mid
The allread variable was an un-necessary intermediate step
Using variable names for objects (ie ws for the worksheet), prevents longer references
code
Sub ReadFileIntoExcel()
Dim fPath As String
Dim ws As Worksheet
Const fsoForReading = 1
Dim readlength As Long
Dim readstart As Long
Dim rw as Long
Dim X()
Set ws = Worksheets("READFILE")
readlength = ws.Cells(1, "E").Value
readstart = ws.Cells(1, "D").Value
fPath = ws.Cells(1, "C").Value
Dim objFSO As Object
Dim objTextStream As Object
Set objFSO = CreateObject("scripting.filesystemobject")
If objFSO.FileExists(fPath) Then
Set objTextStream = objFSO.OpenTextFile(fPath, fsoForReading)
rw = 1
ReDim X(1 To 1, 1 To 1000)
Do Until objTextStream.AtEndOfStream
txt = objTextStream.ReadLine
If rw Mod 1000 = 0 Then ReDim Preserve X(1 To 1, 1 To UBound(X, 2) + 1000)
X(1, rw) = Trim$(Mid$(txt, readstart, readlength))
rw = rw + 1
Loop
ws.[G1].Resize(UBound(X, 2), 1) = Application.Transpose(X)
ws.Columns("G").NumberFormat = "#"
objTextStream.Close
Set objTextStream = Nothing
Set objFSO = Nothing
Exit Sub
End If
End Sub
You might try turning off screen updating while the cells are being updated. If you are touching a great many cells, this will definitely speed things up.
Application.ScreenUpdating = False
...update cells...
Application.ScreenUpdating = True
There are other things you can do as well, such as turning off calculations, but it doesn't sound like you have formulas trying to evaluate the cells your setting.
Related
First time I ask a question here, but so far answers from this forum have always helped me a lot. However, now I have been dealing with a problem for weeks and unfortunately never found sufficient answers.
The current task is to update an already existing macro regarding data processing and display to a newer UI and increased usability. However, in the same sense I would like to improve the speed of the macro.
My current problem is opening, loading, splitting and pasting multiple selected .txt files into appropriately named sheets. The files can very quickly have over a hundred thousand entries of data, all separated by either space or enter. For importing and splitting a single file, I stumbled across this code, which I have subsequently adapted for my circumstances:
Private Sub testModule1()
Dim arr, tmp, output
Dim Datei
Dim FSO
Dim x, y As Integer
Dim str_string, filePath As String
Set FSO = CreateObject("Scripting.FilesystemObject")
filePath = Application.GetOpenFilename
Set Datei = FSO.OpentextFile(filePath)
str_string = Datei.readall
Datei.Close
arr = Split(str_string, vbCrLf)
ReDim output(UBound(arr), 50)
For x = 0 To UBound(arr)
tmp = Split(arr(x), " ")
For y = 0 To UBound(tmp)
output(x, y) = tmp(y)
Next
Next
Sheets("Sheet1").Range("A1").Resize(UBound(output) + 1, UBound(output, 2)) = output
End Sub
This part lets me select a single file, splits the cells as desired, and finally posts it to the first sheet.
For importing multiple files and naming the sheet after the file name, I found code here (the first solution):
https://www.mrexcel.com/board/threads/importing-multiple-text-files-in-to-multiple-work-sheets-with-text-file-names.1147363/
However, it currently opens in a new workbook, Windows tells me several times that data is overwritten when I do this, and the delimiter is also limited to only one character.
I am currently failing to find a reasonable combination of these two actions. The direct opening and reasonable splitting of several selected files and the subsequent integrating into several sheets named accordingly by file name.
In the old version of the macro, all file paths were first retrieved and stored in cells for this purpose, and later looped through these cells while reading and integrating the individual data in the process. However, everything in a sheet and rather, as I find, cumbersome.
I hope to find a more elegant solution for this problem than having to store data in sheets during editing and I am also happy about other suggestions and solutions.
EDIT:
After the hint from Solar Mike I was able to adapt the code to this:
Private Sub testModule2()
Dim fDialog As FileDialog
Dim fPath As Variant
Dim FSO
Dim Datei
Dim arr, tmp, output
Dim file, fileName As String
Dim x, y As Integer
Dim newSht As Worksheet
Application.ScreenUpdating = False
Set fDialog = Application.FileDialog(msoFileDialogFilePicker)
With fDialog
.AllowMultiSelect = True
.Title = "Please select files to import"
.Filters.Clear
.Filters.Add "VBO Files", "*.vbo"
If .Show = True Then
For Each fPath In .SelectedItems
Set FSO = CreateObject("Scripting.FilesystemObject")
fileName = FSO.GetFilename(fPath)
Set Datei = FSO.OpentextFile(fPath)
file = Datei.readall
Datei.Close
arr = Split(file, vbCrLf)
ReDim output(UBound(arr), 50)
For x = 0 To UBound(arr)
tmp = Split(arr(x), " ")
For y = 0 To UBound(tmp)
output(x, y) = tmp(y)
Next
Next
Set newSht = ActiveWorkbook.Sheets.Add(after:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
newSht.Name = fileName
Sheets(fileName).Range("A1").Resize(UBound(output) + 1, UBound(output, 2)) = output
Next
End If
End With
Application.ScreenUpdating = True
End Sub
This does what is actually required, but just importing only 5 files already takes about a minute. Since on average up to 20 files can/should be imported and the processing of the data still takes place afterwards, this still seems a bit much to me.
It should be noted that the data sets are reduced again during processing, something between 40 and 80% of the data are filtered. Unfortunately I don't have the expertise to do this before, even if this would reduce the loading time.
Does this do what you want?
Sub CombineTextFiles()
'updateby Extendoffice
Dim xFilesToOpen As Variant
Dim I As Integer
Dim xWb As Workbook
Dim xTempWb As Workbook
Dim xDelimiter As String
Dim xScreen As Boolean
On Error GoTo ErrHandler
xScreen = Application.ScreenUpdating
Application.ScreenUpdating = False
xDelimiter = "|"
xFilesToOpen = Application.GetOpenFilename("Text Files (*.txt), *.txt", , "Kutools for Excel", , True)
If TypeName(xFilesToOpen) = "Boolean" Then
MsgBox "No files were selected", , "Kutools for Excel"
GoTo ExitHandler
End If
I = 1
Set xTempWb = Workbooks.Open(xFilesToOpen(I))
xTempWb.Sheets(1).Copy
Set xWb = Application.ActiveWorkbook
xTempWb.Close False
xWb.Worksheets(I).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:="|"
Do While I < UBound(xFilesToOpen)
I = I + 1
Set xTempWb = Workbooks.Open(xFilesToOpen(I))
With xWb
xTempWb.Sheets(1).Move after:=.Sheets(.Sheets.Count)
.Worksheets(I).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:=xDelimiter
End With
Loop
ExitHandler:
Application.ScreenUpdating = xScreen
Set xWb = Nothing
Set xTempWb = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description, , "Kutools for Excel"
Resume ExitHandler
End Sub
Unfortunately, after a bit more trial and error with my edited code, I haven't found a better way to optimize the process, so I'm posting the final code in response to the question.
The reduction of the amount of data is now done by a third party program and speeds up the processing sufficiently.
Option Explicit
Public Sub fileImporter()
Dim fDialog As FileDialog
Dim fPath As Variant
Dim FSO
Dim Data
Dim arr, tmp, output
Dim file, fileName As String
Dim x, y As Integer
Dim newSht As Worksheet
Application.ScreenUpdating = False
Set fDialog = Application.FileDialog(msoFileDialogFilePicker)
With fDialog
.AllowMultiSelect = True
.Title = "Please select files to import"
.Filters.Clear
.Filters.Add "VBO Files", "*.vbo" 'VBO Files are opened and handled like Text Files
If .Show = True Then
For Each fPath In .SelectedItems
Set FSO = CreateObject("Scripting.FilesystemObject")
fileName = FSO.GetFilename(fPath)
Set Data = FSO.OpentextFile(fPath)
file = Data.readall
Data.Close
arr = Split(file, vbCrLf)
ReDim output(UBound(arr), 50)
For x = 0 To UBound(arr)
tmp = Split(arr(x), " ")
For y = 0 To UBound(tmp)
output(x, y) = tmp(y)
Next
Next
Set newSht = ActiveWorkbook.Sheets.Add(after:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
newSht.Name = fileName
Sheets(fileName).Range("A1").Resize(UBound(output) + 1, UBound(output, 2)) = output
Next
End If
End With
Application.ScreenUpdating = True
End Sub
Thanks for all the help and I hope this can help someone else too.
I'm currently working with a workbook containing 34 different tabs.
I'm trying to extract Monthly Data from each of the tabs and Transpose it into daily figures for each specific city.
I have put all the dates within the year 2019 as columns in order to present it as daily figures. (See example in img below)
Each tab contains data for each specific city.
I always want to extract the data present on row 20 from column 4 to 15 in each tab for each specific city. ( see 2nd image below highlighted in yellow)
Public Sub CreateArray()
Dim myArrayOfMonths(11) As Double
Dim currentWorkbook As Workbook
Dim currentSheet As Worksheet
Dim otherSheet As Worksheet
Dim i As Integer
Dim r As Integer
Dim c As Integer
Dim j As Integer
Set currentWorkbook = ActiveWorkbook
Set otherSheet = currentWorkbook.Worksheets("Output")
i = 1
For Each currentSheet In currentWorkbook.Worksheets
r = 20
j = 0
For c = 4 To 15
myArrayOfMonths(j) = ActiveSheet.Cells(r, c)
j = j + 1
Next c
Debug.Print myArrayOfMonths(0)
i = i + 1
Next currentSheet
Set currentSheet = Nothing
Set currentWorkbook = Nothing
End Sub
In my code I'm trying to run through all of the tabs with a loop
and with a 2nd loop check the date (row 16, column 4 to 15) and extract it on my template (Similiar to a vlookup) Unfortunately, it never passes through the first tab as i=0 always for some reason.
Could you please advise?
Would you be able to do something like this?
Option Explicit
Public Sub PopulateOutput()
Dim outputSheet As Worksheet
Dim i As Integer
Set outputSheet = ActiveWorkbook.Worksheets("Output")
' starting at index 2 since output sheet looks like index 1
For i = 2 To ActiveWorkbook.Worksheets.Count
With ActiveWorkbook.Worksheets(i)
outputSheet.Range("B" & i & ":M" & i).Value = .Range("D20:O20").Value
End With
Next
End Sub
Does this suit your needs?
Public Sub CreateArray()
Dim myArrayOfMonths(11) As Double
Dim currentWorkbook As Workbook
Dim currentSheet As Worksheet
Dim otherSheet As Worksheet
Dim r As Integer
Dim c As Integer
Set currentWorkbook = ActiveWorkbook
Set otherSheet = currentWorkbook.Worksheets("Output")
For Each currentSheet In currentWorkbook.Worksheets
r = 20
For c = 4 To 15
myArrayOfMonths(c - 4) = myArrayOfMonths(c - 4) + currentSheet.Cells(r, c)
Next c
Next currentSheet
otherSheet.Range("B1:M1").Value = myArrayOfMonths
Set currentSheet = Nothing
Set currentWorkbook = Nothing
End Sub
Use currentSheet.Cells(r,c) instead of ActiveSheet
or use currentSheet.Activate and then myArrayOfMonths(j) = ActiveSheet.Cells(r, c), but try to avoid ActiveSheet.
Hopefully i've phrased that right...
I came across something online stating that copy and pasting wastes precious time. It's better to assign values more directly, without using excel functions.
I found a section in a VBA book explaining how to store a range in a 2D array.
Now what if I wanted to copy and paste a range from a dynamic number of worksheets into another one main sheet with this method?
In my head, I imagine stacking more and more values into an array, then dumping the array where I'd like it to go, into a range whose size is defined by the dimensions of the big array.
In practice, all I have managed to create is something like the below, performing the same simple action for each worksheet in turn.
Is it possible to do this better? That runs faster? Help a brother out!
Sub arrayCopyPaste()
Dim Obj As Range
Dim Data As Variant
Dim ws As Worksheet
Dim sheetCount As Integer
Dim LR As Integer
sheetCount = Sheets.Count
Set ws = Sheets.Add
ws.Move After:=Worksheets(Worksheets.Count)
For i = 1 To sheetCount
Data = Sheets(i).Range("A1:B9")
LR = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Set Obj = ws.Range("A" & LR)
Set Obj = Obj.Resize(UBound(Data, 1), UBound(Data, 2))
Obj.Value = Data
Next i
End Sub
With just about any code I use, I like to make a call to this routine I made:
Sub SpeedupCode(Optional ByVal Val As Boolean = True)
With Application
If Val = True Then
.ScreenUpdating = False
.Calculation = xlCalculationManual
Else
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End If
End With
End Sub
So, in your code you would simply use it as follows:
Sub arrayCopyPaste()
Dim Obj As Range
Dim Data As Variant
Dim ws As Worksheet
Dim sheetCount As Integer
Dim LR As Integer
SpeedupCode
sheetCount = Sheets.Count
Set ws = Sheets.Add
ws.Move After:=Worksheets(Worksheets.Count)
For i = 1 To sheetCount
Data = Sheets(i).Range("A1:B9")
LR = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Set Obj = ws.Range("A" & LR)
Set Obj = Obj.Resize(UBound(Data, 1), UBound(Data, 2))
Obj.Value = Data
Next i
SpeedupCode False
End Sub
While this does not necessarily optimize your code, it can significantly improve the performance on every project that you do. In the event that your code requires a newly calculated variable in your worksheet, you can always use Application.Calculate before you grab that variable, but generally, it shouldn't be needed.
I'd be inclined to use your current approach and just boil it down a bit.
Sub arrayCopyPaste()
Dim ws As Worksheet
Set ws = Sheets.Add(After:=Worksheets(Worksheets.Count))
For i = 1 To Sheets.Count - 1
With Sheets(i).Range("A1:B9")
ws.Cells(ws.Rows.Count, 1).End(xlUp).Offset(1, 0).Resize( _
.Rows.Count, .Columns.Count).Value = .Value
End With
Next i
End Sub
This version is slightly more efficient due to writing the results all at once, though you probably won't notice much of a difference unless you're working with very large ranges.
Sub test()
'Same as original: final array is 2 columns wide, (3 * number of sheets) rows long
Call mergeRangeValues("A1:B3", "Results", True)
'Alternate version: final array is 3 rows long, (2 * number of sheets) columns wide
'Call mergeRangeValues("A1:B3", "Results", False)
End Sub
Sub mergeRangeValues(rngString As String, newWSName As String, stackRows As Boolean)
'Merges the same range (rngString) from all sheets in a workbook
'Adds them to a new worksheet (newWSName)
'If stackRows = True, values are stacked vertically
'If stackRows = False, values are stacked horizontally
Dim sheetCount As Long
Dim newWS As Worksheet
sheetCount = ThisWorkbook.Sheets.Count
Set newWS = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(sheetCount))
newWS.Name = newWSName
Dim numCols As Long
Dim numRows As Long
numCols = newWS.Range(rngString).Columns.Count * IIf(stackRows, 1, sheetCount)
numRows = newWS.Range(rngString).Rows.Count * IIf(stackRows, sheetCount, 1)
ReDim resultsArr(1 To numRows, 1 To numCols) As Variant
'''Longer version:
'If stackRows Then
'numCols = newWS.Range(rngString).Columns.Count
'numRows = newWS.Range(rngString).Rows.Count * sheetCount
'Else
'numCols = newWS.Range(rngString).Columns.Count * sheetCount
'numRows = newWS.Range(rngString).Rows.Count
'End If
'''ie "If you want to stack the results vertically, make the array really long"
'''or "If you want to stack the results horizontally, make the array really wide"
Dim i As Long
For i = 0 To sheetCount - 1
Dim tempArr As Variant
tempArr = ThisWorkbook.Sheets(i + 1).Range(rngString).Value
Dim j As Long
Dim k As Long
If stackRows Then
For j = LBound(tempArr, 1) To UBound(tempArr, 1)
For k = LBound(tempArr, 2) To UBound(tempArr, 2)
resultsArr(j + i * (numRows / sheetCount), k) = tempArr(j, k)
Next
Next
Else
For j = LBound(tempArr, 1) To UBound(tempArr, 1)
For k = LBound(tempArr, 2) To UBound(tempArr, 2)
resultsArr(j, k + i * (numCols / sheetCount)) = tempArr(j, k)
Next
Next
End If
Next
With newWS
.Range(.Cells(1, 1), .Cells(numRows, numCols)).Value = resultsArr
End With
End Sub
I have no clue how to do this so any help will be awesome. Using an array, I send row by row to an excel workbook, which does numerous calculations (too many to be programmed) and spits out 13 values which I want to store into another array. Is this possible?
Dim aP() as Variant
Dim wbR as Workbook
Dim wsR as Worksheet
Dim i as Long
Set wbR = Workbooks.Open([directory])
Set wsR = wbR.Sheets("Sheet1")
aP = Application.Transpose(Activesheet.Range("A1:Z100"))
For i = 1 to 100
wsR.Range("A1:A26") = Application.Index(aP, [row(1:26)], i)
'this is where I need help. Want to paste range C1:C13 into another array,
'so that I can paste it back into the activesheet. I do not wish to paste it
'straight back to the worksheet, but accumulate all the data into array and
'and then paste the array into the activesheet
Next i
Exit Sub
It seems like you're are trying to make your code ultra efficient. I made a few changes that may speed it up.
Sub BuildArrayR100C26()
Dim arData(99, 12)
Dim arCalculations
Dim i As Integer, j As Integer
Dim wbR As Workbook
Dim wsR As Worksheet
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set wbR = Workbooks.Open([directory])
Set wsR = wbR.Sheets("Sheet1")
For i = 0 To 99
wsR.Range("A1:A26").Value = Application.Transpose(ActiveSheet.Range("A1:Z1").Offset(i))
Application.Calculate
arCalculations = wsR.Range("C1:C13").Cells(j + 1)
For j = 0 To 12
arData(i, j) = arCalculations(j + 1, 1)
Next
Next i
Sheet2.Range("A1").Resize(UBound(arData, 1), UBound(arData, 2)).Value = arData
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
This line paste the range into wsR one row at a time.
wsR.Range("A1:A26").Value = Application.Transpose(ActiveSheet.Range("A1:Z1").Offset(i))
This loop copies your calculations into an array
For j = 0 To 12
arData(i, j) = wsR.Range("C1:C13").Cells(j + 1)
Next
Turn off ScreenUpdating and Calculation
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Recalculate after we paste the new data to be calculated
Application.Calculate
I have more than 50 files needed to create the pivot table and each file has the same exact formort with different contents. So far, I have finished creating the code for the pivot and it works very well when running alone, however, it failed when I tried to run the code for all workbooks in the same folder. I don't know what happened and why it kept showing that no files could be found despite nothing wrong about the pathname.
Sub DoAllFiles()
Dim Filename, Pathname As String
Dim WB As Workbook
Pathname = "D:\Reports"
Filename = Dir(Pathname & "\*.xls*")
Do While Filename <> ""
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Set WB = Workbooks.Open(Pathname & Filename) 'open all files
PivotX WB
WB.Close SaveChanges:=True
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Filename = Dir()
Loop
End Sub
Here is the code for pivot and it works very well when running it alone:
Sub PivotX(WB As Workbook)
Dim Lrow, Lcol As Long
Dim wsData As Worksheet
Dim rngRaw As Range
Dim PvtTabCache As PivotCache
Dim PvtTab As PivotTable
Dim wsPvtTab As Worksheet
Dim PvtFld As PivotField
Set wsData = ActiveSheet
Lrow = wsData.Cells(Rows.Count, "B").End(xlUp).Row
Lcol = wsData.Cells(1, Columns.Count).End(xlToLeft).Column
Set rngRaw = wsData.Range(Cells(1, 1), Cells(Lrow, Lcol))
Set wsPvtTab = Worksheets.Add
wsData.Select
ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=rngRaw, Version:=xlPivotTableVersion12).CreatePivotTable TableDestination:=wsPvtTab.Range("A3"), TableName:="PivotTable1", DefaultVersion:=xlPivotTableVersion12
Set PvtTab = wsPvtTab.PivotTables("PivotTable1")
PvtTab.ManualUpdate = True
Set PvtFld = PvtTab.PivotFields("Month")
PvtFld.Orientation = xlPageField
PvtTab.PivotFields("Month").ClearAllFilters
Set PvtFld = PvtTab.PivotFields("Year")
PvtFld.Orientation = xlPageField
PvtTab.PivotFields("Year").ClearAllFilters
Set PvtFld = PvtTab.PivotFields("Fund_Code")
PvtFld.Orientation = xlRowField
PvtFld.Position = 1
Set PvtFld = PvtTab.PivotFields("Curr")
PvtFld.Orientation = xlColumnField
PvtFld.Position = 1
wsPvtTab.PivotTables("PivotTable1").PivotFields("Curr").PivotItems("USD").Position = 1
With PvtTab.PivotFields("Trx_Amount")
.Orientation = xlDataField
.Function = xlSum
.NumberFormat = "#,##0;[red](#,##0)"
End With
wsPvtTab.PivotTables("Pivottable1").RowAxisLayout xlTabularRow
'Remove grand total
wsPvtTab.PivotTables("Pivottable1").RowGrand = False
For Each PvtTbCache In ActiveWorkbook.PivotCaches
On Error Resume Next
PvtTbCache.Refresh
Next PvtTbCache
'Determine filter value
Set PvtFld = PvtTab.PivotFields("Year")
PvtFld.ClearAllFilters
PvtFld.EnableMultiplePageItems = True
With PvtFld
.AutoSort xlmnual, .SourceName
For Each Pi In PvtFld.PivotItems
Select Case Pi.Name
Case "2014"
Case Else
Pi.Visible = False
End Select
Next Pi
.AutoSort xlAscending, .SourceName
End With
'determine filter value
Set PvtFld = PvtTab.PivotFields("Month")
PvtFld.ClearAllFilters
PvtFld.EnableMultiplePageItems = True
With PvtFld
.AutoSort xlmnual, .SourceName
For Each Pi In PvtFld.PivotItems
Select Case Pi.Name
Case "11"
Case Else
Pi.Visible = False
End Select
Next Pi
.AutoSort xlAscending, .SourceName
End With
PvtTab.ManualUpdate = False
End Sub
Any help would be very much appreciated. Thank you very much in advance.
This should solve your problem:
Set WB = Workbooks.Open(Pathname & "\" & Filename)
When I tried using your code, for some reason, it did not retain the backslash you put at the beginning of the "Filename" variable. That would explain why VBA couldn't find the files. Adding it back should between the path name and file name should make it work correctly
I believe you have the answer to your base problem above but I would offer the following 'tweaks' to avoid screen flashing and unrecovered variable assignment.
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Do While Filename <> ""
Set WB = Workbooks.Open(Pathname & "\" & Filename) 'open all files
Call PivotX(WB)
WB.Close SaveChanges:=True
Set WB = Nothing
Filename = Dir()
Loop
Application.DisplayAlerts = True
Application.ScreenUpdating = True
The Set WB = Nothing is really only purposeful on the last pass when WB is not reassigned but your PivotX sub could use several Set nnn = Nothing before exiting. While the reference count is supposed to be decremented (and memory consequently released), that is not always the case. (see Is there a need to set Objects to Nothing inside VBA Functions) In short, it is just good coding practise.
Finally, using Dim Filename, Pathname As String declares Filename as a variant, not a string type. It isn't making any difference here but you should be aware of what your variables are being declared as.