How to open the csv file with proper length in xl - vb.net

Using VB.Net
Below code is working fine for creating a csv file.
When i open the csv file in xls or xlsx, some of the columns are collapsed, i need to expand manually to see the full details of the each column. I want to create a csv file with wraptext or length of the data
Code
Sub SetDataTable_To_CSV(ByVal dtable As DataTable, ByVal path_filename As String, ByVal sep_char As String)
Dim streamWriter As System.IO.StreamWriter
Try
streamWriter = New System.IO.StreamWriter(path_filename)
Dim _sep As String = ""
Dim builder As New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(col.ColumnName)
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
For Each row As DataRow In dtable.Rows
_sep = ""
builder = New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(row(col.ColumnName))
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
Next
Catch ex As Exception
Finally
If Not streamWriter Is Nothing Then streamWriter.Close()
End Try
End Sub
For Example
In csv file
12345,987665544433
Same File when i open in xl
12345,1.02141E+15
Expected Output
in xl file also
12345,987665544433
How to achieve this. Need code help

This behavior happens because of scientific notation which is a "feature" built into Excel. Unfortunately there is no known way to disable this, there are workarounds however:
1) If you want the numbers to show up properly without having to do anything then adding commas into your numbers is the way to go. Excel will still treat this as a number field, and will stop doing scientific notation on the number.
Note: You will most likely have to wrap all text in double-quotes to prevent Excel from thinking the commas indicate a new column. Wrapping your text with double quotes alone will not stop scientific notation from changing your numbers!:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(String)) ' Notice that our number field is saved as type string so that we can add commas into the number
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = FormatNumber(987654320 + i, 0, TriState.UseDefault, TriState.UseDefault, TriState.True) ' Format the number with commas
dt.Rows.Add(dr)
Next
SetDataTable_To_CSV(dt, System.IO.Path.Combine(Application.StartupPath, "test.csv"), ",")
End Sub
Sub SetDataTable_To_CSV(ByVal dtable As DataTable, ByVal path_filename As String, ByVal sep_char As String)
Dim streamWriter As System.IO.StreamWriter
Try
streamWriter = New System.IO.StreamWriter(path_filename)
Dim _sep As String = ""
Dim builder As New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(FixCSVField(col.ColumnName)) ' Add quotes around this field
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
For Each row As DataRow In dtable.Rows
_sep = ""
builder = New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(FixCSVField(row(col.ColumnName))) ' Add quotes around this field
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
Next
Catch ex As Exception
Finally
If Not streamWriter Is Nothing Then streamWriter.Close()
End Try
End Sub
Function FixCSVField(sInString As String) As String
Return """" & sInString.Replace("""", """""""") & """" ' Wrap string in quotes to prevent problems with commas in the field and escape double quotes with another double quote
End Function
End Class
2) If you don't like the comma approach then you can always just open up the csv and highlight all the cells that you want to change. Once highlighted you can right-click on the columns and choose the "Format Cells" option. In the "Category" box, click "Number" and click "OK" to change all your cells back into numbers so that they no longer show up funny. Unfortunately this has to be done for every new csv file that you generate and I'm kind of assuming you knew about this option and were looking for the automatic method above.
3) The only last thing I can recommend is to use a different csv viewer such as Open Office or Google Spreadsheets to view your CSV files as these products do not truncate your numbers.
Good luck!
Edit:
I just thought of some more ideas on how to create your excel files automatically without any user intervention:
4) Use Excel Automation. You can use this to create an xls/xlsx file directly instead of a csv file. The benefit here is that you have a little more control of the data and layout then you do with a simple csv file. Unforunately there are many drawbacks and it depends upon your situation whether or not this is a valid option:
Potential Negatives:
You will require a license for Microsoft Excel on every machine your application will run on
All machines that the application runs on must have the same version of Microsoft Excel installed (For some reason I am thinking that newer versions installed on the client machine may still work, but older for sure will not, can anyone confirm?)
When you use Excel Automation, Microsoft Excel is loaded in the background which takes up memory to load a large number of files/DLLs
Excel Automation is much slower to generate large files as opposed to CSV
Microsoft explicitly recommends against using Excel Automation in a server environment: http://support.microsoft.com/kb/257757
That all being said, if you are just using the app on your own machine or you know for sure that everyone else who will use it is going to have the same version of Excel installed, this is a great way to write your Excel files without having to worry about the scientific notation problem.
Here is some sample code using the same test data as above:
Note: Before you can use this code you must add a reference to the Microsoft Excel xx.0 Object Library to your project. The version number will depend upon which version of Microsoft Excel you have installed on your machine. In my case I have Excel 2013 and therefore I add the Microsoft Excel 15.0 Object Library. You do this by opening up your project properties window, click the "References" tab, Click "Add", Click the "Com" tab and put a check next to the Microsoft Excel Object Library and click "OK".
Imports Microsoft.Office.Interop
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Notice that our number field is now actually an integer type
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Excel automation to create an xls/xlsx file
Dim xlApp As Excel.Application = New Microsoft.Office.Interop.Excel.Application()
If xlApp Is Nothing Then
' Excel automation can only be used if the correct version of excel is installed on the machine
MessageBox.Show("Excel is not installed on this computer.")
Else
Dim bIsXLSX As Boolean = True ' If this is true then an xlsx file is created, if false then the older xls file is used (use xls only if you need to support office 2003 and below)
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim misValue As Object = System.Reflection.Missing.Value
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls" & If(bIsXLSX = True, "x", ""))
xlWorkBook = xlApp.Workbooks.Add(misValue)
xlWorkSheet = xlWorkBook.Sheets("sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
xlWorkSheet.Cells(1, c + 1) = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
xlWorkSheet.Cells(r + 2, c + 1) = dt.Rows(r).Item(c) ' Write the data to the correct column
Next
Next
xlWorkSheet.Columns.AutoFit() ' Autofit all cells to ensure they do not show the scientific notation
xlWorkBook.SaveAs(sFilename, If(bIsXLSX = True, Excel.XlFileFormat.xlWorkbookDefault, Excel.XlFileFormat.xlWorkbookNormal), misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue)
xlWorkBook.Close(True, misValue, misValue)
xlApp.Quit()
' Cleanup excel object
ReleaseExcelObject(xlWorkSheet)
ReleaseExcelObject(xlWorkBook)
ReleaseExcelObject(xlApp)
MessageBox.Show("Excel file created: " & sFilename)
End If
End Sub
Private Sub ReleaseExcelObject(ByVal oExcelObject As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcelObject)
oExcelObject = Nothing
Catch ex As Exception
oExcelObject = Nothing
Finally
GC.Collect()
End Try
End Sub
End Class
5) If you would like to go the xls/xlsx route (as opposed to csv) but can't ensure that every client machine the app will be run on will have the same version of Excel installed you can use a third party dll to generate the file. The benefit of this approach is that the client machine does not even need to have Microsoft Excel installed to work. The biggest drawback to this method is that most dlls are not free.
There are many different options when it comes to these third party dlls so you have a lot of choices. Here are a few examples that should work for you:
Spire.XLS
GemBox.Spreadsheet
SpreadsheetGear
ComponentOne Excel for .Net
TMS Flexcel Studio for .NET
The only one I have used in the past is Spire.XLS and I will provide a working example below to demonstrate how easy it is to create the excel file with this dll. They provide a fully functional dll for free that you can use to test the product. The only limitation of using the free version versus paying is that the free version will automatically insert an extra worksheet into the file with an evaluation warning.
At the time of writing the newest version is 7.6 and you can find a direct link here: http://www.e-iceblue.com/downloads/spire.xls-se_7.6.zip (usually you need to signup to get the download link so this link may change in the future).
Here is a sample of how to get it working:
Imports Spire.Xls
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Spire.XLS to create an xls file
Dim bIsXLSX As Boolean = True ' If this is true then an xlsx file is created, if false then the older xls file is used (use xls only if you need to support office 2003 and below)
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls" & If(bIsXLSX = True, "x", ""))
Dim oWorkbook As New Workbook
Dim oSheet As Worksheet = oWorkbook.Worksheets(0)
' New workbook automatically creates 3 blank worksheets by default
' Remove the last two since we only need one
oWorkbook.Worksheets.Remove(oWorkbook.Worksheets(2))
oWorkbook.Worksheets.Remove(oWorkbook.Worksheets(1))
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oSheet.Range(1, c + 1).Text = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oSheet.Range(r + 2, c + 1).Text = dt.Rows(r).Item(c) ' Write the data to the correct column
Next
Next
oSheet.Range().AutoFitColumns() ' Automatically adjust the width of all columns to fit the data
oWorkbook.SaveToFile(sFilename, If(bIsXLSX = True, ExcelVersion.Version2013, ExcelVersion.Version97to2003)) ' You can change version from 2013 to match the version of Excel you are using
oWorkbook.Dispose()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
6) There is a free, open-source dll called ExcelLibrary that will create an xls file without having Excel installed but it hasn't been updated since 2011 and has a few quirks. First off it does not support the newer xlsx format, which shouldn't be an issue for you since you were using csv to begin with. Second, it supports setting the column width but it doesn't have an autofit option so you will have to hardcode the width which might cause the original problem with scientific notation if you don't specify a large enough width. Next, it does other funny things to large numbers like the ones you specified (ex. 987665544433) so you again have to treat the number as a string when you write it or else you will get negative numbers when they should be large positive numbers. Finally, xls files generated with this dll don't open properly in Microsoft Excel 2010 or higher unless it is of a certain filesize (file needs to be at least 7 KB in size so if you have too few rows the file won't open). However there is a workaround for this which involves adding blank data rows to the end of the file to make the filesize larger and therefore readable by Microsoft Excel. I don't recommend this approach because of all the quirks but I am including it for completion sake. Download the dll from here: https://code.google.com/p/excellibrary/
Imports ExcelLibrary.SpreadSheet
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(String)) ' Our number field is a string value again, if you try Int32 it makes large numbers negative and if you try Int64 it will give you an "Invalid cell value" error
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Excel Library to create an xls file
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls")
Dim oWorkbook As New Workbook()
Dim oWorksheet As New Worksheet("Sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(0, c) = New Cell(dt.Columns(c).ColumnName)
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(r + 1, c) = New Cell(dt.Rows(r).Item(c)) ' Write the data to the correct column
Select Case c
Case Is = 0 ' StringField width
oWorksheet.Cells.ColumnWidth(c) = 3000
Case Is = 1 ' NumberField width
oWorksheet.Cells.ColumnWidth(c) = 3500
End Select
Next
Next
' Workaround to fix the "We found a problem with some content in 'excelfilename'" error when opening with Office 2010 or greater by adding extra blank rows to ensure the file size is greater than 7 KB
If dt.Rows.Count < 100 Then
Dim nRowCount = dt.Rows.Count + 1
Do While nRowCount < 100
oWorksheet.Cells(nRowCount, 0) = New Cell(" ")
nRowCount += 1
Loop
End If
oWorkbook.Worksheets.Add(oWorksheet)
oWorkbook.Save(sFilename)
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
As you can see there are many solutions to this problem. Please let us know which one worked for you!
Edit 2:
Well I had some more time and I found some better and FREE dlls to create xls/xlsx files with which are very much worth mentioning:
7) ClosedXML is a free, open source solution that can be used to create xlsx files from .Net code with much less hassle than ExcelLibrary. It only allows creation of the newer xlsx files so Excel 2007 or greater is required to open but it doesn't require Excel to be installed for it to create files. This one was really simple to use and the only real downside I found was that you need to also reference the DocumentFormat.OpenXml.dll (also free and open source) along with the ClosedXML dll. More information here: http://closedxml.codeplex.com/
Imports ClosedXML.Excel
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Closed XML to create an xlsx file
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xlsx")
Dim oWorkbook As New XLWorkbook
Dim oWorksheet = oWorkbook.Worksheets.Add("Sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cell(1, c + 1).Value = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cell(r + 2, c + 1).Value = dt.Rows(r).Item(c) ' Write the data to the correct column
Next
Next
oWorksheet.Columns.AdjustToContents() ' Automatically adjust the width of all columns to fit the data
oWorkbook.SaveAs(sFilename)
oWorkbook.Dispose()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
8) NPOI is another free open source dll that is a tad bit more complicated than ClosedXML but it supports read/write of xls, xlsx and word + powerpoint files too (not that you need those last ones). It also requires two dlls to be referenced and doesn't require excel to be installed to generate files. More information here: http://npoi.codeplex.com/
Imports NPOI.SS.UserModel
Imports NPOI.XSSF.UserModel
Imports NPOI.HSSF.UserModel
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use NPOI to create an xls/xlsx file
Dim bIsXLSX As Boolean = True ' If this is true then an xlsx file is created, if false then the older xls file is used (use xls only if you need to support office 2003 and below)
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls" & If(bIsXLSX = True, "x", ""))
Dim oWorkbook As IWorkbook
' Define workbook differently for xls and xlsx files
If bIsXLSX = True Then
oWorkbook = New XSSFWorkbook()
Else
oWorkbook = New HSSFWorkbook()
End If
Dim oWorksheet As ISheet = oWorkbook.CreateSheet("Sheet1")
Dim oRow As IRow
' Write headers
oRow = oWorksheet.CreateRow(0)
For c As Int32 = 0 To dt.Columns.Count - 1
oRow.CreateCell(c).SetCellValue(dt.Columns(c).ColumnName)
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
oRow = oWorksheet.CreateRow(r + 1)
For c As Int32 = 0 To dt.Columns.Count - 1
oRow.CreateCell(c).SetCellValue(dt.Rows(r).Item(c).ToString) ' Write the data to the correct column
Next
Next
' Automatically adjust the width of all columns to fit the data
For i As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.AutoSizeColumn(i)
Next
Dim sw As IO.FileStream = IO.File.Create(sFilename)
oWorkbook.Write(sw)
sw.Close()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
9) Last but not least is EPPlus which again is free and open source. It only uses one dll and only works with xlsx files. Again, very simple to use. More information here: http://epplus.codeplex.com/
Imports OfficeOpenXml
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use EPPlus to create an xlsx file
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xlsx")
Dim oPackage As New ExcelPackage()
Dim oWorksheet As ExcelWorksheet = oPackage.Workbook.Worksheets.Add("Sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(1, c + 1).Value = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(r + 2, c + 1).Value = dt.Rows(r).Item(c).ToString ' Write the data to the correct column
Next
Next
oWorksheet.Cells(oWorksheet.Dimension.Address).AutoFitColumns() ' Automatically adjust the width of all columns to fit the data
oPackage.SaveAs(New IO.FileInfo(sFilename))
oPackage.Dispose()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
Well that's it, I'm not adding more. Here are 9+ ways that you can accomplish what you are looking for using a variety of methods and complete with code examples. Believe it or not there are more ways to do this still but for sure one of these methods will get you to where you need to go. Happy coding!

Related

exclude header from csv in vb.net

I got a .csv and I want to load it into a datagridview. I have a button called button1 and I got a datagridview called datagridview1. I click the button and it appears... including the header, which I don't want.
Please:
How do I exclude the header from the .csv ?
code:
Imports System.IO
Imports System.Text
Public Class CSV_Reader
Private Sub CSV_Reader_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim filename As String = "C:\Users\Gaius\Desktop\meepmoop.csv"
Dim thereader As New StreamReader(filename, Encoding.Default)
Dim colsexpected As Integer = 7
Dim sline As String = ""
DataGridView1.Rows.Clear()
Do
sline = thereader.ReadLine
If sline Is Nothing Then Exit Do
Dim words() As String = sline.Split(";")
DataGridView1.Rows.Add("")
If words.Length = colsexpected Then
For ix As Integer = 0 To 6
DataGridView1.Rows(DataGridView1.Rows.Count - 2).Cells(ix).Value = words(ix)
Next
Else
DataGridView1.Rows(DataGridView1.Rows.Count - 2).Cells(0).Value = "ERROR"
End If
Loop
thereader.Close()
End Sub
End Class
meepmoop.csv:
alpha;bravo;charlie;delta;echo;foxtrot;golf
1;meep;moop;meep;moop;meep;moop
2;moop;meep;moop;meep;moop;meep
3;meep;moop;meep;moop;meep;moop
4;moop;meep;moop;meep;moop;meep
5;meep;moop;meep;moop;meep;moop
6;moop;meep;moop;meep;moop;meep
7;meep;moop;meep;moop;meep;moop
8;moop;meep;moop;meep;moop;meep
9;meep;moop;meep;moop;meep;moop
10;moop;meep;moop;meep;moop;meep
edit:
[...]
Dim sline As String = ""
DataGridView1.Rows.Clear()
Dim line As String = thereader.ReadLine()
If line Is Nothing Then Return
Do
sline = thereader.ReadLine
[...]
The above addition to the code works but I have no idea why. Nor do I understand why I have to -2 rather than -1. I can't rely on guesswork, I'm expected to one day do this professionally. But I just can't wrap my head around it. Explanation welcome.
edit:
Do
sline = thereader.ReadLine
If sline Is Nothing Then Exit Do
Dim words() As String = sline.Split(";")
If words.Count = 7 Then
DataGridView1.Rows.Add(words(0), words(1), words(2), words(3), words(4), words(5), words(6))
Else
MsgBox("ERROR - There are " & words.Count & " columns in this row and there must be 7!")
End If
Loop
I've shortened the Loop on the advice of a coworker, taking his word on it being 'better this way'.
Another method, using Enumerable.Select() + .Skip()
As noted in Ondřej answer, there's a specific tool for these operations: TextFieldParser
But, if there are no special requirements and the string parsing is straightforward enough, it can be done with the standard tools, as shown in Tim Schmelter answer.
This method enumerates the string arrays returned by the Split() method, and groups them in a list that can be then used in different ways. As a raw text source (as in this case) or as a DataSource.
Dim FileName As String = "C:\Users\Gaius\Desktop\meepmoop.csv"
Dim Delimiter As Char = ";"c
Dim ColsExpected As Integer = 7
If Not File.Exists(FileName) Then Return
Dim Lines As String() = File.ReadAllLines(FileName, Encoding.Default)
Dim StringColumns As List(Of String()) =
Lines.Select(Function(line) Split(line, Delimiter, ColsExpected, CompareMethod.Text)).
Skip(1).ToList()
DataGridView1.Rows.Clear()
'If the DataGridView is empty, add a `[ColsExpected]` number of `Columns`:
DataGridView1.Columns.AddRange(Enumerable.Range(0, ColsExpected).
Select(Function(col) New DataGridViewTextBoxColumn()).ToArray())
StringColumns.Select(Function(row) DataGridView1.Rows.Add(row)).ToList()
If you instead want to include and use the Header because your DataGridView is empty (it has no predefined Columns), you could use the Header line in the .csv file to create the control's Columns:
'Include the header (no .Skip())
Dim StringColumns As List(Of String()) =
Lines.Select(Function(line) Split(line, Delimiter, ColsExpected, CompareMethod.Text)).ToList()
'Insert the columns with the .csv header columns description
DataGridView1.Columns.AddRange(Enumerable.Range(0, ColsExpected).
Select(Function(col, idx) New DataGridViewTextBoxColumn() With {
.HeaderText = StringColumns(0)(idx)
}).ToArray())
'Remove the header line...
StringColumns.RemoveAt(0)
StringColumns.Select(Function(row) DataGridView1.Rows.Add(row)).ToList()
You can skip the header by calling ReadLine twice. Also use the Using-statement:
Using thereader As New StreamReader(filename, Encoding.Default)
Dim colsexpected As Integer = 7
Dim sline As String = ""
Dim line As String = thereader.ReadLine() ' header
if line is Nothing Then Return
Do
sline = thereader.ReadLine()
If sline Is Nothing Then Exit Do
Dim words() As String = sline.Split(";"c)
' ... '
Loop
End Using
You should use VB.NET class that is designed and tested for this purpose. It is Microsoft.VisualBasic.FileIO.TextFieldParser and you can skip header by calling ReadFields() once before you start parsing in loop.

Creating multiple .txt files while restricting size of each

In my program, I collect bits of information on a massive scale, hundreds of thousands to millions of lines each. I am trying to limit each file I create to a certain size in order to be able to quickly open it and read the data. I am using a HashSet to collect all the data without duplicates.
Here's my code so far:
Dim Founds As HashSet(Of String)
Dim filename As String = (Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\Sorted_byKING\sorted" + Label4.Text + ".txt")
Using writer As New System.IO.StreamWriter(filename)
For Each line As String In Founds
writer.WriteLine(line)
Next
Label4.Text = Label4.Text + 1 'Increments sorted1.txt, sorted2.txt etc
End Using
So, my question is:
How do I go about saving, let's say 250,000 lines in a text file before moving to another one and adding the next 250,000?
First of all, do not use Labels to simply store values. You should use variables instead, that's what variables are for.
Another advice, always use Path.Combine to concatenate paths, that way you don't have to worry about if each part of the path ends with a separator character or not.
Now, to answer your question:
If you'd like to insert the text line by line, you can use something like:
Sub SplitAndWriteLineByLine()
Dim Founds As HashSet(Of String) 'Don't forget to initialize and fill your HashSet
Dim maxLinesPerFile As Integer = 250000
Dim fileNum As Integer = 0
Dim counter As Integer = 0
Dim filename As String = String.Empty
Dim writer As IO.StreamWriter = Nothing
For Each line As String In Founds
If counter Mod maxLinesPerFile = 0 Then
fileNum += 1
filename = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
$"Sorted_byKING\sorted{fileNum.ToString}.txt")
If writer IsNot Nothing Then writer.Close()
writer = New IO.StreamWriter(filename)
End If
writer.WriteLine(line)
counter += 1
Next
writer.Dispose()
End Sub
However, if you will be inserting the text from the HashSet as is, you probably don't need to write line by line, instead you can write each "bunch" of lines at once. You could use something like the following:
Sub SplitAndWriteAll()
Dim Founds As HashSet(Of String) 'Don't forget to initialize and fill your HashSet
Dim maxLinesPerFile As Integer = 250000
Dim fileNum As Integer = 0
Dim filename As String = String.Empty
For i = 0 To Founds.Count - 1 Step maxLinesPerFile
fileNum += 1
filename = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
$"Sorted_byKING\sorted{fileNum.ToString}.txt")
IO.File.WriteAllLines(filename, Founds.Skip(i).Take(maxLinesPerFile))
Next
End Sub

VB 2010 compare string within directory and store latest revision letter of the file name

My application currently extracts data from an excel document, putting the data into a listview. I then am able to open each of the strings/items within the listview (which are pdf files in a given directory). However the pdf files within the given directory have revision letters at the end of their file names, starting with 'A' for the first revision and 'B' for the second revision...and so on.
So I am trying to approach it like comparing the string to the files in the directory and then once it's found, check what the latest rev letter is if any.
So if there is 07010302A.pdf file in the directory and there's also a 07010302B.pdf in the directory, I want to store that file name (07010302B.pdf) to a new string in my vb application. Any help on this would be much appreciated.
Here's what I am working with:
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim range As Excel.Range
Dim rCnt As Integer
Dim cCnt As Integer
Dim Obj As Object
xlApp = New Excel.Application
xlWorkBook = xlApp.Workbooks.Open("C:\Users\Admin\Desktop\Exp_Master.xlsm")
xlWorkSheet = xlWorkBook.Worksheets("Sheet1")
range = xlWorkSheet.Range("H1:H100") 'xlWorkSheet.UsedRange
For rCnt = 1 To range.Rows.Count
For cCnt = 1 To range.Columns.Count
Obj = CType(range.Cells(rCnt, cCnt), Excel.Range)
If IsNumeric(CType(range.Cells(rCnt, cCnt), Excel.Range).Value) Then
'MsgBox(Obj.value)
ListView1.Items.Add(Obj.value)
ListView1.View = View.List
End If
Next
Next
xlWorkBook.Close()
xlApp.Quit()
releaseObject(xlApp)
releaseObject(xlWorkBook)
releaseObject(xlWorkSheet)
'Kill Excel Process that wouldn't close
Process.Start("C:\Users\Admin\Desktop\batch archive\EXCEL_KILLER.bat")
'MsgBox("Total Item(s) in ListView:" & ListView1.Items.Count)
Dim i As Integer = 0
Dim n As Integer = 0
Dim str As String
For i = 1 To (ListView1.Items.Count)
Dim strng As String = "R:\"
n = (i - 1)
str = strng & (ListView1.Items.Item(n).Text) & (".pdf")
MsgBox(str)
'----
'System.Diagnostics.Process.Start(str)
'Here I want to check the R:\ directory and compare it with each string to see
'what the latest revision letter of the filename is and store it in another string to add to
'a pdf merging list later in this for loop
'----
Next
End Sub
Private Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
End Class
I was able to use your Directory.getfiles suggestion and I added a for loop to display only the last of the files labeled within that criteria. Thanks a bunch, just took a little more playing with it to determine what I actually wanted and how to put it in code.
If anyone cares, here is the update that works and gets the last file name and path of the directory.getfiles group within a search criteria.
Cheers!
For i = 1 To (ListView1.Items.Count)
Dim strng As String = "R:\"
n = (i - 1)
str = strng & (ListView1.Items.Item(n).Text) & (".pdf")
'MsgBox(str)
Dim substr As String
substr = str.Substring(3, 8)
'MsgBox(substr)
'----
'System.Diagnostics.Process.Start(str)
' Only get files that begin with...
Dim dirs As String() = Directory.GetFiles("R:\", (substr & ("*.pdf")))
'MsgBox("The number of files starting with your string is {0}.", dirs.Length)
Dim dir As String
For Each dir In dirs
If dir Is dirs.Last Then
MsgBox(dir)
'do something with your last item'
End If
Next
'----
Next
End Sub

Parse Log File - Reading from the end first

Having some trouble with a log file I need to parse and display certain fields in a data grid view. The log file is a large tab delimited file and I can read it and parse the array easily. The issue is that I want to start at the END of the file and read backwards until I hit a certain value in one of the fields. Then I want to start reading forward again until it hits the end of the file. While it's reading to the end I want it to fill the data grid view with certain fields. Here's what I have so far -
Looking at the code - it needs to read from the end until the 4th field equals zero and then start reading forward again. I can also read from the end, saving the values to the data grid view as I go until I hit that 0 if that's easier.
Thanks for the help!
The other option would be to read the file and save it in reverse, line by line - the last line first, the 2nd to last line 2nd, etc. That would be really nice as I have another function that will need to read the file and it also needs to go from the end to the beginning.
Private Sub btnParseLog_Click(sender As Object, e As EventArgs) Handles btnParseLog.Click
Dim FileLocation As String = "BLAHBLAHBLAH"
Dim LogFile As String = "LOGFILE"
DataGridView1.ColumnCount = 3
DataGridView1.ColumnHeadersVisible = True
' Set the column header style.
Dim columnHeaderStyle As New DataGridViewCellStyle()
columnHeaderStyle.BackColor = Color.Beige
columnHeaderStyle.Font = New Font("Verdana", 10, FontStyle.Bold)
DataGridView1.ColumnHeadersDefaultCellStyle = columnHeaderStyle
DataGridView1.Columns(0).Name = "User"
DataGridView1.Columns(1).Name = "Number"
DataGridView1.Columns(2).Name = "Time"
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(LogFile)
MyReader.TextFieldType =
Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {vbTab}
Dim TotalLineCount As Integer = File.ReadAllLines(LogFile).Length
Dim currentRow As String()
Dim RowCount As Integer = 0
'Loop through all of the fields in the file.
'If any lines are corrupt, report an error and continue parsing.
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
RowCount = RowCount + 1
' Include code here to handle the row.
If RowCount = TotalLineCount Then
While Not currentRow(4).ToString = 0
DataGridView1.Rows.Add(currentRow(1).ToString, currentRow(4).ToString, currentRow(7).ToString)
RowCount = RowCount - 1
End While
End If
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
" is invalid. Skipping")
End Try
End While
End Using
End Sub

Adding records (Row/ Column) to DataGridView; Collection already belongs to a DataGridView control VB.NET

I'm looking for some help with an issue I am having.
I have multiple text files, in a folder. The folder can have an "unlimited" amount of text files in it, although typically 2-150 files
http://gyazo.com/5f314d1ca374abf9f813914609dd931d (images for this + below, can't embed due to lack of reputation)
Each file then contains an "unlimited" (although typically 0-20 lines) amount of data inside it. Line 1 being the "test number" and line 2 being the "test result" - as seen in the image above
My Data Grid View has 3 columns in it (Username, test number, test result) - as seen in the image above
When running my code below; first record being added to the Data Grid View works perfectly, but the second (or any record after the first) the error occurs:
http://gyazo.com/0d492b97d918853e62c55ee314f3f181 (image) or error message:
"System.InvalidOperationException: Collection already belongs to a
DataGridView control. This operation is no longer valid. at
System.Windows.Forms.DataGridViewCellCollection.Add(DataGridViewCelldataGridViewCell)
at SpellingBee.TeacherMultiResults.TeacherMultiResults_Load(Object
sender, EventArgs e)"
This error occurs on the DGVRow.Cells.Add(DGVCell) 'add cell to row
One thing I don't want to do is change any of my text file/ folder structures, even though I'm aware that it is currently inefficient storage.
How can I fix this error? I'm using VB.net (Visual Studios 2013)
If you need any more information, please just ask
Many thanks.
Imports System.Windows.Forms
Imports System.IO
Public Class TeacherMultiResults
Dim AmountOfFiles
Dim LineCount As Integer = 0
Dim FileName As IO.FileInfo
Dim DGVRow As New DataGridViewRow
Dim DGVCell As DataGridViewCell
Dim Username As String = ""
Dim TestNumber As Integer = 0
Dim TestResult As Integer = 0
Private Sub TeacherMultiResults_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim directory As New IO.DirectoryInfo(LoadForm.CurrentDirectory & "\UserResults\") 'selects directory
Dim FileNames As IO.FileInfo() = directory.GetFiles()
Dim Files As IO.FileInfo
For Each Files In FileNames 'list the names of all files in the specified directory
Username = Files.ToString
Username = (Username.Substring(0, Username.Length - 4)) 'removes the .txt from the name
Try
LineCount = File.ReadAllLines(LoadForm.CurrentDirectory & "\UserResults\" & Username & ".txt").Length 'amount of lines in file
If LineCount > 1 Then
Dim Information As New System.IO.StreamReader(LoadForm.CurrentDirectory & "\UserResults\" & Username & ".txt") 'opens file
LineCount = LineCount / 2 'halfs line count
For i = 0 To LineCount - 1
TestNumber = Information.ReadLine() 'reads line to variable
TestResult = Information.ReadLine() 'reads line to variable
i = i + 1 'adds one to i
DGVCell = New DataGridViewTextBoxCell 'create a new DGV text box cell
DGVCell.Value = Username 'add value to DGV text box cell
DGVRow.Cells.Add(DGVCell) 'add cell to row
DGVCell = New DataGridViewTextBoxCell 'create a new DGV text box cell
DGVCell.Value = TestNumber 'add value to DGV text box cell
DGVRow.Cells.Add(DGVCell) 'add cell to row
DGVCell = New DataGridViewTextBoxCell 'create a new DGV text box cell
DGVCell.Value = TestResult 'add value to DGV text box cell
DGVRow.Cells.Add(DGVCell) 'add cell to row
DGV_MultiResults.Rows.Add(DGVRow) 'add row to DGV
Next
Information.Close() 'Close read
End If
Catch ex As Exception 'if file won't read
MsgBox(ex.ToString) 'show error
Exit Try
End Try 'end of try
Next 'end of files
End Sub
I hope that somebody can help me with this issue, I understand it's fairly simple to fix most probably although I can't seem to find a solution to the error!
Many thanks, Toby.
When working with a DataGridView, it is generally easier to just build an object list and then bind it to the DGV using the built-in data binding features.
For your example, it would look like this:
' Read the files, build objects as you go and add them to a list
Dim lst = New List(Of TeacherMultiResults)
' Replace this part with your file reading code...
Dim t1 = New TeacherMultiResults With {.Username = "Bob", .TestNumber = 1, .TestResult = 75}
lst.Add(t1)
Dim t2 = New TeacherMultiResults With {.Username = "Rick", .TestNumber = 1, .TestResult = 85}
lst.Add(t2)
Dim t3 = New TeacherMultiResults With {.Username = "Zoe", .TestNumber = 1, .TestResult = 95}
lst.Add(t3)
' Bind the list to the DataGridView
Dim bindList = New BindingList(Of TeacherMultiResults)(lst)
Dim bindSrc = New BindingSource
bindSrc.DataSource = bindList
grid.DataSource = bindSrc
Your grid should display each item of your list.