WScript / vbscript check if file in directory - csv

IN THE BOTTOM CODE THAT WORKED
Working on a variation of Convert XLS to CSV on command line that I could use to copy xls as csv.
I just want to copy files that are not yet copied, so need to check if file already exists in my target directory.
Was thinking something like:
Set fso=CreateObject("Scripting.FileSystemObject")
Set sourcefldr=fso.getFolder(sourcepath)
Set targetfldr=fso.getFolder(targetpath)
for each sfile in sourcefldr.files
for each tfile in target
if not file in targetfldr.files then
'create excelfile and save as csv
however file in targetfldr.files not working
How can I avoid looping over all my target files every time?
tks in advance!
EDIT:
Incorporated #Pankaj Jaju and #Ansgar Wiechers answer and below is working!
csv_format = 6
sourcestring ="C:\sourcefolder"
deststring= "V:\destfolder"
Set fso=CreateObject("Scripting.FileSystemObject")
Set sourcefldr=fso.getFolder(sourcestring)
Set destfldr=fso.getFolder(deststring)
Dim oExcel
Set oExcel = CreateObject("Excel.Application")
Dim oBook
for each sfile in sourcefldr.files
destname = left(sfile.name,len(sfile.name)-3) & "csv"
fulldest = fso.buildpath(destfldr, destname)
if not fso.FileExists(fulldest) then
Set oBook = oExcel.Workbooks.Open(sfile)
oBook.SaveAs fulldest, csv_format
oBook.Close False
WScript.Echo "Copied " & fulldest
end if
next
oExcel.Quit

Try this !
set fso=createobject("scripting.filesystemobject")
set sourcefldr=fso.getfolder(sourcepath).files
for each sfile in sourcefldr
if not fso.fileexists(fso.buildpath(targetpath, sfile.name)) then
fso.getfile(sfile).copy(fso.buildpath(targetpath, sfile.name))
end if
next

Best bet would be add all of your target folder files into a dictionary. This way you can just use "Exists" to search for it in the dictionary.
Set fso=CreateObject("Scripting.FileSystemObject")
Set filesDic = CreateObject("Scripting.Dictionary")
Set targetfldr=fso.getFolder(targetpath)
'add destination files into dictionary
For Each file in targetfldr.files
filesDic.Add file.name, file.name
Next
This way all you need to do is check the new filename against the dictionary
filesDic.Exists(file.name)
This will just return a true / false
Here is a bit more information about the dictionary http://www.devguru.com/technologies/vbscript/13992

Related

VBS - Loop through multiple .csv files in a folder and convert the files to .xlsx

I managed to get the following piece of code put together:
'Constants
Const xlOpenXMLWorkbook = 51 '(without macro's in 2007-2016, xlsx)
Const xlOpenXMLWorkbookMacroEnabled = 52 '(with or without macro's in 2007-2016, xlsm)
Const xlExcel12 = 50 '(Excel Binary Workbook in 2007-2016 with or without macro's, xlsb)
Const xlExcel8 =56 '(97-2003 format in Excel 2007-2016, xls)
' Extensions for old and new files
strExcel = "xlsx"
strCSV = "csv"
' Set up filesystem object for usage
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Get folder name to process off the command line, make sure it's valid
If (WScript.Arguments.Count > 0) Then
strFolder = WScript.Arguments(0)
If Not objFSO.FolderExists(strFolder) Then
WScript.StdErr.WriteLine "Specified folder does not exist."
WScript.Quit
End If
Else
WScript.StdErr.WriteLine "No folder name specified to process."
WScript.Quit
End If
' Access the folder to process
Set objFolder = objFSO.GetFolder(strFolder)
' Load Excel (hidden) for conversions
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
objExcel.DisplayAlerts = False
' Process all files
For Each objFile In objFolder.Files
' Get full path to file
strPath = objFile.Path
' Only convert CSV files
If LCase(objFSO.GetExtensionName(strPath)) = LCase(strCSV) Then
' Display to console each file being converted
WScript.Echo "Converting """ & strPath & """"
' Load CSV into Excel and save as native Excel file
Set objWorkbook = objExcel.Workbooks.Open(strPath, False, True)
objWorkbook.SaveAs Replace(strPath, strCSV, strExcel), xlOpenXMLWorkbook
objWorkbook.Close False
Set objWorkbook = Nothing
End If
Next
'Wrap up
objExcel.Quit
Set objExcel = Nothing
Set objFSO = Nothing
Unfortunately I have 3 issues:
I was instructed to run this in the following manner:
Copy the code above and saved it as csv.vbs
Go to CMD and type in
cscript csv.vbs "C:\Users\Eitel\Desktop\3rd Party\Work Folder"
This is the path where the CSV files are.
I would prefer to have a way of executing the code by clicking on/opening a VBScript.
I received this error:
Input Error: Can not find script file "C:\Users\Eitel\csv.vbs"
I went to "C:\Users\Eitel\csv.vbs" and pasted the csv.vbs file in this location. I ran the command again and this is what was displayed:
"C:\Users\Eitel\Desktop\3rd Party\Work Folder\TestFile.CSV"
C:\Users\Eitel\csv.vbs(44.9) Microsoft Excel: Cannot save as that name. Document was opened as read-only.
I have no clue what this means or why it happens?
I noticed that while most of the files are .csv extensions, some of the files extensions are displayed as .CSV and some are .csv. I am wondering if this will affect the way in which the script is executed?
Here is the solution I needed:
Link: https://www.experts-exchange.com/questions/29088597/Change-Multiple-csv-files-into-xlsx-files.html?notificationFollowed=205599875
'Constants
Const xlOpenXMLWorkbook = 51 '(without macro's in 2007-2016, xlsx)
Const xlOpenXMLWorkbookMacroEnabled = 52 '(with or without macro's in 2007-2016, xlsm)
Const xlExcel12 = 50 '(Excel Binary Workbook in 2007-2016 with or without macro's, xlsb)
Const xlExcel8 =56 '(97-2003 format in Excel 2007-2016, xls)
' Extensions for old and new files
strExcel = "xlsx"
strCSV = "csv"
strXLS = "xls"
' Set up filesystem object for usage
Set objFSO = CreateObject("Scripting.FileSystemObject")
strFolder = "B:\EE\EE29088597\Files"
' Access the folder to process
Set objFolder = objFSO.GetFolder(strFolder)
' Load Excel (hidden) for conversions
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
objExcel.DisplayAlerts = False
' Process all files
For Each objFile In objFolder.Files
' Get full path to file
strPath = objFile.Path
' Only convert CSV files
If LCase(objFSO.GetExtensionName(strPath)) = LCase(strCSV) Or LCase(objFSO.GetExtensionName(strPath)) = LCase(strXLS) Then
' Display to console each file being converted
Wscript.Echo "Converting """ & strPath & """"
' Load CSV into Excel and save as native Excel file
Set objWorkbook = objExcel.Workbooks.Open(strPath, False, True)
strNewPath = objFSO.GetParentFolderName(strPath) & "\" & objFSO.GetBaseName(strPath) & "." & strExcel
objWorkbook.SaveAs strNewPath, xlOpenXMLWorkbook
objWorkbook.Close False
Set objWorkbook = Nothing
End If
Next
'Wrap up
objExcel.Quit
Set objExcel = Nothing
Set objFSO = Nothing
This will scan the directory for any xls or csv file and convert them into xlsx files.

xlsx to csv: unwantedly asks for confirmation, cannot select range

When I want to convert a xlsx file into a csv with the following code:
WorkingDir = "C:\Users\Admin\Documents\example.xlsx"
Dim fso, FileName, SaveName, myFile
Dim objExcel, objWorkbook
Set fso = CreateObject("Scripting.FilesystemObject")
Set myFile = fso.GetFile(WorkingDir)
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
objExcel.DisplayAlerts = True
FileName = Left(myFile, InStrRev(myFile, "."))
Set objWorkbook = objExcel.Workbooks.Open(myFile)
objWorkbook.Sheets(1).Range("A2:C2").Select
SaveName = FileName & "csv"
objWorkbook.SaveAs SaveName, 23
objWorkbook.Close
Set objWorkbook = Nothing
Set objExcel = Nothing
Set fso = Nothing
Set myFolder = Nothing
It works but asks me if i want to save my changes in the example.csv file. The saving should work without confirming and also should overwrite an eventually existing .csv file.
The second problem is that the range command where i select a specific part (rows and coumns) of the example.xlsx file which will be converted into a .csv file doesnt work. But there is no error. It seems that the vbscript jumps over this command.
Thank you in advance.
Try telling Excel that the file is already saved
objWorkbook.Saved = true
objWorkbook.Close
In terms of saving your select range, you could try
objWorkbook.Sheets(1).Range("A2:C2").Copy
dim sheet: set sheet = objWorkbook.Sheets.Add()
' Add()ing should actually activate the sheet
' sheet.Activate
sheet.Paste
' SaveAs will save the active sheet
objWorkbook.SaveAs FileName, 23
In otherwords, you need to duplicate the data in a second worksheet then save that worksheet as your csv. Closing the workbook (xlsx) without saving it will discard that new sheet.

Scanning multiple CSV files to append a single output file

Starting with this as the code:
Const ForReading = 1
Const ForAppending = 8
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objSourceFile = objFSO.OpenTextFile("Path\file.csv", ForReading)
Set objDestinationFile = objFSO.OpenTextFile("Path\Database.csv", ForAppending)
'Loop start files in dir
Do Until objSourceFile.AtEndOfStream
strLine = objSourceFile.ReadLine
arrFields = Split(strLine, ",")
If arrFields(0) <> """""" Then
strContents = strContents & arrFields(1) & ","
End If
Loop
strContents = strContents & vbCrLf
objSourceFile.Close
objDestinationFile.Write strContents
'Move source file to processed directory
'Loop end files in dir
objDestinationFile.Close
Which is fine for one file at a time, but I'm trying to append many files into the single file.
Appreciate any tips.
Thanks.
Edit: So this was a request that started with a single file which turned into having to migrate many files. The original CSV needed to have its format changed and then placed into another easier to use CSV.
The issue is that there many files and each source file has to be modified before placing it into the destination file. I am new to VB Scripting and I was trying to be concise with my text. Thanks.
I appreciate the help.

FileSystemObject - new object added to dir during the middle of a For loop

I have a VBA function that creates a FileSystemObject instance, and uses it to read the contents of a directory and perform some stuff based on conditional logic.
In the function, I use a loop that reads the contents of the dir. My question is: What happens when a new file is added to the dir after the loop has been opened but before it is closed? Does the operating system know to include this file in the collection of files? Or is a 'snapshot' of sorts taken of the dir when the loop is opened, causing the newly-added file to be overlooked?
Please correct me on any improper terminology I may have used above.
My code is below:
Function fn_FileCheckType()
'load INI data
fn_ReadINI
'does filename end with .xls or .xlsx?
'read files from iDumpFolder
Dim fs As Object
Set fs = CreateObject("Scripting.FileSystemObject")
Dim objFolder As Object
Set objFolder = fs.GetFolder(iDumpFolder)
Dim objFile As Object
For Each objFile In objFolder.files
If (objFile.Name Like "*.xls" Or objFile.Name Like "*.xlsx") Then
'do nothing
Debug.Print objFile.Name & " is valid."
Else
'copy to invalid file archive and delete from inbox
objFile.Copy (iInvalidArchive & "\" & objFile.Name)
MsgBox (objFile.Name & " is not saved as .xls or .xlsx. Please modify and re-import.")
objFile.Delete
End If
Next 'objFile
'Cleanup
Set objFolder = Nothing
Set objFile = Nothing
Set fs = Nothing
End Function
The following VBA code indicates that the .Files collection is a "snapshot" of the files in a folder at the moment that the collection is referenced. Before running the code I placed two files in the test folder: b.txt and c.txt. The Debug.Assert statement suspends the code immediately after entering the loop for the first time. While paused, I added the files a.txt and d.txt and then hit F5 to resume execution. The code only lists the two files that were originally in the folder.
Option Compare Database
Option Explicit
Public Sub FilesCollectionTest()
Dim fso As New FileSystemObject, objFolder As Folder, objFile As File, i As Long
Set objFolder = fso.GetFolder("C:\__tmp\zzzTest")
i = 1
For Each objFile In objFolder.Files
Debug.Assert i > 1
Debug.Print objFile.Name
i = i + 1
Next
Set objFile = Nothing
Set objFolder = Nothing
Set fso = Nothing
End Sub
The way you have your example written objFolder.files is re-evaluated on every iteration and would thus pick up any change. But, I was a little surprised to see that if you so something like
Dim fso As New FileSystemObject
Dim files, f
Set files = fso.GetFolder("C:\~\My test Folder").files
For Each f In files
debug.print f.name
Next f
Debug.Print ' break point here
Debug.Print
That even if you are not in the loop Files is refreshed. I put a breakpoint on the firs Print after the loop, added a file to my folder then hit F8, and Files updated to the right file count.

Converting xls to csv using VBScript and separate by semicolons

I have a VBScript code snippet which converts my xls and xlsx files into csv files. However, I want each cell to be separated by a semicolon rather than a comma. On my computer, the list separator is set to semicolon instead of comma so when I open up an excel window and do save as csv, it separates by semicolon. However, my VBScript produces a csv file separated by commas. I found the code snippet online as I do not really know VBScript (I'm mainly a Java Programmer) that well. How can I change the code snippet to separate the csv files by semicolon rather than by comma?
if WScript.Arguments.Count < 2 Then
WScript.Echo "Error! Please specify the source path and the destination. Usage: XlsToCsv SourcePath.xls Destination.csv"
Wscript.Quit
End If
Dim oExcel
Set oExcel = CreateObject("Excel.Application")
Dim oBook
Set oBook = oExcel.Workbooks.Open(Wscript.Arguments.Item(0))
oBook.SaveAs WScript.Arguments.Item(1), 6
oBook.Close False
oExcel.Quit
WScript.Echo "Done"
you can keep your original script, only need to give a parameter to indicate local setting must apply. This saves my CSV with a ; separator
if WScript.Arguments.Count < 2 Then
WScript.Echo "Error! Please specify the source path and the destination. Usage: XlsToCsv SourcePath.xls Destination.csv"
Wscript.Quit
End If
Dim oExcel
Set oExcel = CreateObject("Excel.Application")
oExcel.DisplayAlerts = FALSE 'to avoid prompts
Dim oBook, local
Set oBook = oExcel.Workbooks.Open(Wscript.Arguments.Item(0))
local = true
call oBook.SaveAs(WScript.Arguments.Item(1), 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, local) 'this changed
oBook.Close False
oExcel.Quit
WScript.Echo "Done"
The use of a comma in delimited text files finds its roots in the regional settings. While the comma is standard in the US, other countries such as Germany use the semicolon instead. You can change the List Separator value in the Regional and Language settings and then choose CSV (Comma delimited) (.csv) from Excel's Save As window. The resulting file will be delimited by whatever value is in the system settings. This script changes default List Separator setting. Then it opens the specified spreadsheet and resaves it. It reverts the system setting to its previous value before finishing.
It accepts two command line parameters. The first is the input spreadsheet; the second is the output filename for the exported file.
strDelimiter = ";"
strSystemDelimiter = "" ' This will be used to store the current sytem value
Const HKEY_CURRENT_USER = &H80000001
' Get the current List Separator (Regional Settings) from the registry
strKeyPath = "Control Panel\International"
strValueName = "sList"
strComputer = "."
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
objRegistry.GetStringValue HKEY_CURRENT_USER, strKeyPath, strValueName, strSystemDelimiter
' Set it temporarily to our custom delimiter
objRegistry.SetStringValue HKEY_CURRENT_USER, strKeyPath, strValueName, strDelimiter
' Open spreadsheet with Excel and save it in a text delimited format
Const xlCSV = 6
Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open(WScript.Arguments.Item(0))
objWorkbook.SaveAs WScript.Arguments.Item(1), xlCSV
objWorkbook.Close vbFalse ' Prevent duplicate Save dialog
objExcel.Quit
' Reset the system setting to its original value
objRegistry.SetStringValue HKEY_CURRENT_USER, strKeyPath, strValueName, strSystemDelimiter
After some testing, it seems that this only works through Excel's Save As dialog and not through command-line or automation. I've changed the script a little to make the Excel window visible and use shortcuts keys to open the Save As dialog through the Excel interface. This should do the trick. It worked for me on Vista x64 with Excel 2007. I hope this works for you.
strDelimiter = ";"
strSystemDelimiter = "" ' This will be used to store the current sytem value
Const HKEY_CURRENT_USER = &H80000001
' Get the current List Separator (Regional Settings) from the registry
strKeyPath = "Control Panel\International"
strValueName = "sList"
strComputer = "."
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
objRegistry.GetStringValue HKEY_CURRENT_USER, strKeyPath, strValueName, strSystemDelimiter
' Set it temporarily to our custom delimiter
objRegistry.SetStringValue HKEY_CURRENT_USER, strKeyPath, strValueName, strDelimiter
' Open spreadsheet with Excel and save it in a text delimited format
Const xlCSV = 6
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = vbTrue
Set objWorkbook = objExcel.Workbooks.Open(WScript.Arguments.Item(0))
WScript.Sleep 500 ' Delay to make sure the Excel workbook is open
strWorkbookName = objExcel.ActiveWorkbook.Name
strTitlebar = strWorkbookName
Set WshShell = CreateObject("WScript.Shell")
WshShell.AppActivate strTitlebar ' Make the workbook active so it receives the keystrokes
WshShell.SendKeys "%fa" ' Keyboard shortcuts for the Save As dialog
WScript.Sleep 500
WshShell.SendKeys "%tc{ENTER}" ' Change the Save As type to CSV
If WScript.Arguments.Count > 1 Then
WshShell.SendKeys "+{TAB}" & WScript.Arguments.Item(1)
WScript.Sleep 500
End If ' This If block changes the save name if one was provided
WshShell.SendKeys "{ENTER}" ' Save the file
WScript.Sleep 500
WshShell.SendKeys "{ENTER}" ' Dismiss the CSV warning dialog
Set WshShell = Nothing
objWorkbook.Close vbFalse ' Prevent duplicate Save dialog
objExcel.Quit
' Reset the system setting to its original value
objRegistry.SetStringValue HKEY_CURRENT_USER, strKeyPath, strValueName, strSystemDelimiter
The Function SaveAs is defined so :
.SaveAs(FileName, FileFormat, Password, WriteResPassword, ReadOnlyRecommended, CreateBackup, AccessMode, ConflictResolution, AddToMru, TextCodepage, TextVisualLayout, Local)
Thas is, to use the semicolon (if your regional language option are correctly set)
ExcelObj.Workbooks(1).SaveAs csvFile, 6,,,,,,,,,,True
You can reopen the file with the FSO object, then do a Replace() on the comma character.
Const OpenAsDefault = -2
Const FailIfNotExist = 0
Const ForReading = 1
Const ForWriting = 2
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set fCSVFile = _
oFSO.OpenTextFile("C:\path\file.csv", ForReading, FailIfNotExist, OpenAsDefault)
sFileContents = fCSVFile.ReadAll
fCSVFile.Close
sFileContents = Replace(sFileContents, ",",";"))
Set fCSVFile = oFSO.OpenTextFile("C:\path\file.csv", ForWriting, True)
fCSVFile.Write(sFileContents)
fCSVFile.Close
I changed the parameter to true, and worked for me.
if WScript.Arguments.Count < 2 Then
WScript.Echo "Erro! Especifique origem e destino. Exemplo: XlsToCsv SourcePath.xls Destination.csv"
Wscript.Quit
End If
Dim oExcel
Set oExcel = CreateObject("Excel.Application")
Dim oBook
Set oBook = oExcel.Workbooks.Open(Wscript.Arguments.Item(0))
call oBook.SaveAs(WScript.Arguments.Item(1), 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, true) --CHANGED
oBook.Close False
oExcel.Quit