how to input data into an array from a text file that are vbTab separated? - vb.net

I am having trouble turning a set of data from a .txt file into arrays, basically, what i have in the text file is:
Eddy vbtab 20
Andy vbtab 30
James vbtab 20
etc..
I want to set up the names as a Names array, and numbers as number array.
Now what I have done is
strFilename = "CustomerPrices.txt"
If File.Exists(strFilename) Then
Dim srReader As New StreamReader(strFilename)
intRecords = srReader.ReadLine()
intRows = intRecords
For i = 0 To intRows - 1
intLastBlank = strInput.IndexOf(vbTab)
strName(intPrices) = strInput.Substring(0, intLastBlank)
dblPrices(intPrices) = Double.Parse(strInput.Substring(intLastBlank + 1))
But when I debug I get a problem "Object Reference not set to an instance of an object"
Can anyone give me some advise?
Thanks

Separate arrays are probably a bad idea here. They group your data by fields, when it's almost always better to group your data by records. What you want instead is a single collection filled with classes of a particular type. Go for something like this:
Public Class CustomerPrice
Public Property Name As String
Public Property Price As Decimal
End Class
Public Function ReadCustomerPrices(ByVal fileName As String) As List(Of CustomerPrice)
Dim result As New List(Of CustomerPrice)()
Using srReader As New StreamReader(fileName)
Dim line As String
While (line = srReader.ReadLine()) <> Nothing
Dim data() As String = line.Split(vbTab)
result.Add(new CustomerPrice() From {Name = data(0), Price = Decimal.Parse(data(1))})
End While
End Using
Return result
End Function
Some other things worth noting in this code:
The Using block will guarantee the file is closed, even if an exception is thrown
It's almost never appropriate to check File.Exists(). It's wasteful code, because you still have to be able to handle the file io exceptions.
When working with money, you pretty much always want to use the Decimal type rather than Double
This code requires Visual Studio 2010 / .Net 4, and was typed directly into the reply window and so likely contains a bug, or even base syntax error.

Related

Using the New List command with a Passed Parameter

I'm trying to Pass a Field Parameter from my form textbox to a Function to create a New List object from the Data Table parameter I'm passing.
In the following code, the first tmpReadTable shows with no syntax error, but when I try to use the Parm with the Datatable name I'm not sure what I'm missing syntax wise. I'm new to this, thanks in advance!
Updated code below:
Thank you for all the helpful replies...sorry I'm not more experienced, I'm coming from a Visual Foxpro background.
To summarize:
I want to pass in my IMPORT table parameters from my form.
The cImportTable is an empty SQL Table to use to import and validate each CSV file row.
I found this example in Murach's VB book but he leaves out how the LIST is being created from a PRODUCTS table in an earlier exercise. So I thought I could just substitute my passed cImportTable to do the same...that's where I'm stuck and maybe you all know of a better way.
Private Function ReadImportFile(ByVal cImportFile As String, ByVal cGroupID As String, ByVal cControlTable As String, ByVal cImportTable As String)
MessageBox.Show(cImportFile + " " + cGroupID + " " + cControlTable)
If Not File.Exists(cImportFile) Then
MessageBox.Show("File: " + cImportFile + " does not exist - cancelling process.")
Return False
End If
Dim curFileStream As New StreamReader(New FileStream(cImportFile, FileMode.Open, FileAccess.Read))
Dim curImportTable = "NewDataSet." + cImportTable
'Here I'm trying to create a LIST or DATASET using my Empty SQL Import Table and read in each row of the CSV file in the DO WHILE loop
'...I'm coming from Visual Foxpro background so am not sure what I'm missing or what is the standard procedure to do this simple task.
'This line gives me a syntax issue - and I'm not even sure what it's suppose to do, I'm taking it from Murach's VB book example,
'but he leaves out this vital piece of how to create this LIST from a Datatable - or if it's even the right method to use.
Dim tmpReadTable = New List(Of curImportTable)
Do While curFileStream.Peek <> -1
Dim row As String = curFileStream.ReadLine
Dim columns() As String = row.Split(",")
Dim ImportRecord As New curImportTable
ImportRecord.GroupId = columns(0)
ImportRecord.MemberId = columns(1)
Loop
'More Processing after Importing CSV file.....
curFileStream.Close()
'If lNoErrors
Return True
End Function
You are using a variable instead of TYPE on the code line #3 here
' This seems to be ok, no syntax error
Dim tmpReadTable = New List(Of NewDataSet.FO_ImportDataTable)
' The variable below implicitely will be of STRING type
Dim curImportTable = "NewDataSet." + cImportTable.ToString
' This line is not going to work
Dim tmpReadTable = New List(Of curImportTable)
' BUT THIS WILL
Dim x = New List(Of String)
Another issue is that Dim tmpReadTable happened twice in your code! can't re-declare variable. On top you declared it as NewDataSet.FO_ImportDataTable
Besides, I recommend declare all variables like Dim curImportTable as String, this way you can recognize types easier. Option Infer is good when you use anonymous types, LINQ, etc

string modifiers and properties do not work

I am trying to use Methods and Properties of the String Class to modify a string, but I keep getting an Invalid qualifier compile error. I even copied the following code* directly from the MSDN website and it throws the same error.
Public Sub Main()
Dim original As String
original = "aaabbb"
Dim modified As String
modified = original.Insert(3, " ")
End Sub
'This is the original code, but I had to change it slightly because the word-vba
'programming environment didn't like the syntax and highlighted everything red.
'Public Sub Main()
'Dim original As String = "aaabbb"
'Console.WriteLine("The original string: '{0}'", original)
'Dim modified As String = original.Insert(3, " ")
'Console.WriteLine("The modified string: '{0}'", modified)
'End Sub
Does word-vba not support string class modifiers and properties, am I not initializing the string correctly, or is there some other problem?
modified = original.Insert(3, " ")
You're thinking in VB.NET, but writing VBA. Strings (or any primitive or UDT type) don't have members in VBA. Not your fault, finding official VBA documentation is getting harder every day, with every "VBA" search yielding results for VB.NET.
That original code is clearly VB.NET.
If you mean to concatenate 3 spaces in front of original, then what you want to do is this:
modified = String(3, " ") & original
If you mean to get a new string in which a specified string is inserted at a specified index position in this instance (MSDN), then you want to do this (thanks #A.S.H!):
modified = Left$(original, 3) & " " & Right$(original, Len(original) - 3)

Listview - add File type & Last modified Subitems

I'm trying to add "file type" and "last modified" to my Listview when adding items in It same as in Explorer, but I don't find what property should be assigned to SubItem. Here is my code:
For Each MyFile As IO.FileInfo In ItemDirectory.GetFiles
Dim lvi As New ListViewItem
lvi.Tag = mFile.FullName
lvi.Text = mFile.Name
lvi.ImageKey = CacheShellIcon(mFile.FullName)
Listview1.Items.Add(lvi)
lvi.SubItems.Add("File type ??")
lvi.SubItems.Add(mFile.LastAccessTime.ToShortDateString & " " & mFile.LastAccessTime.ToShortTimeString) 'This isn't same as last modified ?
Next
If somebody knows how to do It please let me know, I want to have this in my Details view.
The linked answer provides an all-purpose way to get all the extended properties. With 300+ elements in newer Windows versions it is clearly overkill to fetch them all if you are only interested in one or two. This returns just the file type. A better approach might be to pass a "shopping list" of desired property names.
As before, you need to add a reference to Microsoft Shell Controls and Automation or Microsoft Shell Folder View Router based on your OS version.
Imports Shell32
Imports SHDocVw
Partial Friend Class Shell32Methods
Friend Shared Function GetShellFileProperty(filepath As String, index As Int32) As String
Dim shell As New Shell32.Shell
Dim shFolder As Shell32.Folder
shFolder = shell.NameSpace(Path.GetDirectoryName(filepath))
' get shell data for this file, cast to folder item
Dim shFolderItem = DirectCast(shFolder.Items().Item(Path.GetFileName(filepath)),
Shell32.ShellFolderItem)
If shFolderItem IsNot Nothing Then
Return shFolder.GetDetailsOf(shFolderItem, index)
Else
Return String.Empty
End If
End Function
...
End Class
Usage:
Dim lvi As ListViewItem
Dim fileType As String
For Each f As String In Directory.EnumerateFiles("C:\Temp\ShellTest")
fileType = Shell32Methods.GetShellFileProperty(f, 9)
lvi = New ListViewItem
lvi.Text = Path.GetFileName(f)
lvi.SubItems.Add(fileType)
lvFiles.Items.Add(lvi)
Next
Ideally, you'd want to create an Enum for the properties so the code could avoid magic numbers:
fileType = Shell32Methods.GetShellFileProperty(f, Shell32FileProps.FileType)
As noted elsewhere, the index of the ones >260 or so can change depending on the OS version. That could be easily modified to accept an Enum/Int array and return a list of values so as to prevent iterating all 300+ propertied to get one or three.
For filetype you can use lvi.SubItems.Add(MyFile.Extension)
and for the "last modified" date, of course the last modified! :D
lvi.SubItems.Add(MyFile.LastWriteTime.ToShortDateString)
Last write and last access are not the same ;)
I figured out another solution, I think this one is easier, at least for me :
Public Function ExProperty(filepath As String, PropertyItem As Integer)
Dim arrHeaders As New List(Of String)()
Dim shell As New Shell
Dim rFolder As Folder = shell.[NameSpace](Path.GetDirectoryName(filepath))
Dim rFiles As FolderItem = rFolder.ParseName(Path.GetFileName(filepath))
'I needed only File type so I looped to 2 only (2 is the file type in my case - Windows 10 -
' to see all available properties do a loop
' 0 To Short.MaxValue - 1" and then extract whatever property you like)
For i As Integer = 0 To 2
Dim value As String = rFolder.GetDetailsOf(rFiles, i).Trim()
arrHeaders.Add(value)
Next
Dim DesiredProperty As String
DesiredProperty = arrHeaders.Item(PropertyItem)
Return DesiredProperty
End Function
Usage with Listview just simply (this adds File type subitem):
Listview1_Item.SubItems.Add(ExProperty(filepath, 2))
As in all solutions, a reference to Microsoft Shell Controls and Automation must be set.

Create ReadOnly Property of CSV String vb.net

What is the best way to go about taking a List(Of objects) and adding a ReadOnly Property that displays a csv list of one of the Properties of the object? Is there a good way to convert that list to a string by specifying "Name".
Ex
Object = New Item()
Object.ID = 1
Object.Name = "Test"
li.Add(Object)
Object = New Item()
Object.ID = 2
Object.Name = "Test 2"
li.Add(Object)
Object = New Item()
Object.ID = 3
Object.Name = "Test 3"
li.Add(Object)
I'm thinking a for each would need to be done here or is there a better way to do this?
Return "Test, Test 2, Test 3" from the list values
Essentially, this does what I'm wanting to do but I would like to know if there is a BETTER way to do it.:
Public ReadOnly Property ItemList() As String
Get
Dim returnvalue As String = String.Empty
If Items.Count > 0 Then
For Each Item In Items
returnvalue = returnvalue & Item.Name & ", "
Next
Return Left(returnvalue, returnvalue.Length - 2)
Else
Return ""
End If
End Get
End Property
I have this link to share, the solution is similar, and may need a few tweeks. The conversion from C# to VB is simple enough and can show you where to make a few changes.
Write C# Lists of objects in CSV file
However, I believe your code is fine, with the exception of how you create your csv string.
I would recommend using string builder. This way, if an item exists, you build a new line. Otherwise, you don't. This would keep your from needed to remove (left) the last inserted comma. You would also want to catch the last item in your list, and avoid the comma at the end there.
as an exmaple:
Dim sb As StringBuilder
--if not last item then --
sb.AppendFormat ("{0},{1}",Item.Name,",")
--else this is last item--
sb.AppendFormat ("{0},",Item.Name)
The link I shared is a much better solution. My example is only to build your method more reliable.
Or, if you change your list of object to an array, or list of string...
Dim sampleList = New List(Of String)() From { _
"lala", _
"lulu", _
"lele" _
}
Dim data = String.Join(",", sampleList)

VB.NET: How to find a word after a specific word in a line and store it

I have a continuous string of words coming from a machine to hyper terminal of my system, for which I am using USB to serial cable. I want to find some of the values which comes after a specific word in that string and then store it.
I used threads and splitting concepts to do it but as per the requirement and operation of the machine it will not work properly in the runtime.
The values which I want to capture comes from a specific word. I want to skip that words and just store the values. How to do it?
I have given the example of that string below:
MEAN 49 50
SD 500 10
MIN 100 5
MAX 50 45.56
In this I just want to store the values e.g. 49 and 50, then discard MEAN. Then discard SD and store 500 and 10 and so on.
You can use a StreamReader object to read the stream one line at a time. Then, you can easily parse the line using the String.Split method. I would recommend creating one or more classes that represent the data being read, like this:
Public Class LineData
Public Property Label As String
Public Property Value1 As Decimal
Public Property Value2 As Decimal
End Class
Public Function ReadNextLine(stream As Stream) As LineData
Dim reader As New StreamReader(stream)
Dim line As String = reader.ReadLine()
Dim data As LineData = Nothing
If line IsNot Nothing Then
Dim words() As String = line.Split(New Char() {" "c}, StringSplitOptions.RemoveEmptyEntries)
If words.Length = 3 Then
data = New LineData()
data.Label = words(0)
data.Value1 = Decimal.Parse(words(1))
data.Value2 = Decimal.Parse(words(2))
End If
End If
Return Data
End Function
Note, this is a very simple example based on the example data you provided. If different lines have different numbers of numeric parameters, that will further complicate the logic. In my example, the method returns Nothing if no data can be read. Also, the method will throw an exception if the last two words in the line are not numeric. Therefore, you would need to wrap it in some additional exception handling.
This may be what you're looking for. Although personally I'd create a class which stores the type(mean, median etc), firstvalue and secondvalue.
By the sounds of it though, all you want it to do is dump the values into some sort of storage, therefore this will suffice.
Dim Values as New List(Of Decimal)
'Use a streamreader to read each line of text
Using reader As StreamReader = New StreamReader(*your text source*)
'Read the line
Dim linetext as string = reader.ReadLine
Dim myValue as decimal
'Split the line
Dim splitText() = linetext.Split(" ")
'Analyze each section of the line, if its possible to parse the value as a decimal then add it to the list of values to be stored.
For Each txt in splitText
If Decimal.TryParse(txt, myValue) then Values.Add(myValue)
Next
End Using