Read a text file

Read a text file

Often the output of one program is used as the input of another; a common method of transferring this information is through the use of files. For instance, an industrial designer may make a clay concept model of a new product; to begin the digital modeling process the model may be 3D scanned or measured with a coordinate measuring machine (CMM). The scanner or CMM doesn't need to know anything about the CAD program that will be used, it can output point data to a file which can then be imported to the CAD software as "point clouds" and subsequently used to recreate the surfaces. This tutorial will show how to read a text file and parse point information from it to draw lines between the given points.

File types

On Windows systems file names take the form [filename].[extension]; generally the extension is 3 letters long (though the filesystem your OS version uses may allow more) and they help the OS and the user to quickly identify the type of file. Even though there are 100's of different file types, they all basically belong to one of two categories: text file or binary file. Typical text files you will run across include: .txt (obviously), .log, .csv, .x_t. Some common binary files include: .exe, .dll, .mp3, .jpg, .prt. Try opening a few different files in notepad (or your favorite text editor, but remember to make a backup first and DO NOT SAVE THE FILE IN THE TEXT EDITOR); if you can make sense of it, it is likely a text file - if you are confronted with a mass of seeming gibberish, it is either a binary file or monkey test subject #27649's attempt at rewriting Shakespear's Hamlet. So even though we are reading text files, we are not limited to only files with the .txt extension.

.NET StreamReader

.NET provides everything we need to read text files; specifically, we will be using a "stream reader" object. For our input file, each line will represent a single point; X, Y, and Z values separated by commas.The stream reader will allow us to read the input file line by line. Our strategy will be to read a line, split it into components (XYZ), assign the components to a corresponding Point3D, and on the second and subsequent points - draw a line from the previous point to the current point.

Download the code here

'NXJournaling.com
'example: read text file
'each line of the input file should be 3 numbers separated by commas (#.###, #.###, #.###)
'the numbers will be interpreted as line start/end points
 
Option Strict Off
Imports System
Imports System.IO
Imports System.Windows.Forms
Imports NXOpen
 
Module Module1
 
    Sub Main()
        Dim openFileDialog1 As New OpenFileDialog()
 
        openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
        openFileDialog1.FilterIndex = 1
        openFileDialog1.RestoreDirectory = True
 
        If openFileDialog1.ShowDialog() = DialogResult.OK Then
            Dim theSession As Session = Session.GetSession()
            Dim workPart As Part = theSession.Parts.Work
            Dim line As String
            Dim startPoint As Point3d  = nothing
            Dim endPoint As Point3d
            Dim firstPass as Boolean = True
            Dim delim As Char() = {","c}
 
            Using sr As StreamReader = New StreamReader(openFileDialog1.FileName)
                Try
                    line = sr.ReadLine()
                    While Not line Is Nothing
                        Dim strings As String() = line.Split(delim)
                        endPoint.x = Double.Parse(strings(0))
                        endPoint.y = Double.Parse(strings(1))
                        endPoint.z = Double.Parse(strings(2))
                        If firstPass Then
                            firstPass = False
                        Else
                            'create a line from startpoint to endpoint
                            workPart.Curves.CreateLine(startPoint, endPoint)
                        End If
                            startPoint = endPoint
 
                            line = sr.ReadLine()
                    End While
                Catch E As Exception
                    MessageBox.Show(E.Message)
                End Try
            End Using
        End If
    End Sub
 
 
    Public Function GetUnloadOption(ByVal dummy As String) As Integer
 
         'Unloads the image when the NX session terminates
        GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination
 
    End Function
 
End Module 

Some items of note:
You may have noticed we didn't use the usual Dim statement before the StreamReader variable. The Using... End Using block will dispose of the stream reader object at the proper time; otherwise, we would have to call the stream reader's Close method ourselves to mark it for garbage collection. The Using... End Using block allows the compiler to do the work for us and we can be assured the stream reader will be disposed of properly; had we used Dim sr as StreamReader... and forgotten the sr.Close statement, the compiler would not warn us (since it doesn't know when or if we want to close the stream reader).

The Double.Parse method is used to convert the text to a numeric value (of type double). If your computer's regional settings use something other than the decimal point for the decimal separator (the comma, for instance), you likely got an error message along the lines of "input in an incorrect format". We can correct this by specifying what format we want to read; the next bit of journal code will show how to do this.

All input points were interpreted into the absolute coordinate system of the part. The next journal will include a function to map the points to the WCS.

Improved Code

This next journal includes a System.Globalization.CultureInfo object that is set to US english ("en-US"), since that is the format that we expect the input strings to use (change the journal accordingly for your specific requirements). Now when the values are parsed, we specify the text to parse along with the culture info to interpret it properly. This code should now run properly regardless of the computer's regional settings.

Lastly, there is a function included (taken from a GTAC example) that converts the point coordinates to the WCS.

'NXJournaling.com
'example: read text file
'each line of the input file should be 3 numbers separated by commas (#.###, #.###, #.###)
'the numbers will be interpreted as line start/end points
 
Option Strict Off  
Imports System  
Imports System.IO  
Imports System.Windows.Forms  
Imports NXOpen  
Imports NXOpen.UF  
 
Module Module1  
	Dim ufs As UFSession = UFSession.GetUFSession  
 
	Sub Main()  
		Dim openFileDialog1 As New OpenFileDialog()  
 
		openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"  
		openFileDialog1.FilterIndex = 1  
		openFileDialog1.RestoreDirectory = True  
 
		If openFileDialog1.ShowDialog() = DialogResult.OK Then  
			Dim theSession As Session = Session.GetSession()  
			Dim workPart As Part = theSession.Parts.Work  
			Dim line As String  
			Dim startPoint As Point3d  = nothing  
			Dim endPoint As Point3d  
			Dim i As Integer = 0  
			Dim firstPass as Boolean = True
			Dim delim As Char() = {","c}  
			Dim USculture As system.globalization.CultureInfo = New System.Globalization.CultureInfo("en-US")  
 
			Using sr As StreamReader = New StreamReader(openFileDialog1.FileName)  
			Try  
				line = sr.ReadLine()  
				While Not line Is Nothing  
					Dim strings As String() = line.Split(delim)  
					endPoint.x = Double.Parse(strings(0), USculture)  
					endPoint.y = Double.Parse(strings(1), USCulture)  
					endPoint.z = Double.Parse(strings(2), USCulture)  
					endPoint = Abs2WCS(endPoint)  
					If firstPass Then  
						firstPass = False  
					Else  
						'create a line from startpoint to endpoint
						workPart.Curves.CreateLine(startPoint, endPoint)  
					End If  
					startPoint = endPoint  
					line = sr.ReadLine()  
				End While  
			Catch E As Exception  
				MessageBox.Show(E.Message)  
			End Try
			End Using
		End If  
 
	End Sub  
'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
'Date:  11/18/2010
'Subject:  Sample NX Open .NET Visual Basic routine : map point from absolute to wcs
'
'Note:  function taken from GTAC example code
 
	Function Abs2WCS(ByVal inPt As Point3d) As Point3d  
		Dim pt1(2), pt2(2) As Double  
 
		pt1(0) = inPt.X  
		pt1(1) = inPt.Y  
		pt1(2) = inPt.Z  
 
		ufs.Csys.MapPoint(UFConstants.UF_CSYS_ROOT_COORDS, pt1, _  
			UFConstants.UF_CSYS_ROOT_WCS_COORDS, pt2)  
 
		Abs2WCS.X = pt2(0)  
		Abs2WCS.Y = pt2(1)  
		Abs2WCS.Z = pt2(2)  
 
    End Function   
'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
	Public Function GetUnloadOption(ByVal dummy As String) As Integer  
 
'Unloads the image when the NX session terminates
		GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination  
 
	End Function  
 
End Module

Conclusion

This article shows how to use .NET's stream reader to read a text file line by line. As long as you know how to interpret the input file, you can write custom code to read it and do something useful with it in NX.

Comments

NXJournaling,

Do you have a code where the whole input file is "loaded" to a string (then closed) rather than read line by line. My code below (for an xls macro) does not work

'Allocate all the data in file to string 'TotalFile' then close it
FileNum = FreeFile
Open strFileToProcess For Binary As #FileNum
TotalFile = Space(LOF(FileNum))
Get #FileNum, , TotalFile
Close #FileNum

Thanks
Regards

Are you reading a text file or a binary file?

The following links may be of some interest to you. The stream reader object has several "read*" methods, one or more may be useful to you. The other link has some example code for reading and writing to a binary file.

https://msdn.microsoft.com/en-us/library/System.IO.StreamReader%28v=vs.1...

https://msdn.microsoft.com/en-us/library/aa711083%28v=vs.71%29.aspx

Thanks for the links. Apologies for the stupid question. I totally missed the ReadToEnd() option when looking at the online doc a couple of days ago. Doing too many things at once I guess (!). The following does job

If openFileDialog1.ShowDialog() = DialogResult.OK Then
Dim sr As StreamReader = New StreamReader(openFileDialog1.FileName)
TotalFile=sr.ReadToEnd()
sr.Close
theLW.WriteLine("File content is: " & TotalFile)
End If

Thanks
Regards

You don't really need a Streamreader. Just use the System.IO.File read functions. ReadAllText reads all text into a single string, and ReadAllLines reads all text into an array of strings, one string per line.

Back in the NX programming world after doing some "real" work. I have started looking into a way pf processing a number of .csv files (in 1-go) to create records in an NX(.CAE) .afu file

Does anyone know if there is a way of extracting an entire column from a csv file without having to read it line-by line?

To create a record in an NX .afu file one needs to create "vectors" of X and Y values. In my case the Y values may actually be a set of values so the Y column is actually 2 columns.

But consider the simple case of an X,Y set. The .csv file will have the standard format:

header1,header2, header3, etc
value11,value21,value31,etc
value12,value22,value32,etc
etc

read csv file to create columns of data
 
Dim Xdata() As Double
Dim Ydata() As Double
Dim theAFUData As CAE.AfuData
 
Xdata:= csvcolumn1 (from row 2 to Nrow)
 
For col = 2 to NCol
   Ydata=csvcolumn(col)
   'create record afu record
   theAFUData.SetRealData(Xdata,Ydata)
Next col

Thanks
Regards

Thanks
Regards

Would the Method Array.Copy() works in NX? Looks like on needs to declare the System.Array and can't remember if this is "supported". It's been a while since I have a look at NX programming

Thanks
Regards

If you are using a .NET language, it should be supported.
https://msdn.microsoft.com/en-us/library/k4yx47a1(v=vs.110).aspx

I don't know of a way to get what you want without reading every line, but the TextFieldParser may help with your task.

https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.te...

while doing some search onthe problem I came across the use of DataTable variable which seems to be using the system.data.olddb
could this be used?

i have nearly work out the workflow to convert the csv into the array required. just need to start basic coding

Thanks
Regards

Found some pseudo-code to convert csv to a DataTable, see below.
Has anyone ever used that sort of type? Looks like it's quite neat
Haven't found yet how to
1. create/put data in the table as double
2. extract an entire column (or a column between 2 specific row)
3. "print" a specific value or loop through data in a column/row

Thanks
Regards

	Sub TestDataTable()
 
	'converts the CSV into a new in-memory DataTable
		Dim sFileName As String	
		sFileName = "C:\exampletestdata.txt"
 
	   Dim TextFileReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(sFileName)
 
		TextFileReader.TextFieldType = FileIO.FieldType.Delimited
		TextFileReader.SetDelimiters(",")
 
		Dim dtTextFileTable As DataTable = Nothing
 
		Dim Column As DataColumn
		Dim Row As DataRow
		Dim UpperBound,ColumnCount As Int32
		Dim CurrentRow As String()
 
		Dim sDataTableName As String
		sDataTableName = "TextFileTable"
 
		While Not TextFileReader.EndOfData
			Try
				CurrentRow = TextFileReader.ReadFields()
				If Not CurrentRow Is Nothing Then
					''# Check if DataTable has been created
					If dtTextFileTable Is Nothing Then
						dtTextFileTable = New DataTable(sDataTableName)
						''# Get number of columns
						UpperBound = CurrentRow.GetUpperBound(0)
						''# Create new DataTable
						For ColumnCount = 0 To UpperBound
							Column = New DataColumn()
							Column.DataType = System.Type.GetType("System.String")
							Column.ColumnName = "Column" & ColumnCount
							Column.Caption = "Column" & ColumnCount
							Column.ReadOnly = True
							Column.Unique = False
							dtTextFileTable.Columns.Add(Column)
						Next
					End If
					Row = dtTextFileTable.NewRow
					For ColumnCount = 0 To UpperBound
						Row("Column" & ColumnCount) = CurrentRow(ColumnCount).ToString
					Next
					dtTextFileTable.Rows.Add(Row)
				End If
			Catch ex As _
			Microsoft.VisualBasic.FileIO.MalformedLineException
				MsgBox("Line " & ex.Message & _
				"is not valid and will be skipped.")
			End Try
		End While
		TextFileReader.Dispose()
 
End sub

Thanks
Regards

Have a look at this code:
http://nxjournaling.com/content/find-duplicate-sheet-bodies

It uses a data table to record information about model faces. It should answer your question #1.

Once you have your information in the data table, you can run SQL code on it to extract all the rows, or only certain ones that meet your specified criteria. Do a websearch on "SQL tutorial" and you should get many good results.

Thanks for the link and suggestion

Made some progress. I just cannot decide if processing the csv file with a DataTable is better/faster that the "traditional" way

I have not found a way of extracting an entire column to put it into an array without using LINQ. Looks like one still needs to loop trough each row which defeat the purpose somewhat

Dim X(),Y() As Double
Dim total As Integer
 irowtotal = myTableData.Rows.Count - 1
 
 ReDim X(0 To irowtotal)
 ReDim Y(0 To irowtotal)
 
       For N = 0 to 15 By 3
	For r = 0 To irowtotal
		X(r) = myTableData.Rows(r)(N)
		Y(r) = myTableData.Rows(r)(N+1)
	 Next r
           'deal with X& Y
        Next N

Thanks
Regards