Open Relative path in VBS with OpenText and SaveAs method - excel

ok so I have some code in a vbs file, where basically I want to open a CSV file. Perform some changes (I can work that out later) and then save it as an xls. The code works flawlessly when run with a fully qualified file path. However I need the file path to be relative. The files will always be opened and saved to the same path the script is run from. Ive looked at GetParentFolderName and GetAbsolutePathName. However I cant figure how to call the fully qualified path in the text. I've tried just putting the variable where the file name is with and without quotes, appended it with a period.
Any example on building the function or whatever, and then calling it in the code below would be a huge help.
Dim myXL
Const xlDelimited = 1
Const xlWorkbookNormal = -4143
Set myXL=CreateObject("Excel.Application")
myXL.Visible=False
myXL.WorkBooks.OpenText "file.csv", , , xlDelimited, , , , , True
myXL.DisplayAlerts=False
MORE CODE WILL GO HERE
myXL.ActiveWorkbook.SaveAs "new_file.xls", xlWorkbookNormal
myXL.DisplayAlerts=True
myXL.ActiveWorkbook.Close False
myXL.Quit
Set myXL = Nothing

You can get the path of your script by using this code that i Found at an answer about Relative Path
p = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
p should be the path to your script you can then edit "file.csv" to p & "\file.csv" and so.

To point out/emphasize that
you should never use string concatenation to build pathes; .BuildPath() is the way to go
"relative path" needs a clear "relative to what" specification
VBScript's concatenation operator is & not . (dot/period)
:
>> f = WScript.ScriptFullName
>> n = WScript.ScriptName
>> p = goFS.GetParentFolderName(f)
>> a = goFS.GetAbsolutePathName(n)
>> c = goWS.CurrentDirectory
>> WScript.Echo "c", c
>> WScript.Echo "p", p
>> WScript.Echo "?", p & n
>> Wscript.Echo "a", a
>> WScript.Echo "!", goFS.BuildPath(p, n)
>>
c C:\Documents and Settings\eh
p M:\bin
? M:\binivbs.wsf
a C:\Documents and Settings\eh\ivbs.wsf
! M:\bin\ivbs.wsf

Related

How to get the name of the directory from the name of the directory + the file

In an application, I can get the path to a file which resides in a directory as a string:
"/path/to/the/file.txt"
In order to write another another file into that same directory, I want to change the string "/path/to/the/file.txt" and remove the part "file.txt" to finally only get
"/path/to/the/"
as a string
I could use
string = "/path/to/the/file.txt"
string.split('/')
and then glue all the term (except the last one) together with a loop
Is there an easy way to do it?
You can use os.path.basename for getting last part of path and delete it with using replace.
import os
path = "/path/to/the/file.txt"
delete = os.path.basename(os.path.normpath(path))
print(delete) # will return file.txt
#Remove file.txt in path
path = path.replace(delete,'')
print(path)
OUTPUT :
file.txt
/path/to/the/
Let say you have an array include txt files . you can get all path like
new_path = ['file2.txt','file3.txt','file4.txt']
for get_new_path in new_path:
print(path + get_new_path)
OUTPUT :
/path/to/the/file2.txt
/path/to/the/file3.txt
/path/to/the/file4.txt
Here is what I finally used
iter = len(string.split('/'))-1
directory_path_str = ""
for i in range(0,iter):
directory_path_str = directory_path_str + srtr.split('/')[i] + "/"

VBS script to batch process multiple files (replacing string of text)

I have more 10000 files in a folder (extension *.WIR - plain text inside though). I want to find and replace specific line inside every single one. My problem is this line is slightly different in every file + I don't know how to force script to batch process.
Example file 1 have: "INSULATION RESIS 20.0 M ohm"
Example file 2 have: "INSULATION RESIS 100.0 M ohm"
Example file 3 have: "INSULATION RESIS 0.2 M ohm"
...
I need to change them all to "INSULATION RESIS 500.0 M ohm".
Is there any chance VBS script can use wildcards to batch process everything in the same time. How can I do that?
Many thanks in advance for any response.
Three strategies for three (sub)problems:
cscript 01.vbs
xxA 1.0 BxxA 1.1 BxxA 123.456 Bxx
xxA 500.0 BxxA 500.0 BxxA 500.0 Bxx
Option Explicit
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
' use RegExp to replace all occurrences of "A #.# B" in a string
Dim reRpl : Set reRpl = New RegExp
Dim sTest : sTest = "xxA 1.0 BxxA 1.1 BxxA 123.456 Bxx"
reRpl.Global = True
reRpl.Pattern = "(A )\d+\.\d+( B)"
WScript.Echo sTest
WScript.Echo reRpl.Replace(sTest, "$1500.0$2")
' use FileSystemObject/Stream to read/write from/to file
Dim sAll : sAll = oFS.OpenTextFile(WScript.ScriptFullName).ReadAll()
WScript.Echo sAll
oFS.CreateTextFile(WScript.ScriptFullName, True).Write sAll
' use FileSystemObject/Folder/File to loop directory
Dim oFile
For Each oFile In oFS.GetFolder(".").Files
WScript.Echo oFile.Name
Next
username24.txt
01.vbs
00.vbs
I would probably do something like this:
Set fso = CreateObject("Scripting.FileSystemObject")
Set re = New RegExp
re.Pattern = "(INSULATION RESIS) \d+\.\d+ (M ohm)"
For Each f In fso.GetFolder("...").Files
If LCase(fso.GetExtensionName(f)) = "wir" Then
filename = f.Path
tempname = filename & ".tmp"
Set f_in = fso.OpenTextFile(filename)
Set f_out = fso.OpenTextFile(tempname, 2)
Do Until f_in.AtEndOfStream
f_out.WriteLine re.Replace(f_in.ReadLine, "$1 500.0 $2")
Loop
f_in.Close
f_out.Close
f.Delete
fso.MoveFile tempname, filename
End If
Next
This solution avoids potential memory exhaustion due to large input files by processing each file line-by-line. Disadvantage of this solution is that the output-handling requires additional steps (write output to temporary file, replace input file with temporary file).

Split a text file to multiple files based on the data begin with

I'm looking for the way to split the File A into two (File B and File C) by windows batch file or vbscript. I greatlly appreciate if you can provide the sample code !!
File A
------------------------------
'H',123,'1st'
'D',123,'1st'
'D',123,'2nd'
'D',123,'3rd'
'H',456,'2nd'
'D',456,'1st'
'D',456,'2nd'
'D',456,'3rd'
------------------------------
File B
------------------------------
'H',123,'1st'
'H',456,'2nd'
------------------------------
File C
------------------------------
'D',123,'1st'
'D',123,'2nd'
'D',123,'3rd'
'D',456,'1st'
'D',456,'2nd'
'D',456,'3rd'
------------------------------
findstr /bl "'H'" a.txt >b.txt
findstr /bl "'D'" a.txt >c.txt
You could also do it programmatically like this:
for /f "tokens=1-3 delims=," %%a in (File_A) do (
if "%%a"=="'H'" echo %%a,%%b,%%c>>File_B
if "%%a"=="'D'" echo %%a,%%b,%%c>>File_C
)
I believe that this method will probably be slower, but it will allow you more fine tuning of your conditions or manipulation of the data without having to learn REGEX (which FINDSTR implements poorly).
And for completeness or educational purposes, a VBS solution.
An output stream object for each found letter is kept as the value in a dictionary.
Option Explicit
Dim fso, dic, ts_in, ts_out, s, key, INFILE, OUTDIR
Set fso = WScript.CreateObject("Scripting.Filesystemobject")
Set dic = CreateObject("scripting.dictionary")
INFILE = "c:\temp\infile.txt"
OUTDIR = Left (INFILE, InstrRev (INFILE, "\")) 'same folder as INFILE's
Set ts_in = fso.OpenTextFile (INFILE)
Do Until ts_in.AtEndOfStream
s = ts_in.ReadLine
key = Replace (Left (s, InStr (s, ",")-1), "'", "")
If Not dic.Exists (key) Then
Set ts_out = fso.CreateTextFile (OUTDIR & key & ".txt")
dic.Add key, ts_out
End If
Set ts_out = dic(key)
ts_out.writeLine s
Loop
ts_in.Close
For Each ts_out In dic.Items
ts_out.Close
Next

Writing data to excel files, MATLAB

I am using MatlabR2011a on my Windows 7 machine.
I have a folder of 635 text files. Each file contains multiple rows and 2 columns. I am trying to loop through the folder and read each file and write these values to excel. So far this is what I have:
close all; clc;
dirname = uigetdir;
Files = dir(fullfile(dirname,'*.txt'))
for k = 1:635
j =1
filename = fullfile(dirname,Files(k).name);
fid = fopen(filename);
x = fgetl(fid)
while ischar(x)
x = fgetl(fid)
a2 = strtrim(x);
a3 = textscan(a2,'%s');
a4 = a3{1}{1};
a5= a3{1}{2};
pos3 = strcat('A',num2str(j));
xlswrite('sample_output',{a4,a5},'Sheet1',pos3)
j = j+1;
end
fclose(fid);
end
It keeps giving me the following error after finishing reading the first file.
Error using ==> strtrim Input should be a string or a cell array of strings.
A sample input file looks like this:
15076 4636259
15707 4636299
15714 1781552
15721 4204950
15730 2174919
16209 4636510
16413 4758572
16470 4445808
17519 311397
17667 2116489
17739 1729694
18024 3210756
18627 3714194
18695 4192858
19141 632766
19318 1923574
19438 1255216
19493 4635020
19771 4770250
How can I fix this? Would appreciate help with this!
In the while loop, cut the line
x=fgetl(fid)
...and paste it before the end statement right after j=j+1.
The error occurs because you get a line before the while statement, then you use the while statement to test validity of the string (all fine so far), but then immediately get the subsequent line before you perform your string operation. The call to fgetl at the start of the while block could return an EOF, causing subsequent string manipulation functions to fail.
Also... The code would be more robust if you set your for loop like so
for k=1:numel(Files)
Since all your data are numeric this should work. Give it a try.
dirname = uigetdir;
Files = dir(fullfile(dirname,'*.txt'))
j =0;
for k = 1:numel(Files)
filename = fullfile(dirname,Files(k).name);
x = dlmread(filename,'\t'); %# I assume tab-delimiter
j = j + size(x, 1);
xlswrite( 'sample_output', x, 'Sheet1',sprintf('A%d',j) )
end

Windows native script to change text file based on line and column number

A simulation program I'm using requires a text based input file. I need to run the simulation in different configurations by changing the values in the text file. I am looking for a way to do this automatically with any script that does not require third party compilers. It has to run natively on a Windows XP machine. I only have a little bit of coding experience in MATLAB and FORTRAN.
I will describe my idea of what the script should do in some pseudo-code:
% speed.txt - a txt file with 10 different speed values
% coeff.txt - a txt file with 10 different coefficients
% dist.txt - a txt file with 5 different distance values
% input.txt - the txt file containing the input parameters. This file has to be changed.
% output.txt- the output of the simulation
% sp - the i-th speed value
% co - the i-th coeff value
% di - the j-th distance value
% D:\FO - Final Output folder
Read input.txt
for i = 1:10
Display i on screen % so I know how much of the batch is done
Go to line 37, overwrite 1st four characters with i-th value from speed.txt
Go to line 68, overwrite 1st eight characters with i-th value from coeff.txt
for j = 1:5
Display j on screen % so I know how much of the batch is done
Go to line 67, overwrite 1st five characters with j-th value from dist.txt
Run simulation.exe
When simulation is done, get output.txt, rename it to "output_sp_co_di.txt"
and move the file to D:\FO
end
end
I hope that this is possible with a .bat or .vbs script (or anything else that will run natively). All help is greatly appreciated.
EDIT: after some advice I started a vbs script. I have never used that language before but pulled the thing here under together from scraps on the internet:
Option Explicit
Dim objFSO, strTextFile, strData, strLine, arrLines
Dim filesys, filetxt, path
Dim speed(10), ct(10), dist(4), text(73), d(4)
Dim i, j, k
i = 0
j = 0
k = 0
speed(0) = 3.0
speed(1) = 5.0
speed(2) = 7.0
speed(3) = 9.0
speed(4) = 11.0
speed(5) = 13.0
speed(6) = 15.0
speed(7) = 17.0
speed(8) = 19.0
speed(9)= 21.0
speed(10)= 22.0
ct(0) = 0.987433
ct(1) = 0.816257
ct(2) = 0.816361
ct(3) = 0.720357
ct(4) = 0.418192
ct(5) = 0.239146
ct(6) = 0.154534
ct(7) = 0.107608
ct(8) = 0.079057
ct(9)= 0.060437
ct(10)= 0.053465
dist(0) = 173.48
dist(1) = 260.22
dist(2) = 346.96
dist(3) = 433.7
dist(4) = 520.44
d(0) = 2
d(1) = 3
d(2) = 4
d(3) = 5
d(4) = 6
CONST ForReading = 1
'name of the text file
strTextFile = "TurbSim.inp"
'Create a File System Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Open the text file - strData now contains the whole file
strData = objFSO.OpenTextFile(strTextFile,ForReading).ReadAll
'Split the text file into lines
arrLines = Split(strData,vbCrLf)
'Step through the lines
For Each strLine in arrLines
text(i) = strLine
i = i + 1
Next
'Open text file to write to
path = objFSO.GetAbsolutePathName("D:\Sandbox\TurbSim.inp")
For i = 0 To 10
If i = 0 Then
text(37) = Replace(text(37),"UUUU",speed(i))
text(68) = Replace(text(68),"CCCCCCCC",ct(i))
Else
text(37) = Replace(text(37),speed(i-1),speed(i))
text(68) = Replace(text(68),ct(i-1),ct(i))
End If
For j = 0 To 4
If j = 0 Then
text(67) = Replace(text(67),"DDDDD",dist(j))
Else
text(67) = Replace(text(67),dist(j-1),dist(j))
End If
Set filetxt = objFSO.opentextfile("D:\Sandbox\TurbSim.inp", 2, True)
For k = 0 To 73
if k = 73 Then
filetxt.write text(k)
Else
filetxt.write text(k) & vbCr & vbLf
End If
objFSO.CopyFile "D:\Sandbox\TurbSim.inp", _
"D:\Sandbox\input\TurbSim_" & speed(i) & "_" & d(j) &"D.inp"
Next
filetxt.close
Next
Next
' wscript.echo text(37)
' wscript.echo text(68)
' wscript.echo text(67)
filetxt.Close
'Cleanup
' Set filesys = Nothing
Set objFSO = Nothing
Problem is now that the distance part (the j-loop) is not working properly. From the output generated (TurbSim_speed_dD.inp) I see that only the last distance (520.44) is used. I don't really understand why, I'll look into that later. If anyone has a suggestion for improvement, then you're ideas are always welcome.
The Batch file below is a .bat version of your vbs script:
#echo off
SetLocal EnableDelayedExpansion
REM Auxiliary macro for easier replacements
set Replace=for /F "tokens=1,2 delims==" %%x in
:: speed - vector with 11 different speed values
Set i=0
For %%s in (3.0 5.0 7.0 9.0 11.0 13.0 15.0 17.0 19.0 21.0 22.0) do (
Set speed[!i!]=%%s
Set /A i+=1
)
:: ct - vector with 11 different coefficients
Set i=0
For %%c in (0.987433 0.816257 0.816361 0.720357 0.418192 0.239146 0.154534 0.107608 0.079057 0.060437 0.053465) do (
Set ct[!i!]=%%c
Set /A i+=1
)
:: dist - vector with 5 different distance values
Set i=0
For %%d in (173.48 260.22 346.96 433.7 520.44) do (
Set dist[!i!]=%%d
Set /A i+=1
)
REM d does not need to be a vector because d(i) = i+2
:: Split the text file into lines, and Step through the lines
Set i=0
For /F "delims=" %%l in (TurbSim.inp) do (
Set "text[!i!]=%%l"
Set /A i=i+1
)
For /L %%i in (0,1,10) do (
If %%i == 0 (
%Replace% ("UUUU=!speed[%%i]!") do set "text[37]=!text[37]:%%x=%%y!"
%Replace% ("CCCCCCCC=!ct[%%i]!") do set "text[68]=!text[68]:%%x=%%y!"
) Else (
set /A iM1=i-1
%Replace% ("!iM1!") do set speed_iM1=!speed[%%x]!& set ct_iM1=!ct[%%x]!
%Replace% ("!speed_iM1!=!speed[%%i]!") do set "text[37]=!text[37]:%%x=%%y!"
%Replace% ("!ct_iM1!=!ct[%%i]!") do set "text[68]=!text[68]:%%x=%%y!"
)
For /L %%j in (0,1,4) do (
If %%j == 0 (
%Replace% ("DDDDD=!dist[%%j]!") do set "text[67]=!text[67]:%%x=%%y!"
) Else (
set /A jM1=j-1
%Replace% ("!jM1!") do set dist_jM1=!dist[%%x]!
%Replace% ("!dist_jM1!=!dist[%%j]!") do set "text[67]=!text[67]:%%x=%%y!"
)
set /A d=j+2
(For /L %%k in (0,1,73) do (
if %%k == 73 (
set /P =!text[%%k]!< NUL
) Else (
echo !text[%%k]!
)
)) > "D:\Sandbox\input\TurbSim_!speed[%%i]!_!d!D.inp"
)
)
echo %text[37]%
echo %text[68]%
echo %text[67]%
Notes:
1- This is a first attempt Batch file based on your vbs script; I really don't understand what you tried to do and just did a direct translation. It seems that the requirements you state in the question are not the same of the vbs script. Any problem may be solved if you give me specific details.
2- Previous Batch file remove any empty line from the input file. This may be solved if needed.
3- The text replacement in Batch is textual, NOT by numeric value. Any number must be written exactly the same as the array values in order to be replaced. I think the same behaviour apply to vbs.
4- Input file must not contain certain special Batch characters, like ! ^ and others. This may be fixed in certain cases only.
I have managed to pull together a .vbs script from various internet references that does what I want. The script does the following:
Reads in original input file
Stores the data line by line in the text array
Reads in speed, coefficient and distance data from text file
Stores this data in separate speed, coefficient and distance arrays line by line.
Takes first entry of speed and coeff. array and writes it at appropriate places in the
text array
Loops through distance array and writes the text array line by line back to an .inp file
Runs the simulation with the edited input file
Waits until simulation is terminated.
Copy output files from current directory to output folder, renaming them in the process.
Wait 10 seconds to make sure copying is finished
10.Repeat steps 6-10 with all other entries of speed and coeff. array
Requirements for this script to work:
A. An input folder with an .inp file that has "UUUU", "DDDDD", "CCCCCCCC" written at places where respectively the velocity, distance and coefficient should be written.
B. An output folder
C. The files speed.txt, ct.txt and distance.txt containing the speed, coefficient and distance values to be used.
D. You should run this script from an admin account. Otherwise you don't have the permission to check if the simulation is still running with the "Win32_process".
Option Explicit
Dim objFSO, strTextFile, strTData, strLine, arrTLines
Dim strVelFile, strCtFile, strDistFile
Dim strVData, strCData, strDData
Dim arrVLines, arrCLines, arrDLines
Dim strLineV, strLineC, strLineD
Dim strComputer, oWMI, colEvents, oEvent
Dim filesys, filetxt, path, curPath
Dim speed(), ct(), dist(), text(73)
Dim oShell
Dim i, j, k
i = 0
j = 0
k = 0
' Subroutine to start an executable
Sub Run(ByVal sFile)
Dim shell
Set shell = CreateObject("WScript.Shell")
shell.Run Chr(34) & sFile & Chr(34), 1, false
Set shell = Nothing
End Sub
CONST ForReading = 1
' Create a File System Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Create Shell object. Needed to change directories
Set oShell = CreateObject("WScript.Shell")
'Change current directory to \input folder
oShell.CurrentDirectory = ".\input"
' The name of the original input file
' with the UUUU, DDDDD, CCCCCCC in the correct places
strTextFile = "TurbSim.inp"
' Open the text file and read it all into strTData
strTData = objFSO.OpenTextFile(strTextFile,ForReading).ReadAll
' Go back to parent folder as there all the other .txt files reside
Set oShell = CreateObject("WScript.Shell")
oShell.CurrentDirectory = ".\.."
' name of other input text files
strVelFile = "speed.txt"
strCtFile = "ct.txt"
strDistFile = "dist.txt"
' Open the text file - str*Data now contains the whole file
strVData = objFSO.OpenTextFile(strVelFile,ForReading).ReadAll
strCData = objFSO.OpenTextFile(strCtFile,ForReading).ReadAll
strDData = objFSO.OpenTextFile(strDistFile,ForReading).ReadAll
' Split the text files into lines
arrTLines = Split(strTData,vbCrLf)
arrVLines = Split(strVData,vbCrLf)
arrCLines = Split(strCData,vbCrLf)
arrDLines = Split(strDData,vbCrLf)
' Give the speed, ct and dist arrays their dimension
ReDim speed(UBound(arrVLines))
ReDim ct(UBound(arrCLines))
ReDim dist(UBound(arrDLines))
' Add data to arrays text, speed, ct and dist line by line
For Each strLine in arrTLines
text(i) = strLine
i = i + 1
Next
'Reset counter
i = 0
' Step through the lines speed
For Each strLineV in arrVLines
speed(i) = strLineV
i = i + 1
Next
i = 0
' Step through the lines ct
For Each strLineC in arrCLines
ct(i) = strLineC
i = i + 1
Next
i = 0
' Step through the lines dist
For Each strLineD in arrDLines
dist(i) = strLineD
i = i + 1
Next
i = 0
' Get the current path. Needed to point to the executable.
curPath = objFSO.GetAbsolutePathName(".")
For i = 0 To UBound(speed)
If i = 0 Then
' Replace the UUUU and CCCCCCCC values
' Only the first run.
text(37) = Replace(text(37),"UUUU",speed(i))
text(68) = Replace(text(68),"CCCCCCCC",ct(i))
Else ' Replace the previous speed and coeff. values with the current one
text(37) = Replace(text(37),speed(i-1),speed(i))
text(68) = Replace(text(68),ct(i-1),ct(i))
End If
For j = 0 To UBound(dist)
If j = 0 And i = 0 Then
' Replace the DDDDD value (only at first run)
text(67) = Replace(text(67),"DDDDD",dist(j))
ElseIf j = 0 And i > 0 Then
' Replace the distance value of the previous speed/coeff. case
' with the current one
text(67) = Replace(text(67), dist(UBound(dist)), dist(j))
Else ' Replace the previous distance value with the current one
text(67) = Replace(text(67),dist(j-1),dist(j))
End If
Set filetxt = objFSO.opentextfile(curPath & "\TurbSim.inp", 2, True)
For k = 0 To 73 ' Write to an .inp file line by line
if k = 73 Then ' Prevent adding a new line at the end
filetxt.write text(k)
Else
filetxt.write text(k) & vbCr & vbLf
End If
Next
filetxt.close
' Execute the simulation
Run curPath &"\TurbSimGW.exe"
strComputer = "."
Set oWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
'# Create an event query to be notified within 3 seconds when TurbSimGW is closed
Set colEvents = oWMI.ExecNotificationQuery _
("SELECT * FROM __InstanceDeletionEvent WITHIN 3 " _
& "WHERE TargetInstance ISA 'Win32_Process' " _
& "AND TargetInstance.Name = 'TurbSimGW.exe'")
'# Wait until TurbSimGW is closed
Set oEvent = colEvents.NextEvent
' Copy and rename output files
objFSO.CopyFile curPath & "\TurbSim.wnd", _
curPath & "\output\TurbSim_" & speed(i) & "_" & j+2 &"D.wnd"
wscript.sleep 10000 ' time to allow copying the files
Next
Next
'' ' wscript.echo text(37)
'' ' wscript.echo text(68)
'' ' wscript.echo text(67)
filetxt.Close
' Cleanup
' Set filesys = Nothing
Set objFSO = Nothing
Now it works flawlessly. However A solution to requirement D would be nice. My work-around is instead of checking if the program is terminated I just set a sleep value. For this value of sleep I know for sure the simulation is done and the output files are ready to copy.

Resources