Read and write arrays to from file - arrays

I have a class which create session file on disk with written inside colon-separated fields.
<%
Class MySession
Private session_key, stream
Private Sub Class_Initialize
set stream = createobject("adodb.stream")
session_key = request.cookies("sessionkey")
if len(session_key) = 0 then
CreateSession()
end if
End Sub
' read from session file
Public Property Get val()
on error resume next
val = ""
stream.open
stream.loadfromfile "d:\" & session_key
val = stream.readtext
stream.close
End Property
' write session to file
Public Property Let val(userval)
on error resume next
stream.open
stream.writetext mycstr(userval)
for err11 = 0 to 50
stream.savetofile "d:\" & session_key, 2
if Err.Number = 0 then exit for
Err.Clear
next
stream.close
End Property
End Class
%>
Now to fill session file I do
Set SessionID = new MySession
FillArr = FillArr & Request.cookies("sessionkey") & ":" & now()+1
For Row = 0 to Ubound(arrRst,1)
FillArr = FillArr & ":" & arrRst(Row, 0)
Next
SessionID.val() = FillArr
To read all data in session file I use
AllData = sessionID.val()
Now I need to add additional field to this file.
Problem is:
How to check if this field already exist in the file?
How to update only this field in the file?
So I think there is good to use arrays which I can call by it names.
In session file I need data to be written like:
{"sessionkey":"3yut267d273";"session_exp":"51453463";"username":"Alex"}
I think it must be something like this to get needed filed from file:
AllData = sessionID.val("username")
So help me write a right syntax to do that:
How to write array to file?
How to call only needed array element from file?
How to change only needed (or multiple specified field) array element in file and if it not exist then create it?

The canonical way is to import the file (if it exists) into an in-memory data structure when the custom object is created, and write the data structure back to a file when the object is destroyed. You can do it every time a value is requested or changed, but you'll need to read or write the entire file every time.
To do what you're asking you'd need an abstraction layer mapping the data structure elements to bytes on disk. NoSQL databases are implementations of such an abstraction layer. I have never worked with one, though, so I can't tell you how to establish a connection from VBScript. From what I gleaned from the web you may have to use a REST API (via XMLHttpRequest).

Related

AppleScript to edit an XML file?

I have an Apple Music Library output file that looks like this:
<key>6871</key>
<dict>
<key>Track ID</key><integer>6871</integer>
<key>Name</key><string>12 Wake Up Call</string>
<key>Artist</key><string>Rebelution</string>
<key>Album Artist</key><string>Rebelution</string>
<key>Grouping</key><string>AllMusic</string>
<key>Kind</key><string>Apple Music AAC audio file</string>
<key>Size</key><integer>6178208</integer>
<key>Total Time</key><integer>257332</integer>
<key>Year</key><integer>2009</integer>
<key>Date Modified</key><date>2011-11-22T23:32:45Z</date>
<key>Date Added</key><date>2011-12-14T23:30:26Z</date>
<key>Bit Rate</key><integer>256</integer>
<key>Sample Rate</key><integer>44100</integer>
<key>Play Count</key><integer>101</integer>
<key>Play Date</key><integer>3717804040</integer>
<key>Play Date UTC</key><date>2021-10-23T07:20:40Z</date>
<key>Skip Count</key><integer>10</integer>
<key>Skip Date</key><date>2020-09-16T14:39:31Z</date>
<key>Rating</key><integer>60</integer>
<key>Album Rating</key><integer>60</integer>
<key>Album Rating Computed</key><true/>
<key>Normalization</key><integer>1699</integer>
<key>Artwork Count</key><integer>1</integer>
<key>Persistent ID</key><string>56B43C03AFF476E5</string>
<key>Track Type</key><string>Remote</string>
<key>Apple Music</key><true/>
</dict>
I am trying to make this easier to store in a database (I don't understand SQL, but that's the end goal). For now I am adding and looking up "entries" in an excel sheet. I am able to manipulate the XML file manually by pasting it into a workbook, then I have to use ablebits and vlookups and a bunch of other time consuming operations which I paste into a new text file. End goal of this question is to get my "XML" file to look like this:
<key>5056</key>
<dict>
<TrackID>5056</TrackID>
<Name>Heart Like a Lion</Name>
<Artist>Rebelution</Artist>
<AlbumArtist>Rebelution</AlbumArtist>
<Composer>Eric Ariel Rachmany, Marley D. Williams, Rourke Carey & Wesley Dallas Finley</Composer>
<Album>Courage to Grow</Album>
<Grouping>LIBRARY</Grouping>
<Genre>Reggae</Genre>z
<Kind>Apple Music AAC audio file</Kind>
<Size>11679958</Size>
<TotalTime>338413</TotalTime>
<DiscNumber>1</DiscNumber>
<DiscCount>1</DiscCount>
<TrackNumber>2</TrackNumber>
<TrackCount>12</TrackCount>
<Year>2007</Year>
<DateModified>2021-11-10T08:29:23Z</DateModified>
<DateAdded>2021-11-10T08:29:23Z</DateAdded>
<BitRate>256</BitRate>
<SampleRate>44100</SampleRate>
<PlayCount>8</PlayCount>
<PlayDate>3747937611</PlayDate>
<PlayDateUTC>2022-10-07T01:46:51Z</PlayDateUTC>
<ReleaseDate>2007-06-08T12:00:00Z</ReleaseDate>
<Rating>100</Rating>
<AlbumRating>60</AlbumRating>
<AlbumRatingComputed></AlbumRatingComputed>
<ArtworkCount>1</ArtworkCount>
<SortAlbum>Courage to Grow</SortAlbum>
<SortArtist>Rebelution</SortArtist>
<SortName>Heart Like a Lion</SortName>
<PersistentID>AD1A6E4E78F9C79D</PersistentID>
<TrackType>Remote</TrackType>
<AppleMusic></AppleMusic>
</dict>
Anything will help, this has become more time consuming and difficult than I thought.
Im also open to alternative routes... I just want to backup my metadata because I lost it once (recovered it manually as mentioned above), but I also have some good ideas for making playlists based on timestamps of metadata values.
Oh side note... Im also open to using another language if that's easier. I have minimal background in code and have been teaching myself AppleScript since my scrips are mostly interacting with Apple stuff.
Thanks!
AppleScriptObjC can be used to access the various Cocoa frameworks, for example to read a plist/xml file into an NSDictionary (similar to a record), where the various keys can be accessed programmatically, and for utilities such as date formatting, list sorting, etc.
There is an NSXMLNode class that can be used to create the elements, but in this case manually converting the dictionary keys isn't quite as wordy.
The following script creates a plain XML file from an Apple Music Library export. It extracts the specified key items into a track element and uses the track ID as an element attribute:
use framework "Foundation" -- for the AppleScriptObjC bits
use scripting additions
# the dictionary keys to extract (use an empty list {} for everything):
property keyNames : {"Name", "Kind", "Size", "Total Time", "Date Added", "Track Type", "Location"}
property keepSet : missing value -- this will be an NSSet of the keys
property indent : " " -- formatting
on run -- create an XML file for track data from an exported Music Library plist/XML file
if keyNames is not in {"", {}, missing value} then set keepSet to current application's NSMutableSet's setWithArray:(keyNames as list)
set fileURL to current application's NSURL's fileURLWithPath:(POSIX path of (choose file of type {"com.apple.property-list", "public.xml"} with prompt "Choose the Music Library export file to process:"))
set fileData to current application's NSData's dataWithContentsOfURL:fileURL
try -- read file data (source XML file needs to be in Apple's property list format)
set plist to (current application's NSPropertyListSerialization's propertyListWithData:fileData options:(current application's NSPropertyListMutableContainersAndLeaves) format:(missing value) |error|:(missing value))
if plist is missing value then error "The chosen file is not an Apple plist/XML file."
set trackDict to (plist's valueForKey:"Tracks") -- dictionary of tracks
if trackDict is missing value then error "The chosen file does not have a 'Tracks' key in the root directory."
on error errmess
display alert "Script Error" message errmess
error number -128 -- cancel
end try
set theResult to ""
repeat with trackItem in trackDict's allKeys()
set trackKeyPath to "Tracks." & (trackItem as text) -- dictionary for individual track key
set theResult to theResult & addWrapper(trackItem as text, (XMLtext from (plist's valueForKeyPath:trackKeyPath)))
end repeat
writeToFile((choose file name default name "Converted Library.xml"), addWrapper(missing value, theResult))
end run
# return XML text from simple key/value pairs of a dictionary
on XMLtext from dictionary
set XMLElements to {}
set candidate to current application's NSMutableSet's setWithArray:(dictionary's allKeys())
if keepSet is not missing value then candidate's intersectSet:keepSet -- remove other keys
repeat with keyItem in candidate's allObjects()
try
set theItem to (dictionary's valueForKey:keyItem)
set theValue to theItem as text -- test
on error errmess -- can't coerce object to text
set theClass to current application's NSStringFromClass(theItem's class) as text
if theClass contains "Date" then -- format NSDate
set theValue to (current application's NSISO8601DateFormatter's alloc's init()'s stringFromDate:theItem) as text
else -- something needing additional formatting or processing such as a collection, etc
log theClass & ": " & errmess
set theValue to "*ERROR*" -- or add formatting for the object
end if
end try
set keyName to (keyItem's lowercaseString's stringByReplacingOccurrencesOfString:" " withString:"_") -- no spaces in key names
set end of XMLElements to indent & indent & "<" & keyName & ">" & theValue & "</" & keyName & ">" & linefeed -- can also use NSXMLNode
end repeat
set elementArray to current application's NSArray's arrayWithArray:XMLElements
return (elementArray's sortedArrayUsingSelector:"compare:") as list as text -- sort
end XMLtext
# add wrappers for individual track entries or the document
to addWrapper(theKey, theText)
if theKey is not missing value then -- wrap individual track elements - the key is used as an attribute
return linefeed & indent & "<track id=\"" & theKey & "\">" & linefeed & theText & indent & "</track>" & linefeed
else -- wrapper and root element for a standard XML document
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!-- track data extracted " & ((current date) as «class isot» as string) & " from exported Apple Music Library -->
<music_tracks>" & theText & "</music_tracks>" & linefeed
end if
end addWrapper
on writeToFile(filePath, whatever)
try
set fileRef to (open for access filePath with write permission)
set eof of fileRef to 0 -- overwrite existing
write whatever to fileRef starting at eof
close access fileRef
on error
try
close access fileRef
end try
end try
end writeToFile

ssis script task (vb) issues when reading large file

I'm using the below code inside a ssis script task to modify the contents of a file. I'm basicallly creating 1 json document when in the file there are many jsons, one after the other.
This code works perfectly up until around a 1GB file (to read the 1GB file it's using almost 7GB memory in SSIS), after that it crashes (i assume due to memory). I need to read files up until 5GB.
Any help please
Public Sub Main()
Dim filePath As String = Dts.Variables("User::filepath").Value.ToString()
Dim content As String = File.ReadAllText(filePath).Replace("}", "},")
content = content.Substring(0, Len(content) - 1)
content = "{ ""query"" : [" + content + "] }"
File.WriteAllText(filePath, content)
Dts.TaskResult = ScriptResults.Success
End Sub
It is not recommended to use File.ReadAllText(filePath) to read big flat files because it will store all the content in memory. I think you should use a simple data flow task to transfer the data from this flat file to a new flat file, and you can do the transformation you need in a script component on each row.
Also you can read it line by line in a script using a StreamReader using and write it to a new file using a StreamWriter, when finished you can delete the first file, and rename the new one.
References
How to open a large text file in C#
File System Read Buffer Efficiency
c# - How to read a large (5GB) txt file in .NET?

Multi-Session Variables in MS Access

Is there a way to store variables in access which retain their data even after access restarts? The idea is that I will log the date and time of when the form was last opened, which will allow me to only show records since it was last opened.
Since you are inside Access, just create a table to store such information!
In case anyone comes looking here for a method to store Permanent Variables (aka Multi-session Variables) without using Access tables. Here is the techique to achieve this.
Crux : Use TextBox DefautlValue to store data.
Dim strForm As String
Dim frm As Form
strForm = "FormName"
DoCmd.OpenForm strForm, acDesign, , , , acHidden
Set frm = Forms(strForm)
frm.Text0.Caption = "Test"
frm.Text0.DefaultValue = 4
Set frm = Nothing
DoCmd.Close acForm, strForm, acSaveYes
Important Note : Form needs to be open in Design view.

How can I import records from a text file (not delimited) in access db?

I am just trying figure out a record import program from text file into access database using Microsoft.Jet.Oledb Provider 4.0 and Vb.net. And it seems easy but my problem is different. In the text file, records are not delimited. I am a newbie so it became too hard for me. Please give some hint to solve this issue.
Format of the text file:
Field Name & Size
Date[Date,ShortDate]FirstName[20]LastName[20]Sex[1]Age[2]
Records
02062011john……………..little………………M15
…
…
…
Can I put delimiter programmatically while reading the text file using stream reader and later simply import the whole file in DB. Any suggestions
One option is to use the TextFieldParser class:
http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.aspx
Imports Microsoft.VisualBasic.FileIO
Private Sub ReadFixedWidthText()
Dim theString As String = "John Little M15" + vbCrLf + "Jane Doe F30"
Using rdr As New StringReader(theString)
Using parser As New TextFieldParser(rdr)
parser.TextFieldType = FieldType.FixedWidth
parser.FieldWidths = New Integer() {20, 20, 1, 2}
parser.TrimWhiteSpace = True
While Not parser.EndOfData
Dim fields() As String = parser.ReadFields()
For i As Integer = 0 To fields.Length - 1
Console.WriteLine("Field {0}: {1}", i, fields(i))
Next
End While
End Using
End Using
End Sub
I used a StringReader in this example, but you could just as easily use a StreamReader or just use the filename in the TextFieldParser constructor.
Or you could use a combination of the StreamReader and the String.Substring method to get the individual fields.
Is it not space delimited? Do you have any constraints on text file like for example from first character till 100th character is first name etc? If yes you can break the text on the basis of those constraints.

Excel - VBA Question. Need to access data from all excel files in a directory without opening the files

So I have a "master" excel file that I need to populate with data from excel files in a directory. I just need to access each file and copy one line from the second sheet in each workbook and paste that into my master file without opening the excel files.
I'm not an expert at this but I can handle some intermediate macros. The most important thing I need is to be able to access each file one by one without opening them. I really need this so any help is appreciated! Thanks!
Edit...
So I've been trying to use the dir function to run through the directory with a loop, but I don't know how to move on from the first file. I saw this on a site, but for me the loop won't stop and it only accesses the first file in the directory.
Folder = "\\Drcs8570168\shasad\Test"
wbname = Dir(Folder & "\" & "*.xls")
Do While wbname <> ""
i = i + 1
ReDim Preserve wblist(1 To i)
wblist(i) = wbname
wbname = Dir(FolderName & "\" & "*.xls")
How does wbname move down the list of files?
You dont have to open the files (ADO may be an option, as is creating links with code, or using ExecuteExcel4Macro) but typically opening files with code is the most flexible and easiest approach.
Copy a range from a closed workbook (ADO)
ExecuteExcel4Macro
Links method
But why don't you want to open the files - is this really a hard constraint?
My code in Macro to loop through all sheets that are placed between two named sheets and copy their data to a consolidated file pulls all data from all sheets in each workbook in a folder together (by opening the files in the background).
It could easily be tailored to just row X of sheet 2 if you are happy with this process
I just want to point out: You don't strictly need VBA to get values from a closed workbook. You can use a formula such as:
='C:\MyPath\[MyBook.xls]Sheet1'!$A$3
You can implement this approach in VBA as well:
Dim rngDestinationCell As Range
Dim rngSourceCell As Range
Dim xlsPath As String
Dim xlsFilename As String
Dim sourceSheetName As String
Set rngDestinationCell = Cells(3,1) ' or Range("A3")
Set rngSourceCell = Cells(3,1)
xlsPath = "C:\MyPath"
xlsFilename = "MyBook.xls"
sourceSheetName = "Sheet1"
rngDestinationCell.Formula = "=" _
& "'" & xlsPath & "\[" & xlsFilename & "]" & sourceSheetName & "'!" _
& rngSourceCell.Address
The other answers present fine solutions as well, perhaps more elegant than this.
brettdj and paulsm4 answers are giving much information but I still wanted to add my 2 cents.
As iDevlop answered in this thread ( Copy data from another Workbook through VBA ), you can also use GetInfoFromClosedFile().
Some bits from my class-wrapper for Excel:
Dim wb As Excel.Workbook
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
xlApp.DisplayAlerts = False ''# prevents dialog boxes
xlApp.ScreenUpdating = False ''# prevents showing up
xlApp.EnableEvents = False ''# prevents all internal events even being fired
''# start your "reading from the files"-loop here
Set wb = xlApp.Workbooks.Add(sFilename) '' better than open, because it can read from files that are in use
''# read the cells you need...
''# [....]
wb.Close SaveChanges:=False ''# clean up workbook
''# end your "reading from the files"-loop here
''# after your're done with all files, properly clean up:
xlApp.Quit
Set xlApp = Nothing
Good luck!
At the start of your macro add
Application.ScreenUpdating = false
then at the end
Application.ScreenUpdating = True
and you won't see any files open as the macro performs its function.

Resources