我有一个带有CSV / Excel文件的Windows窗体应用程序,允许用户将它们导入SQL DB。
最近,我遇到了一个奇怪的错误,用户上传了一个CSV文件,它会截断一列中的文字。
这是源文件:
以下是我的应用中的DatagridView,在将数据转换为数据表后显示相同的数据:
请注意,某些值完全为空,并以红色突出显示,而其他值似乎被截断。 但是,这只发生在CSV文件中,而不是excel。这让我相信这可能是一个驱动问题。
以下是将平面文件数据转换为数据表的代码:
Private Function ConvertCSVToDataTable(ByVal path As String) As DataTable
Using con As OleDb.OleDbConnection = New OleDb.OleDbConnection()
Try
If System.IO.Path.GetExtension(path) = ".csv" Then
con.ConnectionString = String.Format("Provider={0};Data Source={1};Extended Properties=""Text;HDR=YES;FMT=Delimited""", "Microsoft.Jet.OLEDB.4.0", IO.Path.GetDirectoryName(path))
Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand("SELECT * FROM [" & IO.Path.GetFileName(path) & "]", con)
Using da As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter(cmd)
con.Open()
da.Fill(dt)
con.Close()
End Using
End Using
ElseIf System.IO.Path.GetExtension(path) = ".xlsx" Then
con.ConnectionString = String.Format("Provider={0};Data Source={1};Extended Properties=""Excel 12.0 Xml;HDR=Yes;IMEX=1""", "Microsoft.ACE.OLEDB.12.0", path)
con.Open()
Dim dbSchema As DataTable = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, Nothing)
Dim firstSheetname As String = dbSchema.Rows(0)("TABLE_NAME").ToString
Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand("SELECT * FROM [" & firstSheetname & "]", con)
Using da As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter(cmd)
'con.Open()
da.Fill(dt)
con.Close()
End Using
End Using
End If
Catch ex As Exception
MessageBox.Show(ex.ToString(), "Conversion Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
Finally
If con IsNot Nothing AndAlso con.State = ConnectionState.Open Then
con.Close()
End If
End Try
End Using
Return dt
End Function
有什么想法导致这个? 我还应该注意,我的一些用户只能导入CSV而不能导入Excel。我想出具有32位Access驱动程序的用户可以导入excel文件,而64位用户则无法导入。我让他们在这里下载驱动程序:
https://www.microsoft.com/en-us/download/details.aspx?id=23734
现在这些用户可以导入Excel,但是它们仍然存在被截断的字符串的问题。这让我相信它可能仍然是一个驱动问题。
测试数据:
Sales Order #
US00123
US00123
US00123
SG0000123
SG0000123
S00123
S00123
S00123
S00123
S00123
答案 0 :(得分:1)
我能够重现您的问题。
问题是由于某种原因,Jet提供程序使用的文本文件驱动程序将“S00123”解释/解析为数值。我必须使用MaxScanRows = 0和ImportMixedTypes =“Majority Type”配置注册表。
我不知道为什么会发生这种情况,但我只是将其归因于另一种使用记录不佳的技术的乐趣。似乎任何以“S”开头,后跟数字的字段都被解释为数字。
如果你坚持使用这种技术来完成一个有更好选择的任务,那么你必须忍受它的许多缺点和怪癖。
解决方案1:
配置要导入的提供程序,并将注册表值ImportMixedTypes设置为“Text”。现在,如果您进行此更改以允许您的程序工作,您还将负责打破任何其他依赖于现有配置的代码。
64位操作系统上注册表值的位置。
对于Jet Provider:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Text
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Excel
对于ACE提供商:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Office\12.0\Access Connectivity Engine\Engines\Text
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Office\12.0\Access Connectivity Engine\Engines\Excel
解决方案2:
使用[Schema.ini]文件https://docs.microsoft.com/en-us/sql/odbc/microsoft/schema-ini-file-text-file-driver)定义如何使用定义的列解释文本文件。
这是使用此技术的首选方法。请注意,文件的编码非常重要;它必须位于.Net编码System.Text.Encoding.ASCII
或System.Text.Encoding.Unicode
中。如果您使用其他编码,例如UTF-8
,则不会读取该文件,并且将使用注册表中的设置。