sorting in visual basic? - sorting

I've got lots of folders each with a number of HTML files in them some as many as 70 files in a folder and asked a friend to help me make a bulk edit of these files to change their background and font colors as well as add a link at the bottom to go to the next file in the folder and this is what he sent me .. it was a .vbs file
'Here are the settings
'Be warned this is old fashioned preHTML5 stuff no css. But well I guess it could be implemented as well
'I think most of the replacements are pretty straight forward
'Run this script in a folder with all the files for one story
'Running it more then once can have unforseen consequences :)
background="black"
foreground="white"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objSuperFolder = objFSO.GetFolder(".")
Call ShowFiles (objSuperFolder)
WScript.Quit 0
Sub ShowFiles(fFolder)
Set objFolder = objFSO.GetFolder(fFolder.Path)
Set colFiles = objFolder.Files
Dim a(50000)
Dim b(50000)
i = 1
For Each objFile In colFiles
If UCase(objFSO.GetExtensionName(objFile.name)) = "HTML" Then
a(i) = objFile.Path
b(i)=objFile.Name
i = i + 1
End If
Next
j=i
For z = 1 To j-1
Set objFile2 = objFSO.OpenTextFile(a(z), 1)
strText = objFile2.ReadAll
strText = Replace(strText, "<body>", "<body bgcolor=""" +background+""">")
strText = Replace(strText, "<html>", "<html><font color=""" +foreground+""">")
strText = Replace(strText, "</html>", "</font></html>")
'Add the link to next chapter
If z < j-1 Then
strText = Replace(strText,"</body>","Link to next chapter!</body>")
End If
objFile2.Close
Set objFile2 = objFSO.OpenTextFile(a(z), 2)
objFile2.Write strText
objFile2.Close
Next
End Sub
and for the most part it works great except that it linked 1 to 10 then 11, 12, ... 19, 2, 20, 21 and so on i'm trying to figure out how to fix it so the links go from 1 to 2, 3, ... 9, 10, 11...
the HTML file names are all the same in a given folder except the number at the end
Name0.html
Name1.html
Name2.html
...
Name9.html
Name10.html
Name11.html
etc...
BTW the html files are generated by a program i downloaded so i can recreate them easy enough if a mistake is made oh and i also wanted to add changing the font size as well but if it's to much trouble i can easily continue to use the zoom feature to work around that
Added in respond to the first answer:
no i can not control the output of the original programs numbering though if someone had a quick VBS script to change the files to a 3 digit format for the numbers that'd be a lovely workaround solution
http://helloacm.com/bubble-sort-in-vbscript/
This looks like it might be a step in the right direction maybe?
Sorting arrays numerically and alphabetically(like Windows Explorer) without using StrCmpLogicalW or shlwapi.dll - ASP.NET VB
or this?

The problem is that in the statement Set objFolder = objFSO.GetFolder(fFolder.Path) there is not really a quick and easy way to sort the results of the files that come out. See this other answer on this site.
What is happening is that when the files are being read by that command it is in fact the 1, 10, 11, 19, 2, 20 and etc like you are experiencing.
The program that you say produces these files. Is it possible such that they could be saved using a zero file. E.g. Name00.html, Name01.html, Name02.html? If so then that would be the way to go then your friends script will work as designed. Or if it won't hurt anything you could also rename the files after your program created these HTML files as well. But long story short you either need to modify the code so that it sorts the files for you, or you can rename the files such that they will come to the program in the order that you are expecting.

Same friend finally got around to fixing the code up and here is the final working version
'Here are the settings
'Be warned this is old fashioned preHTML5 stuff no css. But well I guess it could be implemented as well
'I think most of the replacements are pretty straight forward
'Run this script in a folder with all the files for one story
'Running it more then once can have unforseen consequences :)
background="black"
foreground="white"
size="6" 'Setting go from 1 to 7
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objSuperFolder = objFSO.GetFolder(".")
Call ShowFiles (objSuperFolder)
WScript.Quit 0
Sub ShowFiles(fFolder)
Set objFolder = objFSO.GetFolder(fFolder.Path)
Set colFiles = objFolder.Files
Set objRE = New RegExp
With objRE
.Pattern = "(\d*)\.html"
.IgnoreCase = True
.Global = False
End With
Dim a(50000)
Dim b(50000)
'From here on there is the rename part
Dim arr(3)
arr(0)="0000"
arr(1)="000"
arr(2)="00"
arr(3)="0"
For Each objFile In colFiles
If UCase(objFSO.GetExtensionName(objFile.name)) = "HTML" Then
Set objMatch = objRE.Execute( objFile.Name )
If objMatch.Count = 1 Then
Dim ll,sttt
sttt=objMatch.Item(0).Submatches(0)
ll=Len(sttt)
'WScript.Echo "Old name" & objMatch.Item(0)
strNewName = objRE.Replace( objFile.Name, arr(ll)&sttt&".html")
'WScript.Echo "New name" & strNewName
objFile.Name=strNewName
End If
End If
Next
''The renaming ends here and we're on to business as usual
i = 1
Set objFolder = objFSO.GetFolder(fFolder.Path)
Set colFiles = objFolder.Files
For Each objFile In colFiles
If UCase(objFSO.GetExtensionName(objFile.name)) = "HTML" Then
a(i) = objFile.Path
b(i)=objFile.Name
i = i + 1
End If
Next
j=i
For z = 1 To j-1
Set objFile2 = objFSO.OpenTextFile(a(z), 1)
strText = objFile2.ReadAll
strText = Replace(strText, "<body>", "<body bgcolor=""" +background+""">")
strText = Replace(strText, "<html>", "<html><font size="""+size+""" color=""" +foreground+""">")
strText = Replace(strText, "</html>", "</font></html>")
'Add the link to next chapter
If z < j-1 Then
strText = Replace(strText,"</body>","<p>Link to next chapter!</p></body>")
End If
objFile2.Close
Set objFile2 = objFSO.OpenTextFile(a(z), 2)
objFile2.Write strText
objFile2.Close
Next
End Sub

Related

VBScript to get directory size if over N GB then delete oldest 'Folder' to recover space

I'm very new to bat scripting and would like to be able to do the following:
I have a main 'backups' folder which in turn contains unique folders for individual daily backups taken (i.e. named 'backup (date/time'). Within these individual daily backup folders they contain both files and folders.
I would therefore like to be able to check the main 'backups' folder and if the size is greater then say 50GB then the oldest folder and anything contained within is deleted.
I came across the script below in the Forum which does what I'm looking for, but on files rather then folders. Due to my elementally level of scripting, I'm not sure how straightforward it would be to adapt have it work with folders or if there is something else already available.
Many Thanks
Set fso = CreateObject("Scripting.FileSystemObject")
Set F = fso.GetFolder("C:\Users\User\Desktop\New Folder\Stories\Test")
If F.size > 2^30*2 Then
'Comments on a stupid editor that can't handle tabs
'Creating an in memory disconnected recordset to sort files by date
Set rs = CreateObject("ADODB.Recordset")
With rs
.Fields.Append "Date", 7
.Fields.Append "Txt", 201, 5000
.Open
For Each Thing in f.files
.AddNew
.Fields("Date").value = thing.datelastmodified
.Fields("Txt").value = thing.path
.UpDate
Next
.Sort = "Date Desc"
Do While not .EOF
fso.deletefile .Fields("Txt").Value
If f.size < 2^30*2 then Exit Do
.MoveNext
Loop
End With
End If
Here's code that does what you are looking for:
Dim objFSO
PurgeBackups "C:\Temp"
Sub PurgeBackups(p_sRootFolder)
Dim objRootFolder
Dim objOldestFolder
Dim fOldestInitialized
Dim objFolder
Dim lngFolderSize
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objRootFolder = objFSO.GetFolder(p_sRootFolder)
fOldestInitialized = False
For Each objFolder In objRootFolder.SubFolders
lngFolderSize = GetFolderSize(objFolder)
If lngFolderSize > 50000000000# Then
' Decide if you want to delete this Folder or not
If Not fOldestInitialized Then
Set objOldestFolder = objFolder
fOldestInitialized = True
End If
' Compare date
If objFolder.DateCreated < objOldestFolder.DateCreated Then
Set objOldestFolder = objFolder
End If
End If
Next
If fOldestInitialized Then
' Delete oldest folder
objOldestFolder.Delete
End If
End Sub
Function GetFolderSize(p_objFolder)
Dim objFile
Dim objFolder
Dim lngFolderSize
lngFolderSize = 0
For Each objFile In p_objFolder.Files
lngFolderSize = lngFolderSize + objFile.Size
Next
For Each objFolder In p_objFolder.SubFolders
lngFolderSize = lngFolderSize + GetFolderSize(objFolder)
Next
GetFolderSize = lngFolderSize
End Function
Please find below my attempt which has been based on an existing script and modified to suit, with a few extra flurries . . . I would be grateful for comment.
strOldestFolder = ""
dtmOldestDate = Now
Set oShell = CreateObject("WScript.Shell")
strHomeFolder = oShell.ExpandEnvironmentStrings("%USERPROFILE%\HDBackups")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(strHomeFolder)
intFolderSize = Int((objFolder.Size / 1024) / 1024)
If intFolderSize >= 50 Then ' change as appropriate, value in MBytes
Set objSubFolders = objFolder.SubFolders
For Each objFolder in objSubFolders
strFolder = objFolder.Path
dtmFolderDate = objFolder.DateCreated
If dtmFolderDate < dtmOldestDate Then
dtmOldestDate = dtmFolderDate
strOldestFolder = strFolder
End If
Next
objFSO.DeleteFolder(strOldestFolder)
End If
One aspect that I'm not entirely happy with is the look and neatness of the 'str' and 'Set' in the first six code lines, I would like to be group them together, i.e. all the Sets together. But so far have been unable to do so without the script failing.
Note: have used 50MB rather then the 50GB as per original description, makes testing a bit easier.

Saving file into another file using VBScript after modification

I have some XML files in a folder \\demo.US\Modified\. The files in the folder are:
USA.xml
Canada.xml
Mexico.xml
The code below is changing the encoding from UTF-8 to windows-1252 and is creating a modified file mod.xml.
This mod.xml file have data from all three XML files concatenated.
I need help so I can save files separately.
If value of objFile.Name is USA.xml then it should save modified file name as USA_mod.xml. the output for \\demo.US\Modified\ folder after execution is complete should have mod files in it as below.
USA.xml
Canada.xml
Mexico.xml
USA_mod.xml
Canada_mod.xml
Mexico_mod.xml
The code I used is as follows.
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = "\\demo.US\Modified\"
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile In colFiles
WScript.Echo objFile.Name
Set objFile = objFSO.OpenTextFile(objStartFolder & objFile.Name, 1)
Set outFile = objFSO.OpenTextFile(objStartFolder & "mod.xml", 2, True)
Do Until objFile.AtEndOfStream
strContent = strContent & objFile.ReadLine
Loop
MsgBox strContent
strContent = Replace(strContent, "encoding=""UTF-8""", "encoding=""windows-1252""")
outFile.WriteLine strContent
outFile.Close
objFile.Close
Next
As others have already pointed out, you shouldn't do what you're attempting to do here, because it is very likely to create more problems down the road. Find the cause of the issue and fix that instead of trying to handle symptoms. You have been warned.
With that said, the reason why the content of all input files is written to the same output file is because you always specify the same output file. That file should contain only the content of the last input file, though, because you open the file for writing (thus erasing previous content) rather than for appending.
Replace these lines:
Set objFile = objFSO.OpenTextFile(objStartFolder & objFile.Name, 1)
Set outFile = objFSO.OpenTextFile(objStartFolder & "mod.xml", 2, True)
with this:
Set inFile = objFile.OpenAsTextStream
outFilename = objFSO.BuildPath(objStartFolder, objFSO.GetBaseName(objFile) & "_mod.xml")
Set outFile = objFSO.OpenTextFile(outFilename, 2, True)
and also replace the other occurrences of objFile after that with inFile (always avoid changing the value of a loop variable), and the code should do what you expect it to do. But again, be warned that the output may not be valid XML.
I managed to made it working, below is the code I used
Dim objFSO, filePath, objFile, colFiles, s , FName
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set filePath = objFSO.GetFolder("\\demo.US\Modified\")
Set colFiles = filePath.Files
For Each FName in colFiles
set objFile = objFSO.OpenTextFile(FName.Path,1)
set outFile = objFSO.OpenTextFile(LEFT(FName.Path,instr(FName.Path,".xml")-1) &"_mod.xml",2,True)
do until objFile.AtEndOfStream
strContent=objFile.ReadLine
Loop
strContent = Replace(strContent, "encoding=""UTF-8""", "encoding=""windows-1252""")
outFile.WriteLine strContent
outFile.Close
objFile.Close
Next

List most recent files in ASP Classic

I am redesigning our department website and our IT department does not support the intranet development. The server runs ASP Classic and is able to run VB scripts and Javascript to an extent (somethings work others don't).
So here is my problem:
I modified a simple code that I got from http://www.brainjar.com/asp/dirlist/
to list all the PDF Files in a directory including sub directories but I am not sure how to sort it.
As of now it sorts it in alphabetical order per each folder it reads. I would like it to sort every file of every sub directory by the item.DateLastModified property I do not know if this possible.
I am thinking I would need to store the items in an array and then sort the array and print the data but I have no idea how to do that it has been 10 years since I took a programming course.
Any help would be greatly appreciated!
Current code I am using :
====>
<% sub ListFolderContents(path)
dim fs, folder, file, item, url
set fs = CreateObject("Scripting.FileSystemObject")
set folder = fs.GetFolder(path)
for each item in folder.SubFolders
ListFolderContents(item.Path)
next
'Display a list of files
for each item in folder.Files
url = MapURL(item.path)
if item.type = "PDF File" then
Response.Write("<dt>" & item.Name & "" _
& vbCrLf)
end if
next
Response.Write("</dt>" & vbCrLf)
end sub
function MapURL(path)
dim rootPath, url
'Convert a physical file path to a URL for hypertext links.
rootPath = Server.MapPath("/")
url = Right(path, Len(path) - Len(rootPath))
MapURL = Replace(url, "\", "/")
end function %>
The original is at http://www.brainjar.com/asp/dirlist/
Well, it's your lucky day! I happen to have old code that I wrote for personal use ~10 years ago, so with little tweaking it can fit your case almost perfectly. The key is using a disconnected recordset to hold all the data, then sort by date last modified. The crawling itself is similar to what you already have, by recursion. Note that no need to create new folder instance in each iteration - it's waste of resources, since you already have the folder object in the loop.
Anyway, here it is:
Const adVarChar = 200
Const adInteger = 3
Const adDate = 7
Dim objFSO, oFolder, objRS
Sub ExtractAllFiles(oFolder)
Dim oSubFolder, oFile
'recurse all sub folders
For Each oSubFolder In oFolder.SubFolders
Call ExtractAllFiles(oSubFolder)
Next
'loop through all the files found, add to the recordset
For Each oFile in oFolder.Files
objRS.AddNew
objRS.Fields("Name").Value = oFile.Name
objRS.Fields("Url").Value = MapURL(oFile.Path)
objRS.Fields("Type") = oFile.Type
objRS.Fields("DateLastModified").Value = oFile.DateLastModified
Next
End Sub
Sub ListFolderContents(sPath, sTypeToShow)
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
Set oFolder = objFSO.GetFolder(sPath)
'create a disconnected recordset
Set objRS = Server.CreateObject("ADODB.Recordset")
'append proper fields
objRS.Fields.Append "Name", adVarChar, 255
objRS.Fields.Append "Url", adVarChar, 255
objRS.Fields.Append "Type", adVarChar, 255
objRS.Fields.Append "DateLastModified", adDate
objRS.Open
'extract all files in given path:
Call ExtractAllFiles(oFolder)
'sort and apply:
If Not(objRS.EOF) Then
objRS.Sort = "DateLastModified DESC"
objRS.MoveFirst
End If
'loop through all the records:
Do Until objRS.EOF
If (Len(sTypeToShow)=0) Or (LCase(sTypeToShow)=LCase(objRS("Type"))) Then
Response.Write("<dt>" & objRS("Name") & " (Type: " & objRS("Type") & ", Last modified: " & objRS("DateLastModified") & ")</dt>" _
& vbCrLf)
End If
objRS.MoveNext()
Loop
'clean up resources
Set oFolder = Nothing
Set objFSO = Nothing
objRS.Close
Set objRS = Nothing
End Sub
To use it in your code, have such line in the HTML body:
<% Call ListFolderContents(Server.MapPath("."), "PDF File") %>
You can of course use different path and change the display to show only what you need.

VBScript Renaming File Code Issue

I wrote a simple vbscript to rename files in a particular folder. Specifically to remove particular content from the filname.
The Script I wrote (listed below) runs fine but the highlighted part (second IF-THEN statement) doesn't run. I can't figure out whats wrong with the code. I plan to add more IF-THEN statement to remove particular content from file names.
I'm a novice at this so please be patient with me. Can anyone help?
Set objFS = CreateObject("Scripting.FileSystemObject")
strFolder="C:\Users\Admin2\Downloads\Compressed"
Set objFolder = objFS.GetFolder(strFolder)
For Each strFile In objFolder.Files
strFileName = strFile.Name
If InStr(strFileName,"(2014)") > 0 Then
strNewFileName = Replace(strFileName,"(2014)","")
strFile.Name = strNewFileName
End If
**If InStr(strFileName,"(digital)") > 0 Then
strNewFileName = Replace(strFileName,"(digital)","")
strFile.Name = strNewFileName
End If**
Next
Type prefix fraud detected:
For Each strFile In objFolder.Files
"strFile" should be "objFile". Dangerous extra variable in:
strFileName = strFile.Name
The variable "strFileName" will get stale if you change "objFile.Name". Use a variable to hold the new/desired name instead.
strNewFileName = objFile.Name
Renaming the file twice will loose changes on the way. Modify "strNewFileName" (in steps or all at once:
strNewFileName = Replace(Replace(strNewFileName, "(2014)", ""), "(digital)", "")
; you don't really need the If guard, because Replace won't change strings that don't contain the target).
Check for .FileExists(strNewFileName) before you do the rename.
Can you prove that there are file names that contain "(digita1)" <-- mark the digit 1) exactly? Lower vs. upper case? A nasty blank?
I hope the following code helps
Set objFS = CreateObject("Scripting.FileSystemObject")
strFolder="pathtofolder"
Set objFolder = objFS.GetFolder(strFolder)
For Each objFile In objFolder.Files
ObjFileName = ObjFile.Name
NewFileName = Replace(Replace(ObjFileName,"(2014)",""),"(digital)","")
Set fileSystemObject = CreateObject("Scripting.FileSystemObject")
If fileSystemObject.FileExists(NewFileName) Then
Else
ObjFile.Name = Trim(NewFileName)
End If
Next

Do I need a wait time for setting a new folder vbs?

I am using the following code:
Set StorageFileSystem = CreateObject("Scripting.fileSystemObject")
Set StorageFolder = StorageFileSystem.GetFolder(PathToStorageFiles)
msgBox "Set folders for Storage"
for each Storagefile in StorageFolder.Files 'get the creation time of the oldest recording
msgBox "DateCreated: " & Storagefile.DateCreated & vbCrLf & "EarylDateTime: " & earlyDateTime & vbCrLf & "DateTime to compare: " & dateadd("h" ,-6, Now)
if Storagefile.DateCreated < dateadd("h" ,-6, Now) then
earlyDateTime = Storagefile.DateCreated
end if
next
I have used this before without problem, even in the program that this is in. However this time it never seems to do anything. The folder has over 130,000 files in it (391GB). I don't know if I should include a delay so that the program can emumerate them or if there is some other problem that I just don't see.
Any ideas? I'm using VBS, the msgBox between the 2 set statements and the for loop works, but the one between the opening of the for loop and the if statement does not.
Are you saying the codes in the For loop doesn't seem to work? It seems not work if the folder does not have any files in it. So check the value of PathToStorageFiles.
Your logic of getting the oldest recording creation time is flawed - any time that is 6 hours before Now is treated as oldest and set to earlyDateTime.
Try this code below, with sample output:
PathToStorageFiles = "C:\Test" ' <=- Change this!
Set StorageFileSystem = CreateObject("Scripting.fileSystemObject")
Set StorageFolder = StorageFileSystem.GetFolder(PathToStorageFiles)
sOldestFile = "" ' Stores the full name of the file
earlyDateTime = dateadd("h" ,-6, Now) ' Assuming 6 hours before script started is oldest (it can be just Now)
wscript.echo StorageFolder.Files.Count & " files in the folder " & PathToStorageFiles
for each Storagefile in StorageFolder.Files 'get the creation time of the oldest recording
if Storagefile.DateCreated < earlyDateTime then
sOldestFile = Storagefile.Path
earlyDateTime = Storagefile.DateCreated
wscript.echo "earlyDateTime changed to " & earlyDateTime & " | " & sOldestFile
end if
next
wscript.echo vbCrLf & "Oldest file: " & sOldestFile & vbCrLf & "Created on: " & earlyDateTime
On a side note, you should modify this to process sub folders too, then move files into folders. 130,000 files in a single folder is a mess!
UPDATE
Based on your posted solution, there are improvements you can do.
First, use 1 FileSystemObject.
Then the recentFile in the for loop. You should set it to zero first, rather than 2 comparisons. Having said that, you have the opportunity to time the differences.
recentFile = 0
For Each file in colFiles
If file.DateCreated > recentFile Then
recentFile = file.DateCreated
End If
Next
Lastly, if the D: on the server is a NAS, then you can split the code into 2 parts - one search for most recent, the other for oldest. Then use batch file start cscript.exe //nologo <script#.vbs> method to start them in 2 processes. This you need 2 txt files for output.
If there is only 1 folder to get the latest & oldest file, it can be in 1 for loop.
This is the code that I got to work:
Option Explicit
Dim LocalStorage, NewLocalStorage, recentFile, objFSO, colFiles, objFolder, file, OldestDate, strOldestDate, fso, ts, objFile
LocalStorage = "D:\BlueIris\Storage"
NewLocalStorage = "D:\BlueIris\New"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(NewLocalStorage)
Set colFiles = objFolder.Files
For Each file in colFiles
If recentFile = "" Then
recentFile = file.DateCreated
ElseIf file.DateCreated > recentFile Then
recentFile = file.DateCreated
End If
Next
Set objFolder = objFSO.GetFolder(LocalStorage)
Set colFiles = objFolder.Files
OldestDate = Now
For Each objFile in colFiles
if objFile.DateCreated < OldestDate Then
OldestDate = objFile.DateCreated
strOldestDate = objFile.DateCreated
End if
Next
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.CreateTextFile ("C:\DVRInfo.txt", true)
ts.writeline recentFile
ts.writeline strOldestDate
ts.close
I run this on the actual server so that it runs a lot faster than the original code I attempted. Let me know if you still flaws in this please, I want to be as efficient as possible.
Thanks
EDIT:
New code:
Option Explicit
Dim LocalStorage, NewLocalStorage, recentFile, objFSO, colFiles, objFolder, file, OldestDate, strOldestDate, fso, ts, objFile
LocalStorage = "D:\BlueIris\Storage"
NewLocalStorage = "D:\BlueIris\New"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(NewLocalStorage)
Set colFiles = objFolder.Files
Set recentFile = 0
For Each file in colFiles
If file.DateCreated > recentFile Then
recentFile = file.DateCreated
End If
Next
Set objFolder = objFSO.GetFolder(LocalStorage)
Set colFiles = objFolder.Files
OldestDate = Now
For Each objFile in colFiles
if objFile.DateCreated < OldestDate Then
OldestDate = objFile.DateCreated
strOldestDate = objFile.DateCreated
End if
Next
Set ts = fso.CreateTextFile ("C:\DVRInfo.txt", true)
ts.writeline recentFile
ts.writeline strOldestDate
ts.close

Resources