Hello I recieve a "nullreferenceexception was unhandled" error when I try to run this code:
For i As Integer = 1 To aantaltags
csvopc(i) = csvtagssplit(17 * i)
csvsql(i) = csvtagssplit(17 * i + 15)
Next
Background:
I read a csv file that I clean up and split into csvtagssplit()
csvopc and csvsql are both declared as string() at the top of the program.
anything dumb I did and I'm not noticing?
replicate it if you want to:
code:
http://pastebin.com/JDPa6FSB
csv:
http://pastebin.com/2e66i9EB
Your problem is in the intial part of your code where you declare the two variables cvsopc and cvssql,
As from your comment you write
Dim csvopc As String()
Dim csvsql As String()
But this only declares the two variables without any dimension.
So when you try to reach csvopc(i) you are effectively referencing a index that doesn't exist
Why use arrays when you don't know the exact size of your elements?.
You can easily switch to a List(Of String) where you can dinamically add elements
Dim csvopc As List(Of String) = new List(Of String)
Dim csvsql As List(Of String) = new List(Of String)
and then in your loop
For i As Integer = 0 To aantaltags - 1
csvopc.Add(csvtagssplit(17 * i))
csvsql.Add(csvtagssplit(17 * i + 15))
Next
A List(Of String) could also be referenced by Index as in
Dim aValue = csvopc(0)
You should step through your code with a debugger in order to inspect the data as the code runs. You could put a breakpoint at a place where everything should be initialized but before the exception happens and then see what the values are.
Which iteration of the loop fails, and what line specifically fails? Put a breakpoint on that line and see what all the values are immediately before the line executes. If this debugging doesn't reveal the error to you, update your post with the data you find during debugging and maybe we can get somewhere.
Related
I am needing to create a code that is versatile enough where I can add more columns in the future with minimum reconstruction of my code. My current code does not allow me to travel through my file with my 2-D array. If I was to change MsgBox("map = "+ map(0,1) I can retrieve the value easily. Currently all I get in the code listed is 'System.IndexOutOfRangeException' and that Index was outside the bounds of the array. My current text file is 15 rows (down) and 2 columns (across) which puts it at a 14x1. they are also comma separated values.
Dim map(14,1) as string
Dim reader As IO.StreamReader
reader = IO.File.OpenText("C:\LocationOfTextFile")
Dim Linie As String, x,y As Integer
For x = 0 To 14
Linie = reader.ReadLine.Trim
For y = 0 To 1
map(x,y) = Split(Linie, ",")(y)
Next 'y
Next 'x
reader.Close()
MsgBox("map = " + map(y,x))``
Here's a generic way to look at reading the file:
Dim data As New List(Of List(Of String))
For Each line As String In IO.File.ReadAllLines("C:\LocationOfTextFile")
data.Add(New List(Of String)(line.Split(",")))
Next
Dim row As Integer = 1
Dim col As Integer = 10
Dim value As String = data(row)(col)
This is the method suggested by Microsoft. It is generic and will work on any properly formatted comma delimited file. It will also catch and display any errors found in the file.
Using MyReader As New Microsoft.VisualBasic.
FileIO.TextFieldParser(
"C:\LocationOfTextFile")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
MsgBox(currentField)
Next
Catch ex As Microsoft.VisualBasic.
FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
"is not valid and will be skipped.")
End Try
End While
End Using
Essentially what you are asking is how can I take the contents of comma-separated values and convert this to a 2D array.
The easiest way, which is not necessarily the best way, is to return an IEnuemrable(Of IEnumerable(Of String)). The number of items will grow both vertically based on the number of lines and the number of items will grow horizontally based on the values split on a respective line by a comma.
Something along these lines:
Private Function GetMap(path As String) As IEnumerable(Of IEnumerable(Of String)
Dim map = New List(Of IEnumerable(Of String))()
Dim lines = IO.File.ReadAllLines(path)
For Each line In lines
Dim row = New List(Of String)()
Dim values = line.Split(","c)
row.AddRange(values)
map.Add(row)
Next
Return map
End Function
Now when you want to grab a specific cell using the (row, column) syntax, you could use:
Private _map As IEnumerable(Of IEnumerable(Of String))
Private Sub LoadMap()
_map = GetMap("C:/path-to-map")
End Sub
Private Function GetCell(row As Integer, column As Integer) As String
If (_map Is Nothing) Then
LoadMap()
End If
Return _map.ElementAt(row).ElementAt(column)
End Function
Here is an example: https://dotnetfiddle.net/ZmY5Ki
Keep in mind that there are some issues with this, for example:
What if you have commas in your cells?
What if you try to access a cell that doesn't exist?
These are considerations you need to make when implementing this in more detail.
You can consider the DataTable class for this. It uses much more memory than an array, but gives you a lot of versatility in adding columns, filtering, etc. You can also access columns by name rather than index.
You can bind to a DataGridView for visualizing the data.
It is something like an in-memory database.
This is much like #Idle_Mind's suggestion, but saves an array copy operation and at least one allocation per row by using an array, rather than a list, for the individual rows:
Dim data = File.ReadLines("C:\LocationOfTextFile").
Select(Function(ln) ln.Split(","c)).
ToList()
' Show last row and column:
Dim lastRow As Integer = data.Count - 1
Dim lastCol As Integer = data(row).Length - 1
MsgBox($"map = {data(lastRow)(lastCol)}")
Here, assuming Option Infer, the data variable will be a List(Of String())
As a step up from this, you could also define a class with fields corresponding to the expected CSV columns, and map the array elements to the class properties as another call to .Select() before calling .ToList().
But what I really recommend is getting a dedicated CSV parser from NuGet. While a given CSV source is usually consistent, more broadly the format is known for having a number of edge cases that can easily confound the Split() function. Therefore you tend to get better performance and consistency from a dedicated parser, and NuGet has several good options.
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
I dont know Why I am having trouble with this, but I keep getting 'not set to an instance of an object' exception every time.
Does this make sense?
I have this declared in the main form
Private _Paths() As System.Drawing.Drawing2D.GraphicsPath
and do this in a sub
_Paths(20) = New GraphicsPath
But for whatever reason I get an object reference error on the second line. Any help?
After the decleration, I want to then go ahead and add a line to the graphics path like so
_Paths(k).AddLine(x_loc(k), y_loc(k), x_loc(k + 1), y_loc(k + 1))
As per suggestion to use list:
Declared in main class
Private _Paths As List(Of System.Drawing.Drawing2D.GraphicsPath)
using in sub
for k = 0 to 10
'x_loc and y_loc calculations are done here
_Paths.Add(New GraphicsPath)
_Paths(k).AddLine(x_loc(k), y_loc(k), x_loc(k + 1), y_loc(k + 1))
next
still get error when trying to create new instance of graphicspath
There should be no reason this error should pop up right?
Private _Paths As NEW List(Of System.Drawing.Drawing2D.GraphicsPath)
Your not redimensioning your array, instead use a List(Of GraphicsPath) and just .Add them as you need.
Dim myPaths As New List(Of GraphicsPath)
'later in code
myPaths.Add(New GraphicsPath)
myPaths(0).AddLine(...)'etc...
A list must be declared with New
Dim YourList As New List(Of GraphicsPath)
I notice in your screenshot you are not actually adding new GraphicsPath objects
You are not giving the parameters to create one
Dim Rec As New Rectangle(LocationX,LocationY, Width,Height) 'Create a binding rectangle to contain the graphic
Yourlist.Add(New GraphicsPath {Rec}) 'In place of 'Rec' you can also specify parameters directly
OR
Yourlist.Add(New GraphicsPath {LocationX,LocationY, Width,Height})
The code I have is:
Dim Dbase() As String = Nothing
Dbase(0) = Db_ComboBox.Text
I have declared Dbase as array and assigned Nothing, Db_ComboBox is a combobox.
For that assignment statement, I'm getting the following error: "Reference 'Dbase' has a value of 'Nothing'"
What is the reason for this error, and how can I take the value from the combobox and save it in the array?
You need to change this:
Dim Dbase() As String = Nothing
to this (declare an array of 1 element):
Dim Dbase(0) As String
And then this line will work:
Dbase(0) = Db_ComboBox.Text
If you need to change your array size you can use Redim or Redim preserve, as required.
If you anticipate contents of Dbase to change often, I am all with #Joel's suggestion about switching to List(Of String) instead of handling array sizes manually.
Let's look at your code:
Dim Dbase() As String = Nothing
Dbase(0) = Db_ComboBox.Text
Especially the first line. That first line creates a variable that can refer to an array, but the = Nothing portion explicitly tells it, "Do not create a real array here yet". You have, effectively, a pointer that doesn't point to anything.
I get here that what you really need is a List collection that you can append to over time:
Dim Dbase As New List(Of String)()
Dbase.Add(Db_ComboBox.Text)
Dbase() IS NOTHING. Look at this example:
cargoWeights = New Double(10) {}
atmospherePressures = New Short(2, 2, 4, 10) {}
inquiriesByYearMonthDay = New Byte(20)()() {}
That's how you declare arrays.
More examples: http://msdn.microsoft.com/en-us/library/vstudio/wak0wfyt.aspx
I Have a text file that is like the following:
[group1]
value1
value2
value3
[group2]
value1
value2
[group3]
value3
value 4
etc
What I want to be able to do, is load the values into an array (or list?) based on a passed in group value. eg. If i pass in "group2", then it would return a list of "value1" and "value2".
Also these values don't change that often (maybe every 6 months or so), so is there a better way to store them instead of a plain old text file so that it makes it faster to load etc?
Thanks for your help.
Leddo
This is a home work question?
Use the StreamReader class to read the file (you will need to probably use .EndOfStream and ReadLine()) and use the String class for the string manipulation (probably .StartsWith(), .Substring() and .Split().
As for the better way to store them "IT DEPENDS". How many groups will you have, how many values will there be, how often is the data accessed, etc. It's possible that the original wording of the question will give us a better clue about what they were after hear.
Addition:
So, assuming this program/service is up and running all day, and that the file isn't very large, then you probably want to read the file just once into a Dictionary(of String, List(of String)). The ContainsKey method of this will determine if a group exists.
Function GetValueSet(ByVal filename As String) As Dictionary(Of String, List(Of String))
Dim valueSet = New Dictionary(Of String, List(Of String))()
Dim lines = System.IO.File.ReadAllLines(filename)
Dim header As String
Dim values As List(Of String) = Nothing
For Each line As String In lines
If line.StartsWith("[") Then
If Not values Is Nothing Then
valueSet.add(header, values)
End If
header = GetHeader(line)
values = New List(Of String)()
ElseIf Not values Is Nothing Then
Dim value As String = line.Trim()
If value <> "" Then
values.Add(value)
End If
End If
Next
If Not values Is Nothing Then
valueSet.add(header, values)
End If
Return valueSet
End Function
Function GetHeader(ByVal line As String)
Dim index As Integer = line.IndexOf("]")
Return line.Substring(1, index - 1)
End Function
Addition:
Now if your running a multi-threaded solution (that includes all ASP.Net solutions) then you either want to make sure you do this at the application start up (for ASP.Net that's in Global.asax, I think it's ApplicationStart or OnStart or something), or you will need locking. WinForms and Services are by default not multi-threaded.
Also, if the file changes you need to restart the app/service/web-site or you will need to add a file watcher to reload the data (and then multi-threading will need locking because this is not longer confined to application startup).
ok, here is what I edned up coding:
Public Function FillFromFile(ByVal vFileName As String, ByVal vGroupName As String) As List(Of String)
' open the file
' read the entire file into memory
' find the starting group name
Dim blnFoundHeading As Boolean = False
Dim lstValues As New List(Of String)
Dim lines() As String = IO.File.ReadAllLines(vFileName)
For Each line As String In lines
If line.ToLower.Contains("[" & vGroupName.ToLower & "]") Then
' found the heading, now start loading the lines into the list until the next heading
blnFoundHeading = True
ElseIf line.Contains("[") Then
If blnFoundHeading Then
' we are at the end so exit the loop
Exit For
Else
' its another group so keep going
End If
Else
If blnFoundHeading And line.Trim.Length > 0 Then
lstValues.Add(line.Trim)
End If
End If
Next
Return lstValues
End Function
Regarding a possible better way to store the data: you might find XML useful. It is ridiculously easy to read XML data into a DataTable object.
Example:
Dim dtTest As New System.Data.DataTable
dtTest.ReadXml("YourFilePathNameGoesHere.xml")