Leer un CSV
Se puede leer desde Visual Basic un archivo con formato separado por comas CSV, para que esto sea posible, el formato que debe cumplir un CSV debe cumplir estos requisitos:
Sea un fichero de texto plano cualquiera, eliminamos las cabeceras (suele ser la primera fila), y renombramos el fichero como .csv
Si ahora lo abrimos (debemos tener en nuestro equipo un programa capaz de leer archivos .csv como LibreOffice por ejemplo).
Al intentar abrirlo nos muestra esta pantalla.
Elegimos el conjunto de caracteres unicode (UTF-8) para que no trunque las palabras acentuadas.
Coma y punto y coma , delimitador de cadena ? |
En algunos caso pueden venir caracteres ocultos que producirán errores, como por ejemplo los retornos de carro LF, para quitar estos retornos de carro LF abrimos el CSV con notepad ++ y hacemos lo siguiente:
Ctrl+F
Vamos a la pestaña "Replace"
En "Find What" ponemos: ([^\r])\n
En "Replace with" ponemos: \1
Elegimos "Regular expression" en "Search Mode"
Y pulsamos el botón Replace All
Dados estos pasos previos, creamos un procedimiento de este estilo para cargar el .csv en un dataGridView de Visual Basic.
Private Sub txtLeeCSV_Click(sender As Object, e As EventArgs) Handles txtLeeCSV.Click
Try
OpenFileDialog1.Filter = "CSV
files(*.csv)|*.csv"
If OpenFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
Dim sr As System.IO.StreamReader = New System.IO.StreamReader(OpenFileDialog1.FileName)
sr.Close()
ImportarCSV(grdDatosCSV, ";")
End If
txtCargaBBDD.Enabled = True
txtLeeCSV.Enabled = False
Catch ex As Exception
MessageBox.Show(ex.Message, "ERROR")
End Try
End Sub
Sub ImportarCSV(ByVal TABLA As DataGridView, ByVal DELIMITADOR As String)
Dim fName As String = ""
fName = OpenFileDialog1.FileName
Dim TextLine As String = ""
Dim TextAux As String = ""
Dim SplitLine() As String
Dim NombreColumna As String = ""
Dim CortaEn As Integer
Dim EsCabecera As Boolean = True
grdDatosBBDD.Visible = False
grdDatosCSV.Visible = True
If System.IO.File.Exists(fName) = True Then
Dim objReader As New System.IO.StreamReader(OpenFileDialog1.FileName, Encoding.UTF8)
Do While objReader.Peek() <> -1
TextLine = objReader.ReadLine()
'Aqui
detecta la primera linea para introducir los nombres de las columnas
If EsCabecera Then
TextAux = TextLine
CortaEn = InStr(TextAux, ";")
Do While CortaEn <> 0
NombreColumna
= Mid(TextAux, 1, CortaEn - 1)
grdDatosCSV.Columns.Add(NombreColumna, NombreColumna)
TextAux =
Mid(TextAux, CortaEn + 1)
CortaEn =
InStr(TextAux, ";")
Loop
'Para la última columna
grdDatosCSV.Columns.Add(TextAux, TextAux)
EsCabecera = False
Else
SplitLine = Split(TextLine,
";")
Me.grdDatosCSV.Rows.Add(SplitLine)
End If
Loop
Else
MsgBox("Fichero no existe")
End If
End Sub
Cargar el DataGridView en la Base de Datos
Con el DataGridView cargado podemos pasar los datos del grid a una base de datos Oracle fácilmente del siguiente modo:
Private Sub txtCargaBBDD_Click(sender As Object, e As EventArgs) Handles txtCargaBBDD.Click
txtCargaBBDD.Enabled
= False
TipoAccion = Accion.Alta
grdDatosCSV.Enabled = False
drEdit = bs.AddNew()
bs.MoveLast()
grdDatosBBDD.Refresh()
Dim i As Integer = 0
'Usamos
un ciclo For Each para recorrer nuestro DataGridView
Dim dt As DataTable = TryCast(bs.DataSource, DataTable)
Try
For Each Row As DataGridViewRow In grdDatosCSV.Rows
'Antes
de insertar hay que pasar los datos de un grid a otro linea por line
ObtenerValoresFila(Row, dt)
i = i + 1
Next
bs.DataSource = dt
dA.Update(bs.DataSource)
grdDatosBBDD.Refresh()
bolRefrescar = False
grdDatosCSV.Refresh()
grdDatosBBDD.Refresh()
MsgBox((grdDatosCSV.RowCount - 1) & "
Registros exportados exitosamente", MsgBoxStyle.Information, "PowerCSV")
grdDatosBBDD.Visible = True
grdDatosCSV.Visible = False
txtLeeCSV.Enabled = False
txtCargaBBDD.Enabled = True
Catch ex As Exception
MsgBox("No se pueden guardar los registros por: " &
ex.Message, MsgBoxStyle.Critical, "PowerCSV")
MsgBox(" algunos registros exportados exitosamente, revise el resto", MsgBoxStyle.Information, "PowerCSV")
End Try
End Sub
Sub ObtenerValoresFila(ByVal fila As DataGridViewRow, dt As DataTable)
Try
'Rellenar el contenido con el valor de las celdas de la fila
If dt IsNot Nothing Then
Dim Linea As DataRow = dt.NewRow()
Linea("CAMPO1") = fila.Cells(0).Value
Linea("CAMPO2") = fila.Cells(1).Value
Linea("CAMPO3") = fila.Cells(2).Value
Linea("CAMPO4") = fila.Cells(3).Value
If IsDate(fila.Cells(15).Value) Then
Linea("FEC_LAST_MOD") = fila.Cells(4).Value
Else
Linea("FEC_LAST_MOD") = DBNull.Value
End If
Linea("CAMPO6") = fila.Cells(5).Value
dt.Rows.Add(Linea)
End If
Catch ex As Exception
If Mid(ex.Message, 1, 9) = "ORA-00001" Then
MsgBox("Hay al menos un código duplicado, revise los datos e inténtelo de
nuevo", MsgBoxStyle.Critical, "Error en la inserción masiva de datos")
End If
bolRefrescar = True
End Try
End Sub
Algunas veces se pueden cargar caracteres extraños en el DataGridView que darán problemas a la hora de insertarlos en la BBDD, hay un carácter ASCII especial que no se aprecia en muchos formatos de documentos y en CSV se muestra como una raya vertical gris que apenas se ve, para eliminarlo podemos utilizar esta función
'esta
funcion limpia el caracter ASCII Nº 63 que no se puede detectar de ninguna otra
forma y da error si no se elimina
Private Function LimpiaCadena(ByVal cadena As String) As String
Dim sText As String
Dim i As Integer
Dim lenText As Integer
Dim sASC As String
Dim sLimpio As String
Dim sCaracter As String
Dim Valor
As Integer
sText = cadena
lenText = Len(sText)
'convierte la cadena de texto en una cadena ASCII separada por comas
For i = 1 To lenText
sASC = sASC & "," & CStr(Asc(Mid$(sText, i, 1)))
Next i
sASC = Mid(sASC, 2)
lenText =
Len(sASC)
'Convierte la cadena ASCII en texto buscando el valor 63 y lo sustituye por
un nulo
For i = 1 To lenText
Valor = InStr(sASC, ",")
If Valor <= 0 Then
sLimpio = sLimpio &
Chr(sASC)
Exit For
End If
sCaracter = Mid(sASC, 1, Valor - 1)
If sCaracter = "63" Then
sCaracter = "00"
End If
sLimpio = sLimpio
& Chr(sCaracter)
sASC = Mid(sASC, Valor +
1)
Next i
Return sLimpio
End Function
Programa completo
El programa completo tira de un formulario con dos DataGridView, una para BBDD y otra para el .csv, se van haciendo visibles e invisibles alternativamente para que parezca una sola grid. Además tiene un botón de importar .csv y otro de cargar en BBDD.
Imports System.Data.OleDb
Imports System.Windows.Forms
Imports System.Text
Imports System.IO
Public Class frmCargaCSV
Dim ds As New DataSet()
Dim bs As BindingSource = New BindingSource()
Dim dA As New OleDb.OleDbDataAdapter
Dim drEdit As DataRowView
Dim bolRefrescar As Boolean
Dim
bolPrimeraVez As Boolean = True
Const Tabla
= "CSV"
Enum Accion
Alta = 1
Baja = 2
Modificacion = 3
End Enum
Dim
TipoAccion As Accion
Sub
CargaCSV()
Dim srSQL As StreamReader
Dim strConsulta As String
Dim
cmdbuilder As OleDbCommandBuilder
Try
'Repeticion si no es la primera vez es que se ha llamado desde el
mantenimiento y antes de cargarse debe borrarse la grid
If Not bolPrimeraVez Then
ds.Tables("CSV").Clear()
End If
'***********************
strStartupPath = My.Application.Info.DirectoryPath
srSQL = New System.IO.StreamReader(strStartupPath & "\CargarCSV.sql")
strConsulta = srSQL.ReadToEnd
cmdPD = New OleDb.OleDbCommand(strConsulta, cnxPD)
dA.SelectCommand = cmdPD
cmdbuilder = New OleDbCommandBuilder(dA)
dA.Fill(ds, "CSV")
If Not bolPrimeraVez Then
Exit Sub
End If
bolPrimeraVez = False
dA.UpdateCommand =
cmdbuilder.GetUpdateCommand()
dA.DeleteCommand =
cmdbuilder.GetDeleteCommand()
dA.InsertCommand =
cmdbuilder.GetInsertCommand()
bs.DataSource = ds.Tables(Tabla)
Catch
MsgBox("Se ha producido un error leyendo los datos: " &
Err.Description)
End Try
End Sub
Private Sub txtLeeCSV_Click(sender As Object, e As EventArgs) Handles txtLeeCSV.Click
Try
OpenFileDialog1.Filter = "CSV
files(*.csv)|*.csv"
If OpenFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
Dim sr As System.IO.StreamReader = New System.IO.StreamReader(OpenFileDialog1.FileName)
sr.Close()
ImportarCSV(grdDatosCSV, ";")
End If
txtCargaBBDD.Enabled = True
txtLeeCSV.Enabled = False
Catch ex As Exception
MessageBox.Show(ex.Message, "ERROR")
End Try
End Sub
Sub ImportarCSV(ByVal TABLA As DataGridView, ByVal DELIMITADOR As String)
Dim fName As String = ""
fName = OpenFileDialog1.FileName
Dim TextLine As String = ""
Dim TextAux As String = ""
Dim SplitLine() As String
Dim NombreColumna As String = ""
Dim CortaEn As Integer
Dim EsCabecera As Boolean = True
grdDatosBBDD.Visible = False
grdDatosCSV.Visible = True
If System.IO.File.Exists(fName) = True Then
Dim objReader As New System.IO.StreamReader(OpenFileDialog1.FileName, Encoding.UTF8)
Do While objReader.Peek() <> -1
TextLine = objReader.ReadLine()
'Aqui
detecta la primera linea para introducir los nombres de las columnas
If EsCabecera Then
TextAux = TextLine
CortaEn = InStr(TextAux, ";")
Do While CortaEn <> 0
NombreColumna
= Mid(TextAux, 1, CortaEn - 1)
grdDatosCSV.Columns.Add(NombreColumna, NombreColumna)
TextAux =
Mid(TextAux, CortaEn + 1)
CortaEn =
InStr(TextAux, ";")
Loop
'Para la última columna
grdDatosCSV.Columns.Add(TextAux, TextAux)
EsCabecera = False
Else
SplitLine = Split(TextLine,
";")
Me.grdDatosCSV.Rows.Add(SplitLine)
End If
Loop
Else
MsgBox("Fichero no existe")
End If
End Sub
Private Sub txtCargaBBDD_Click(sender As Object, e As EventArgs) Handles txtCargaBBDD.Click
txtCargaBBDD.Enabled
= False
TipoAccion = Accion.Alta
grdDatosCSV.Enabled = False
drEdit = bs.AddNew()
bs.MoveLast()
grdDatosBBDD.Refresh()
Dim i As Integer = 0
'Usamos
un ciclo For Each para recorrer nuestro DataGridView
Dim dt As DataTable = TryCast(bs.DataSource, DataTable)
Try
For Each Row As DataGridViewRow In grdDatosCSV.Rows
'Me.grdDatosBBDD.Rows.Add(ObtenerValoresFila(Row)) 'esta instruccion es correcta pero da error
por que dice que está
'enlazada con un bindingSourse y no se puede editar directamente, tiene que
hacerse a traves de un datatable
'SUSUTITUYO ESTA INSTRUCCION POR LO DE ABAJO
ObtenerValoresFila(Row, dt)
i = i + 1
Next
bs.DataSource = dt
dA.Update(bs.DataSource)
grdDatosBBDD.Refresh()
bolRefrescar = False
grdDatosCSV.Refresh()
grdDatosBBDD.Refresh()
MsgBox((grdDatosCSV.RowCount - 1) & "
Registros exportados exitosamente", MsgBoxStyle.Information, "PowerCSV")
grdDatosBBDD.Visible = True
grdDatosCSV.Visible = False
txtLeeCSV.Enabled = False
txtCargaBBDD.Enabled = True
Catch ex As Exception
MsgBox("No se pueden guardar los registros por: " &
ex.Message, MsgBoxStyle.Critical, "PowerCSV")
MsgBox(" algunos registros exportados exitosamente, revise el resto", MsgBoxStyle.Information, "PowerCSV")
End Try
End Sub
Sub ObtenerValoresFila(ByVal fila As DataGridViewRow, dt As DataTable)
Try
'Rellenar el contenido con el valor de las celdas de la fila
If dt IsNot Nothing Then
Dim Linea As DataRow = dt.NewRow()
Linea("CAMPO1") = fila.Cells(0).Value
Linea("CAMPO2”) = fila.Cells(1).Value
Linea("CAMPO3") = LimpiaCadena(fila.Cells(2).Value)
Linea("CAMPO4") = LimpiaCadena(fila.Cells(3).Value)
If IsDate(fila.Cells(4).Value) Then
Linea("FEC_LAST_MOD") = fila.Cells(4).Value
Else
Linea("FEC_LAST_MOD") = DBNull.Value
End If
Linea("CAMPO6") = fila.Cells(16).Value
dt.Rows.Add(Linea)
End If
Catch ex As Exception
If Mid(ex.Message, 1, 9) = "ORA-00001" Then
MsgBox("Hay al menos un código duplicado, revise los datos e intentelo de
nuevo", MsgBoxStyle.Critical, "Error en la inserccion masiva de datos")
End If
bolRefrescar = True
End Try
End Sub
'esta
funcion limpia el caracter ASCII Nº 63 que no se puede detectar de ninguna otra
forma y da error si no se elimina
Private Function LimpiaCadena(ByVal cadena As String) As String
Dim sText As String
Dim i As Integer
Dim lenText As Integer
Dim sASC As String
Dim sLimpio As String
Dim sCaracter As String
Dim Valor
As Integer
sText = cadena
lenText = Len(sText)
'convierte la cadena de texto en una cadena ASCII separada por comas
For i = 1 To lenText
sASC = sASC & "," & CStr(Asc(Mid$(sText, i, 1)))
Next i
sASC = Mid(sASC, 2)
lenText =
Len(sASC)
'Convierte la cadena ASCII en texto buscando el valor 63 y lo sustituye por
un nulo
For i = 1 To lenText
Valor = InStr(sASC, ",")
If Valor <= 0 Then
sLimpio = sLimpio &
Chr(sASC)
Exit For
End If
sCaracter = Mid(sASC, 1, Valor - 1)
If sCaracter = "63" Then
sCaracter = "00"
End If
sLimpio = sLimpio
& Chr(sCaracter)
sASC = Mid(sASC, Valor +
1)
Next i
Return sLimpio
End Function
Private Sub frmCVS_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.grdDatosBBDD.DataSource = bs
grdDatosBBDD.Visible = True
grdDatosCSV.Visible
= False
CargaCSV()
End Sub
End Class
CSV.sql
SELECT CAMPO1,
CAMPO2,
CAMPO3,
CAMPO4,
FEC_LAST_MOD,
CAMPO6
FROM PROPIETARIO.TABLA
No hay comentarios:
Publicar un comentario