Delete a record in a Random File in Vb6 - vb6

I'm trying to manage a quite-small DataBase with Vb6 and NotePad.
I collect all the record in Random into the Notepad File (.dat).
I use the Get and Put command for getting the record I stored and insert the newest.
Now I'd like to have the possibility to DELETE a record I entered (maybe the latest).
I tought that:
Delete #FileNumber1, LatestRec, MyRec
was a good chance to get it.
LatestRec is the number of the latest record (ex: 5 means the 5th).
MyRec is my record variable.
Any suggestions?

The Delete statement you note above doesn't apply for random access files. Unfortunately, VB6 Random Access files provide no direct mechanism for record deletion, primarily because deletion leads to a rat's nest of other issues, such as file contraction (filling the empty space), fragmentation (unused empty space), to name a couple. If you truly need to delete a record, about the only option you have is to copy all the other records to a temporary file, delete the old file, and rename the temp file to the "original" name - and, sadly, that's right from Microsoft.
One thing you can do, which I'll admit up front isn't ideal, is to add a "deleted" field to your random-access file, defaulting to 0, but changing to true, 1, or some other relevant value, to indicate that the record is no longer valid.
You could even get into writing routines to reuse deleted records, but if you're getting into file semantics that much, you might be better served by considering a move of the application to a more robust database environment, such as SQL Server.
*EDIT:*Here is a very rough/crude/untested chunk of sample VB6 code that shows how you would delete/add a record with the "deleted field" concept I described above..caveat that tweaks might be needed to get this code perfect, but the point is to illustrate the concept for you:
Type SampleRecord
UserID As Long
lastName As String * 25
firstName As String * 25
Deleted As Boolean
End Type
' This logically deletes a record by setting
' its "Deleted" member to True
Sub DeleteRecord(recordId As Long)
Dim targetRecord As SampleRecord
Dim fileNumber As Integer
fileNumber = FreeFile
Open "SampleFile" For Random As fileNumber Len = LenB(SampleRecord)
Get fileNumber, recordId, targetRecord
targetRecord.Deleted = True
Put #fileNumber, recordId, targetRecord
Close #fileNumber
End Sub
Sub AddRecord(lastName As String, firstName As String)
Dim newRecord As SampleRecord
Dim fileNumber As Integer
Dim newRecordPosition As Long
newRecord.firstName = firstName
newRecord.lastName = lastName
newRecord.Deleted = False
newRecord.UserID = 123 ' assume an algorithm for assigning this value
fileNumber = FreeFile
Open "SampleFile" For Random As fileNumber Len = LenB(SampleRecord)
newRecordPosition = LOF(fileNumber) / LenB(SampleRecord) + 1
Put #fileNumber, newRecordPosition, newRecord
Close #fileNumber
End Sub

Related

Assigning CSV values to structure

I'm creating what should be a simple program but I'm having some difficulty assigning values from a file into a structure and it's variables. Visual Basic.
Structure:
Public Structure Teams
Dim teamName As String
End Structure
Function:
Function getAvailableTeams() As Teams()
Dim rec As Teams
Dim index As Integer
Dim recCount As Integer = 0
'Count how many teams exist
FileOpen(1, "teamConfig.csv", OpenMode.Input)
Do Until EOF(1)
LineInput(1) 'Read document line by line
recCount += 1 'Increment team count by 1
Loop
'store team names in array
Dim teamNames(recCount - 1) As Teams
index = 0
Do Until EOF (1)
Input(1, rec.teamName)
teamNames(index).teamName = rec.teamName
index +=1
Loop
FileClose(1)
Return teamNames
End Function
Simple subroutine to test values are available and being picked up.
Dim availableTeams() As Teams
availableTeams = getAvailableTeams()
lbltest.text = availableTeams(1).toString
The file is stored as a CSV file and there are 11 available team names.
team1 \r\n
team2 \r\n
etc...
I appreciate this is probably something simple but I can't work out where I'm going wrong with this.
One of the comments was on the right track. You need to close and re-open the file for input to start at the beginning again. Since you were already at end-of-file, the second attempt fails immediately unless you re-start from the beginning.

Optimize performance of Removing Hidden Rows in VBA

I am using the following code to remove hidden/filtered lines after applying autofilters to a big sheet in VBA (big means roughly 30,000 rows):
Sub RemoveHiddenRows()
Dim oRow As Range, rng As Range
Dim myRows As Range
With Sheets("Sheet3")
Set myRows = Intersect(.Range("A:A").EntireRow, .UsedRange)
If myRows Is Nothing Then Exit Sub
End With
For Each oRow In myRows.Columns(1).Cells
If oRow.EntireRow.Hidden Then
If rng Is Nothing Then
Set rng = oRow
Else
Set rng = Union(rng, oRow)
End If
End If
Next
If Not rng Is Nothing Then rng.EntireRow.Delete
End Sub
The code comes from here: Delete Hidden/Invisible Rows after Autofilter Excel VBA
Moreover I read this thread: Speeding Up Code that Removes Hidden Rows on a Sheet
The situation: I have applied 5 different filters to a table consisting of 12 columns, therefore a lot of rows are filtered out (hidden) after the process. When I try to delete those, the code above takes a very long time. In my case I don't know if Excel was still working, so I had to force an exit. That leads to the following question:
Is there any other way than looping through all the hidden rows and deleting them?
An idea which came to my mind was to copy only the remaining unfiltered (that is non-hidden) content to a new sheet and afterwards delete the old sheet, which contains the full information. If so, how can that be done?
I don't think you need to involve another worksheet. Simply copy the rows below the existing Range.CurrentRegion property and then remove the filter and delete the original data.
Sub RemoveHiddenRows()
With Sheets("Sheet10")
With .Cells(1, 1).CurrentRegion
With .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count)
If CBool(Application.Subtotal(103, .Columns(1))) Then
.Cells.Copy Destination:=.Cells(.Rows.Count + 1, 1)
End If
.AutoFilter
.Cells(1, 1).Resize(.Rows.Count, 1).EntireRow.Delete
End With
End With
End With
End Sub
You may also receive some good, focused help on this subject by posting on Code Review (Excel).
You can improve performance significantly with a function like this:
Option Explicit
Public Sub deleteHiddenRows(ByRef ws As Worksheet)
Dim rngData As Range, rngVisible As Range, rngHidden As Range
With ws
Set rngData = .UsedRange
With rngData
Set rngVisible = .SpecialCells(xlCellTypeVisible)
Set rngHidden = .Columns(1)
End With
End With
If Not (rngVisible Is Nothing) Then
ws.AutoFilterMode = False
' invert hidden / visible
rngHidden.Rows.Hidden = False
rngVisible.Rows.Hidden = True
' delete hidden and show visible
rngData.SpecialCells(xlCellTypeVisible).Delete
rngVisible.Rows.Hidden = False
End If
End Sub
I tested it on a file with 2 filters applied to it
The function was adapted from the code in this suggestion

VBA, FileSystemObject, Windows sort order

I'm tying to make something in VBA that will basically list all the files in one or more directories starting from a root folder. Long story short, I'm using filesystemobject to run through all of the folders and then getting all the files in those folders. Moving to the next folder, etc.
The problem I'm running into is that I need to spit out my data (onto a sheet) in the same folder sort order as one might find in Windows. I know this isn't a fixed concept per say, so here's a quick example, as it's displayed in Windows(for me):
Windows Sort Order:
FolderTest\000
FolderTest\0
FolderTest\0001
Not too surprisingly, when using FSO it returns the sub folders in a different (perhaps more logical) order:
FolderTest\0
FolderTest\000
FolderTest\0001
I was hoping someone might have an idea of what one could do to get this to be resorted as it's displaying in Windows. This is just an example obviously, the files could be named anything, but it certainly seems to behave a lot better with alpha characters in the name. I'm not necessarily married to using FSO, but I don't even know where else to look for an alternative. I know I could potentially resort these in an array, but I'm not sure what kind of wizardry would be required to make it sort in the "proper" order. For all I know, there's some method or something that makes this all better. Thanks in advance for any help!
To whoever it may end up helping, the following code looks like it's giving me the results I was looking for, converting a list of subfolders into the same sort orders you (probably) find in Windows Explorer. Feeding in Subfolders from a Filesystem object, it spits the results out in an array (fnames). The code... it's not pretty. I'll be the first to admit it. Don't judge me too harshly. Big thanks #Paddy (see above) for pointing me towards StrCmpLogicalW (http://msdn.microsoft.com/en-us/library/windows/desktop/bb759947(v=vs.85).aspx)
Private Declare PtrSafe Function StrCmpLogicalW Lib "shlwapi" _
(ByVal s1 As String, ByVal s2 As String) As Integer
Sub filefoldersortWindows()
Dim folder As String
Dim fnames() As String, buffer As String, content As String
folder = "Your Path"
Set fsol = CreateObject("Scripting.fileSystemObject")
Set fold = fsol.GetFolder(folder)
FoldCount = fold.SubFolders.Count
ReDim fnames(FoldCount)
cFcount = 0
For Each fld In fold.SubFolders
cFcount = cFcount + 1
Namer$ = fld.Name
fnames(cFcount) = StrConv(Namer, vbUnicode)
Next
For AName = 1 To FoldCount
For BName = (AName + 1) To FoldCount
If StrCmpLogicalW(fnames(AName), fnames(BName)) = 1 Then
buffer = fnames(BName)
fnames(BName) = fnames(AName)
fnames(AName) = buffer
End If
Next
Next
For i = 1 To FoldCount
fnames(i) = StrConv(fnames(i), vbFromUnicode)
If i > 1 Then
content = content & "," & fnames(i)
Else
content = fnames(i)
End If
Next
End Sub
Ahh, I see now. I made a bunch of directories with numeric names to see what's going on. Windows explorer does an integer conversion on the value. The sort rule is like this:
numeric value : ascending
padding length : descending
So, if have 01 and 001, both evaluate to the integer 1, but 001 will appear first because it is longer (has more zero-padding). The 'length' in this case only refers to the numeric part (ie the padding), and is not affected by any characters that appear after (they only matter if the numeric value and the padding length are the same - then normal ordering applies):

outofmemory exception when reading xml from file

I am working with twitter api data and after storing the stream results in text files, I input the data into a parser application. What I have planned for was large data files so I read the content in using delimiter]} to separate the individual posts to avoid the potential for errors? A backup function was to read the data using a buffer and then snip into individual posts.
But the problem is that in some cases for a single post, a memory exception will occur. Now when I look at the individual post it does not seem necessarily large but the text will contain foreign characters or some encoding I guess that causes the memory exception. I have not figured out if is exactly this yet but thought I would get some input or advice from here...
myreader.TextFieldType = FileIO.FieldType.Delimited
myreader.SetDelimiters("]}}")
Dim currentRow As String()
Try
While Not myreader.EndOfData
Try
currentRow = myreader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
data = data + currentField
counter += 1
If counter = 1000 Then
Dim pt As New parsingUtilities
If Not data = "" Then
pt.getNodes(data)
counter = 0
End If
End If
Next
Catch ex As Exception
If ex.Message.Contains("MemoryException") Then
fileBKup()
End If
End Try
the other time when a memory exception occurs is then I try to split into different posts:
Dim sampleResults() As String
Dim stringSplitter() As String = {"}}"}
' split the file content based on the closing entry tag
sampleResults = Nothing
Try
sampleResults = post.Split(stringSplitter, StringSplitOptions.RemoveEmptyEntries)
Catch ex As Exception
appLogs.constructLog(ex.Message.ToString, True, True)
moveErrorFiles(form1.infile)
Exit Sub
End Try
I expect the problem is the strings.
Strings are immutable, meaning that every time you think you're changing a string by doing this
data = data + currentField
you're actually creating another new string in memory. So if you do that thousands of times it can cause a problem because they mount up and you get an OutOfMemoryException.
If you're building up strings you should use a StringBuilder instead.

ASP: How to insert contents of array to database?

NOTE:, I don't need help with the generic concept of inserting data to a database, just sorting through the contents of an array depending on the content of the "line" and how to determine which "items" in the array correspond to a field in the database
I have a glob of data posted to me by a desktop application that I need to sort through. My old solution worked, but was far less than elegant (INSERT each line of glob into database, then query for, reINSERT, and delete old).
How can I get the following chunk of information (POSTED to me as "f_data") into an array and insert the data into a database?
f_data Contents:
Open~notepad.exe~7/14/2011 2:28:46 PM~COMPUTER01
Open~mspaint.exe~7/14/2011 2:28:55 PM~COMPUTER01
Close~notepad.exe~7/14/2011 2:30:06 PM~COMPUTER01
Close~mspaint.exe~7/14/2011 2:30:06 PM~COMPUTER01
Session~7/14/2011~336~COMPUTER01
Startup~7/18/2011 11:23:12 AM~COMPUTER01
Please keep in mind that I have never used arrays before. 15 years of ASP and I've never had to use an array. How I've been so lucky I don't know, but I think that it may be required for this solution. Here is my current code to put "f_data" into an array:
Example of what I want to do:
var_logdata = request.form("f_data")
arr_logdata = Split(var_logdata,"~")
for var_arrayitem = 0 to ubound(arr_logdata)
'Do some stuff here depending on the log type
'If type is "Open"
'insert to tb_applicationlog
'Elseif type is "Close"
'insert to tb_applicationlog
'Elseif type is "Session"
'insert to tb_sessions
'End if
next
What I don't know how to do is to determine what "type" of log entry the item in the array is. If you look at the code above, I need to insert to different tables in the database depending on the "type" of log entry. For example, an "Open" or "Close" entry goes into the tb_applicationlog table. Once I determine what type the log entry is, how do I align the items in the array "row" to fields in the database?
Thanks very much in advance,
Beems
I think it would be better to split 'logdata' using another character first, then spilt the fields in the array created by 'logdata' using '~', as below (code not tested) -
var_logdata = request.form("f_data")
arr_logdata = Split(var_logdata,vbCrLf)
'split request.form("f_data") using newline so we have an array containing each line
for var_arrayitem = 0 to ubound(arr_logdata)
'now we can split each line by "~"
arr_linelogdata = Split(arr_logdata(var_arrayitem),"~")
'now arr_linelogdata(0) is log type, arr_linelogdata(1) is next field etc
'linetype = arr_linelogdata(0) etc
'use variables derived from array to do what you need to
next

Resources