How do I get the timestamp of a specific file over multiple files within the same folder? - vba

I'm trying to write a simple script that looks into a folder, finds the specified file, then spits out the timestamp on a cell. That is the easy part which I already have, (using a string & object).
The part where I'm having issues is having this repeat over 400 specific files within a folder of +1,000 files. All the files are labeled differently, but some may have similarities (AB.xls, AC.xls, AD.xls ; A1.xls, A2.xls, etc). I could go the long way and just rinse and repeat just changing the string name to each specific file, but that would take too long to write.
Is there a short cut to loop this or would I need to add a variable line for the file name to change each time?
Here is a snippet:
Sub Timecheck()
Dim oFS As Object
Dim strFilename As String
strFilename = "Where the file is located"
Set oFS = CreateObject("Scripting.FileSystemObject")
Sheets("tab").Activate
ActiveSheet.Cells(3, 3).Value = oFS.GetFile(strFilename).Datelastmodified
Set oFS = Nothing
End Sub

If the names of the files are on another sheet you need to create another function that will iterate through that range of cells.
Once you have that function in place have it call this function:
Sub Timecheck(byval aCell as object,byval X as integer,Y as integer)
Dim oFS As Object
Dim strFilename As String
strFilename = aCell.Text
Set oFS = CreateObject("Scripting.FileSystemObject")
Sheets("tab").Activate
ActiveSheet.Cells(X,Y).Value = oFS.GetFile(strFilename).Datelastmodified
Set oFS = Nothing
End Sub
where X and Y are the coordinates of the cell you want to put the data in. You call it by passing in the cell in the range that you have grabbed from the other sheet.
Alternately if you do not want to have to traverse a range then put each file name in a single cell on the new sheet and delimit it with a character that won't show up in the name. Then take that and break it into the file names.
Good luck.
EDIT:
If you wanted to iterate through the items in a delimited list inside a cell, then once you have the cell text in an object:
http://msdn.microsoft.com/en-us/library/6x627e5f(v=vs.80).aspx
with an input of 'filename1.xls^filename2.xls^filename3.xls'
call once you have the cell object that contains the file list
DoStuff(cellObejct, "^")
Public Sub DoStuff( byval aCell as object, byval specialChar as string)
Dim ListOfNames as Variant
Dim intIndex, xCell, yCell as integer
ListOfNames = Split(aCell.Text,specialChar)
xCell = 1
yCell = 1
For intIndex = LBound(ListOfNames) To UBound(ListOfNames)
TimeCheck(ListOfNames(intIndex),xCell,yCell)
yCell = yCell + 1
Next intIndex
End Sub
Sub Timecheck(byval fName as string,byval X as integer,Y as integer)
Dim oFS As Object
Set oFS = CreateObject("Scripting.FileSystemObject")
Sheets("tab").Activate
ActiveSheet.Cells(X,Y).Value = oFS.GetFile(fName).Datelastmodified
Set oFS = Nothing
End Sub

To loop thought a folder:
Sub timecheck()
Dim FSO As Object
Dim FLD As Object
Dim fil As Object
Dim i As Long
Dim strFolder As String
i = 1
strFolder = "C:\Your Folder Name"
'Create the filesystem object
Set FSO = CreateObject("Scripting.FileSystemObject")
'Get a reference to the folder you want to search
Set FLD = FSO.GetFolder(strFolder)
'loop through the folder and get the file names
For Each fil In FLD.Files
Sheets("Sheet1").Cells(i, 1) = fil.Name ' Filename in column A
Sheets("Sheet1").Cells(i, 2) = fil.datelastmodified ' Date in column B
i = i + 1
Next
End Sub

Related

How to keep leading zeros when opening CSV file in VBA

I have a VBA code that quickly transfer data from CSV files, but unfortunately exclude leading zeros (For example 000123 is converted to 123)
Filename = "c:\text.csv"
Dim wbI As Workbook, wbO As Workbook
Dim wsI As Worksheet
Set wbI = ThisWorkbook
Set wsI = wbI.Sheets("Temp")
Filename = "c:\text.csv"
Set wbO = Workbooks.Open(Filename)
wbO.Sheets(1).Cells.Copy wsI.Cells
wbO.Close SaveChanges:=False
I have tried to add the following after opening the csv file > Cells.NumberFormat = "#"
Set wbO = Workbooks.Open(Filename)
Cells.NumberFormat = "#"
wbO.Sheets(1).Cells.Copy wsI.Cells
wbO.Close SaveChanges:=False
Unfortunately, it is not working and the problem I see is that once the file opens already is missing the leading zeros
Is it possible to open the file without affecting the leading zeros and show all the data as text to maintain the leading zeros?
Try this way, please:
Sub testOpenWithLZeroTxt()
Dim Filename As String, wbI As Workbook, wbO As Workbook, wsI As Worksheet
Dim arrTXT, nrCol As Long, arr(), i As Long, sep As String, lineSep As String
Dim allTxt As String, txtStr As Object, fileTxt As String, fs As Object, f As Object, ts As Object
Set wbI = ThisWorkbook
Set wsI = wbI.Sheets("Temp")
Filename = "c:\text.csv"
fileTxt = Split(Filename, ".")(0) & ".txt" 'create a helper txt file using the csv string content
Set fs = CreateObject("Scripting.FileSystemObject")
allTxt = fs.OpenTextFile(Filename, 1).ReadAll 'reed the csv file content
fs.CreateTextFile fileTxt
Set f = fs.GetFile(fileTxt)
Set ts = f.OpenAsTextStream(2, -2)
ts.write allTxt 'write the csv content in a newly created txt file
ts.Close
'Check the number of text file columns:_______
sep = vbLf ' if not working you can try vbCrLf. It works so on your file
lineSep = "," 'it my be vbTab, ";" etc. It works so on your file
arrTXT = Split(allTxt, sep)
nrCol = UBound(Split(arrTXT(0), lineSep))
'_____________________________________________
ReDim arr(nrCol) 'redim the format array
For i = 0 To nrCol
arr(i) = Array(i + 1, 2) 'fill the format array with variant for TEXT Format!
Next
'open the helper txt file as you need:
Workbooks.OpenText Filename:=fileTxt, origin:=437, startRow:=1, _
DataType:=xlDelimited, Tab:=False, Comma:=True, FieldInfo:=arr()
Set wbO = ActiveWorkbook
'wbO.Sheets(1).cells.Copy wsI.Range("A1") 'copy the content
wbO.Close SaveChanges:=False 'close the file
Kill fileTxt 'kill helper txt file
End Sub
Edited:
I changed the code philosophy. It will firstly read the csv content in a string variable and create a txt file using the obtained string and open it as text, which certainly should work. It will work for any number of columns in the csv file.
The line break in your csv file is unix LF. This corresponds to chr(10).
Since the number of columns in the first row and the number of columns in the next row are inconsistent, a little bias was used. An array was created by doubling the number of columns in the first row.
Sub test()
Dim Ws As Worksheet
Dim Fn As String
Dim Arr As Variant
Fn = "Example.csv"
'Fn = "c:\text.csv"
Set Ws = Sheets("Temp")
Arr = getDatFromCsv(Fn)
With Ws
.Cells.NumberFormat = "#"
.Cells = Empty
.Range("a1").Resize(UBound(Arr, 1) + 1, UBound(Arr, 2) + 1) = Arr
End With
End Sub
Function getDatFromCsv(strFn As String) As Variant
Dim vR() As String
Dim i As Long, r As Long, j As Integer, c As Integer
Dim objStream As Object
Dim strRead As String
Dim vSplit, vRow
Dim s As String
Set objStream = CreateObject("ADODB.Stream")
With objStream
.Charset = "utf-8"
.Open
.LoadFromFile strFn
strRead = .ReadText
.Close
End With
vSplit = Split(strRead, Chr(10)) 'Unix Lf ~~> chr(10)
r = UBound(vSplit)
c = UBound(Split(vSplit(0), ",", , vbTextCompare))
ReDim vR(0 To r, 0 To c * 2)
For i = 0 To r
vRow = Split(vSplit(i), ",", , vbTextCompare)
'If UBound(vRow) = c Then 'if it is empty line, skip it
For j = 0 To UBound(vRow)
vR(i, j) = vRow(j)
Next j
'End If
Next i
getDatFromCsv = vR
Set objStream = Nothing
End Function
Result Image
Use OpenText method instead.
The most important parameter is FieldInfo. You need to pass:
an array containing parse information for individual columns of data. The interpretation depends on the value of DataType. When the data is delimited, this argument is an array of two-element arrays, with each two-element array specifying the conversion options for a particular column. The first element is the column number (1-based), and the second element is one of the XlColumnDataType constants specifying how the column is parsed.
In other words, every column with leading zeros, has to be defined as xlTextFormat.
I'd suggest to record macro. ;) An option to load text data, you'll find under Data tab -> ... -> From text/CSV

Is there method similar to 'Find' available when we Loop through folder (of files) using Dir Function in excel vba?

As we know, we use Find() method to find whether a string or any Microsoft Excel data type exists in an excel.
(Usually we do it on set of data)
I want to know if any such method available when we loop through folder(of files) using Dir function.
Situation:
I have an excel - 'FileNames.xlsx' in which 'Sheet1' has names of files having extensions .pdf/.jpg/.jpeg/.xls/.xlsx/.png./.txt/.docx/ .rtf in column A.
I have a folder named 'Folder' which has most(or all) of the files from 'FileNames.xlsx'.
I have to check whether all the file-names mentioned in the 'FileNames.xlsx' exist in 'Folder'.
For this I have written the below VBScript(.vbs):
strMessage =Inputbox("Enter No. of Files in Folder","Input Required")
set xlinput = createobject("excel.application")
set wb123 =xlinput.workbooks.Open("E:\FileNames.xlsx")
set sh1 =wb123.worksheets("Sheet1")
For i = 2 to strMessage +1
namei = sh1.cells(i,1).value
yesi = "E:\Folder"+ namei +
If namei <> yesi Then
sh1.cells(i,1).Interior.Color = vbRed
Else
End If
Next
msgbox "Success"
xlinput.quit
As I wasn't able to get the required Output I tried it recording a small Excel VBA Macro. (Changed FileNames.xlsx to FileNames.xlsm)
Sub LoopThroughFiles()
Dim lastRow As Long
lastRow = Sheets("Sheet1").UsedRange.Rows.Count
Dim MyFolder As String
Dim filename As Range
Dim MyFile As String
MyFolder = "E:\Folder"
For Each filename In Worksheets("Sheet1").Range("A2A:" & lastRow)
MyFile = Dir(MyFolder & "\*.xlsx")
'Here I actually need to pass all file extensions to Dir
Do While MyFile <> ""
If filename = MyFile Then
'Do Nothing
Else
filename.Interior.Color = vbRed
MyFile = Dir
Next
End Sub
The above is a failed attempt.
I thought of trying it with method similar to Find()
Sub LoopThroughFiles()
Dim lastRow As Long
'Dim LastFile As Long
'Is there need of it (LastFile variable)? I kept this variable
'to save (prior known) count of files in folder.
lastRow = Sheets("Sheet1").UsedRange.Rows.Count
'LastFile = 'Pass count of Files in folder to this variable.
Dim fileName As Range
For Each fileName In Worksheets("Sheet1").Range("A2:A" & lastRow)
Dim rngFnder As Range
On Error Resume Next
'Error at below line.
Set rngFnder = Dir("E:\Folder\").Find(filename)
'This line gives me error 'Invalid Qualifier'
'I am trying to use method similar to Find()
If rngFnder Is Nothing Then
filename.Interior.Color = vbRed
End If
Next
End Sub
But, I couldn't achieve the result. Can anyone tell me is there any such function available to 'Find' whether all filenames in an excel exist in a folder after looping through folder using Dir?
As per my knowledge, Dir function works with only one file extension at a time.
Is it possible to use Dir function for multiple file extensions at a time?
Expected Output:
Assume I have 8 filenames in 'FileNames(.xlsx/.xlsm)'. Out of which Arabella.pdf and Clover.png are not found in 'Folder', Then I want to color cells for these filenames in red background in excel as in below image.
Sub LoopThroughFiles()
Dim lastRow As Long
lastRow = Sheets("Sheet1").UsedRange.Rows.Count
Dim MyFolder As String
Dim filename As Range
Dim MyFile As String
MyFolder = "E:\Folder"
For Each filename In Worksheets("Sheet1").Range("A2:A" & lastRow)
MyFile = MyFolder & "\" & filename
If Not FileExists(MyFile) Then
filename.Interior.Color = vbRed
End If
Next
End Sub
Public Function FileExists(strFullpathName As String) As Boolean
If Dir(strFullpathName) <> "" Then
FileExists = True
Else
FileExists = False
End If
End Function
You can output a list of the files that are contained in the folder. I found a really helpful tutorial on that here: http://software-solutions-online.com/2014/03/05/list-files-and-folders-in-a-directory/#Jump1
If you then loop through both the original and the output lists and look for a match. Easiest is to first colour them all red, and un-colour the matches. Else you would need an additional if-statement that states: When you reach the last element in the original list, and no match has been found, then colour red.
Edit: For continuity's sake I copied the code bits of the link I mentioned above:
Getting all file names form within 1 folder:
Sub Example1()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Get the folder object
Set objFolder = objFSO.GetFolder("D:StuffFreelancesWebsiteBlogArraysPics")
i = 1
'loops through each file in the directory and prints their names and path
For Each objFile In objFolder.Files
'print file name
Cells(i + 1, 1) = objFile.Name
'print file path
Cells(i + 1, 2) = objFile.Path
i = i + 1
Next objFile
End Sub

VBA fetch picture from a folder based on a string name. Contains wildcard

I have an excel file with 160 rows and 2 columns of data - article name, price.
I also have a folder which contains photos for those articles.
The problem is that that picture names are not EXACTLY the same as the article names in my excel sheet.
For example in my sheet I have article name: "3714-012-P140" but in the folder it would be "3714-012-P140---****".
However, after the initial 3 blocks of code (3714; 012; P140 in the example) there will always show up only 1 picture in the search.
How would one go about selecting the picture with a wildcard in it?
Additionally, how would I go about locking the picture into a specific cell in excel? What I mean to say is that when I resize or delete some rows/columns, the pictures move along the cells they are assigned to.
Dim ws As Worksheet
Dim articleCode As String, _
findStr As String
Set ws = Workbooks(1).Worksheets(1)
For i = 1 to ws.UsedRange.Rows.Count
articleCode = ws.Cells(i,1)
findStr = 'some code
ActiveSheet.Pictures.Insert( _
"C:\...path...\" & findStr & ".jpg").Select
Next i
Edit: I need to insert the photo into a third column in each row of data.
Regarding "locking" a picture into a specific cell.
See here for info about how to link a shape to a cell.
Essentially you need to:
Position the picture over a cell. This can be done by setting the pictures (ie shape) .Top and .Left properties to be the same the cell you are linking the picture to.
Set the formula of the shape to equal the cell reference (this will also resize the shape to be the same size as the cell, and cause it to resize if the cell size is changed). See here
The code below taken from here will help you find a file in a folder that matches a "findstring". (It will need to be adapted!)
Sub FindPatternMatchedFiles()
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim objRegExp As Object
Set objRegExp = CreateObject("VBScript.RegExp")
objRegExp.pattern = ".*xlsx"
objRegExp.IgnoreCase = True
Dim colFiles As Collection
Set colFiles = New Collection
RecursiveFileSearch "C:\Path\To\Your\Directory", objRegExp, colFiles, objFSO
For Each f In colFiles
Debug.Print (f)
'Insert code here to do something with the matched files
Next
'Garbage Collection
Set objFSO = Nothing
Set objRegExp = Nothing
End Sub
Have your existing code call a function that accepts the name of the article (articleCode) and returns the path of the image file:
strImage = FindImage(articleCode)
If Len(strImage) > 0 Then ActiveSheet.Pictures.Insert strImage
Then you can write your function like so:
Function FindImage(strArticle As String) As String
Dim objFile As Object
With CreateObject("Scripting.FileSystemObject")
For Each objFile In .GetFolder("c:\path\to\images").Files
If StrComp(Left$(objFile.Name, Len(strArticle)), strArticle, vbTextCompare) = 0 Then
' Found an image file that begins with the article code.
FindImage = objFile.Path
Exit Function
End If
Next
End With
End Function
The function below takes articleCode which is the name of the picture, row and column into which the picture should be input.
Function picInsert(articleCode As String, row As Integer, column As Integer)
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
Dim ws As Worksheet
Set ws = Workbooks(1).Worksheets(2) 'your worksheet where the pictures will be put
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("...path...")
i = 1
For Each objFile In objFolder.Files
If objFile.name Like (articleCode & "*") Then 'finds a picture with similar name to the one searched
With ActiveSheet.Pictures.Insert(objFile.Path)
With .ShapeRange
.LockAspectRatio = msoTrue
.Width = 5
.Height = 15
End With
.Left = ActiveSheet.Cells(row, column).Left
.Top = ActiveSheet.Cells(row, column).Top
.Placement = 1 'locks the picture to a cell
End With
End If
i = i + 1
Next objFile
End Function
This is a test sub with which I tried the function above. Basically a simple loop which goes over the rows, takes the articleCode from first column and inputs a picture into third column using the function above.
Public Sub test()
Dim ws As Worksheet
Dim i As Integer
Dim articleCode As String
Set ws = Workbooks(1).Worksheets(2)
For i = 1 To ws.UsedRange.Rows.Count
articleCode = ws.Cells(i, 1)
Call picInsert(articleCode, i, 3)
Next i
End Sub

Parsing Data in Excel Causes Crash

I was wondering if anyone knew a way to parse rather large data files in Excel VBA because whenever I try the simple data parse it crashes the program. The data is formatted as such
593972,Data,15:59:59.820,9519,9519,Px(25.5),9519,9500,10001,10226,10451,0,0,0,0,0,28.7604,25.4800,25.4841
and there are about 3 million lines formatted exactly the same and I want to pull out certain values in the line if the first value (in the case above it is 593972) is a specific number. I am rather new to VBA so any help would be much appreciated. Thanks so much for your time!
Try using FSO; modify to suit your needs.
Sub ParseFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim strLine As String
Dim arrLine() As String
Dim objFile
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set objFile = fso.OpenTextFile("C:\Temp\Text File.txt", ForReading) '<modify path as needed
Do Until objFile.AtEndOfStream
strLine = Trim(objFile.Readline)
If (strLine <> "") Then
arrLine = Split(strLine, ",") 'one dimensional array
'parse the arrLine to test for the data you need
Dim FirstValue as String
FirstValue = arrLine(0)
If FirstValue = "593972" Then
'put the data in Excel if desired/needed
End If
End If
Loop
objFile.Close
Set objFile = Nothing
End Sub
The Sub below opens a text stream, reads it line by line, and verifies if the first field has a certain value for each line; adapt it to do what you'd want:
Public Sub ReadAndValidate( _
ByVal FileName As String, _
ByVal FieldKey As String _
)
' This function doesn't do error handling, assumes that the '
' field separator is "," and that the key field is first. '
' It uses the "Scripting" lib; "Microsoft Scripting Runtime"'
' needs to be referenced by the containing workbook. '
Dim line As String
Dim keylen As Long
Dim fs As Scripting.FileSystemObject
Dim f As Scripting.TextStream
Let FieldKey = FieldKey & "," ' add the separator to the key '
Let keylen = Strings.Len(FieldKey)
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.OpenTextFile( _
FileName:=FileName, _
IOMode:=IOMode.ForReading _
)
While Not f.AtEndOfStream
Let line = f.ReadLine()
If Strings.Left$(line, keylen) = FieldKey Then
' replace the statement below with your code '
Debug.Print line
End If
Wend
f.Close
End Sub

Extract text from column D to txt files and name files based on content of column C

Apologies for a noob question but I've been fiddling around with this code:
https://stackoverflow.com/a/7151963/3672159
and can't seem to get it modified to do the following (very slight modifications of the code above):
Take as input a worksheet that is called "Export Data" (rather than "Sheet1" as in the existing code; the space seems to cause problems)
Automatically create an empty file for each cell of column D, which should have as its content the value of the respective D cell (same as with the "Disclaimer" data in the code above)
Name each file based on the values of the corresponding C cells (so for me it's name=column C, content=column D rather than B and A in the original code).
I've modified the code as follows:
Sub ExportFiles()
Dim sExportFolder, sFN
Dim rStoreId As Range
Dim rAbstract As Range
Dim oSh As Worksheet
Dim oFS As Object
Dim oTxt As Object
'sExportFolder = path to the folder you want to export to
'oSh = The sheet where your data is stored
sExportFolder = "my file path\txt"
Set oSh = Export Data
Set oFS = CreateObject("Scripting.Filesystemobject")
For Each rStoreId In oSh.UsedRange.Columns("D").Cells
Set rAbstract = rStoreId.Offset(, -1)
'Add .txt to the article name as a file name
sFN = rStoreId.Value & ".txt"
Set oTxt = oFS.OpenTextFile(sExportFolder & "\" & sFN, 2, True)
oTxt.Write rAbstract.Value
oTxt.Close
Next
End Sub
The only thing this does (as does the original code) is create one empty unnamed txt file.
Any help is greatly appreciated!
Try this...
Sub ExportFiles()
Dim sExportFolder, sFN
Dim rStoreId As Range
Dim rAbstract As Range
Dim oSh As Worksheet
Dim oFS As Object
Dim oTxt As Object
'sExportFolder = path to the folder you want to export to
'oSh = The sheet where your data is stored
sExportFolder = "C:\Users\Rich\Desktop"
Set oSh = ThisWorkbook.Sheets("Export Data")
Set oFS = CreateObject("Scripting.Filesystemobject")
For Each rStoreId In oSh.Columns("D").Cells
If IsEmpty(rStoreId.Value) Then
Exit For
End If
Set rAbstract = rStoreId.Offset(, -1)
'Add .txt to the article name as a file name
sFN = rStoreId.Value & ".txt"
Set oTxt = oFS.OpenTextFile(sExportFolder & "\" & sFN, 2, True)
oTxt.Write rAbstract.Value
oTxt.Close
Next
End Sub
You need to select the sheet correctly with (Assuming it is within the same workbook as the code)...
Set oSh = ThisWorkbook.Sheets("Export Data")
And I changed how you were iterating through the range...
For Each rStoreId In oSh.Columns("D").Cells
If IsEmpty(rStoreId.Value) Then
Exit For
End If
Next
This just goes through column D's cells until it hits an empty one, I couldn't quite get it working using UsedRange and this (more old skool) method works in my tests.
This works for me. It writes each value in cells in column D to a text file that is named based on the entry in column C and puts all text files in user specified folder:
Sub ExportFiles()
Dim exportFolder As String
Dim fso As FileSystemObject
Dim stream As TextStream
Dim cl As Range
exportFolder = "C:\User\ExportFolder" //Add you folder path here
Set fso = New FileSystemObject
For Each cl In Worksheets("Export Data").UsedRange.Columns("D").Cells
Set stream = fso.CreateTextFile(filepath & "\" & cl.Offset(0, -1).Value & ".txt", 2, True)
stream.Write cl.Value
stream.Close
Next
End Sub