我想从vba-excel中读取一个csv文件,但是我有一个双精度值的问题,例如,在csv中此值:125.5读取时不带点。所以我得到1255。 我的代码:
Dim rs As New ADODB.Recordset
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & myDir & ";" & "Extended Properties=""text;HDR=Yes;FMT=Delimited()"";"
strSQL = "SELECT * FROM " & myFileName
rs.Open strSQL, strCon, 3, 3
IBH = rs("IBH")
我该如何解决?
更新: 我尝试了@Siddharth Rout解决方案,但是我仍然遇到相同的问题。 现在我的代码:
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim myDate, myTime, IBH, IBL
Dim myDir As String, myFileName As String
Dim strSQL As String
myDir = Trim(shParams.Range("fp_path"))
myFileName = Trim(shParams.Range("fp_filename"))
With conn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=" & myDir & ";Extended Properties='text'"
.Open
End With
strSQL = "SELECT * FROM " & myFileName
rs.Open strSQL, conn, 3, 3
rs.MoveLast
myDate = rs("Date")
myTime = rs("Time")
IBH = rs("IBH")
IBL = rs("IBL")
Debug.Print myDate, myTime, IBH, IBL
rs.Close
Set rs = Nothing
这是结果:
答案 0 :(得分:2)
此问题源于ACE
引擎如何确定ADODB
字段的类型。驱动程序将扫描一定数量的行,以确定整个列的类型。
更改连接字符串
您可以尝试做的一件事是将连接字符串中的MaxScanRows
更改为0。将该值设置为0将扫描所有行以确定类型,请记住,这可能会对性能产生影响,具体取决于数据集的大小。
";Extended Properties='text;MaxScanRows=0;IMEX=0'"
这并不总是能给您想要的结果。假设我们有一个这样的数据集:
+--------------------------+
| DoubleField |
+--------------------------+
| 1 |
| 2 |
| 3 |
| ...(996 more records...) |
| 1000.01 |
+--------------------------+
驱动程序将查看并看到999个看起来像整数的记录和1个看起来像一个Double的记录。它将基于MajorityType
决定此字段是整数,而不是双精度数。坦白地说,我不确定该类型确定是如何准确完成的,但这确实符合这些原则。我还看到过一些实例,只需将顶部记录更改为所需的类型即可。例如
+--------------------------+
| DoubleField |
+--------------------------+
| 1.00 |
| 2 |
| 3 |
| ...(996 more records...) |
| 1000.01 |
+--------------------------+
因此,另一种方法可能是格式化源文件,使其预先包含小数位。如果您控制源文件,这应该很容易做到,但这并非总是如此。
使用架构INI文件
如果无法提高MaxScanRows
,请确保使用 Commintern 所指出的Schema.ini文件来获得期望的每一列类型。
这里是link的内容。
要点是,制作一个文件,为每个列显式定义每种类型。对于我们上面设计的表格,它变为:
[MyFileNameGoesHere.csv]
ColNameHeader = True
Format = CSVDelimited
Col1=DoubleField Double
然后,您将此文件另存为Schema.Ini
,并将其放置在与要导入的文件相同的目录中。这种方法的好处在于,它只是创建一个文本文件,您甚至可以在VBA中完成此操作而不会遇到太多麻烦。这种方法的缺点是,如果要导入很多文件,则很难管理所有Schema.ini文件。
纯粹的VBA方法
您可以在ADODB
中创建一个内存中表,并使用csv文件中的数据填充该表。这是一个小代码示例,可以帮助您入门。
Option Explicit
Private Function getTypedRS() As ADODB.Recordset
Set getTypedRS = New ADODB.Recordset
With getTypedRS
'Add your other fields here
.Fields.Append "DoubleField", adDouble
End With
End Function
Public Sub CSVToADODB()
Dim myTimer As Double
Dim FileNumber As Long
Dim FilePath As String
Dim FileData As String
Dim CSVArray As Variant
Dim i As Long
Dim rs As ADODB.Recordset
myTimer = Timer
Set rs = getTypedRS()
FilePath = "C:\Users\Ryan\Desktop\Example.csv"
'Get the CSV
FileNumber = FreeFile()
Open FilePath For Binary Access Read As FileNumber
FileData = Space$(LOF(FileNumber)) 'Create a buffer first, then assign
Get FileNumber, , FileData
Close FileNumber
'My CSV is just a list of Doubles, should be relatively easy to swap out to process with ','
CSVArray = Split(FileData, vbCrLf)
'Add data
rs.Open
For i = LBound(CSVArray) + 1 To UBound(CSVArray) '+1 to skip header
rs.AddNew
rs.Fields("DoubleField").Value = CSVArray(i)
Next
rs.UpdateBatch
rs.MoveLast
Debug.Print rs.Fields("DoubleField").Value, "Processed 1000 records in: " & Timer - myTimer
End Sub
这种方法的优点在于它仍然相当快。我能够在约0.03秒内加载1000个双音,因为此处完成的大多数操作都是在内存中完成的。这也避免了对Schema.ini文件的需要,但是需要维护更多代码,因此这是一个折衷方案。
推荐
我会尝试更改MaxScanRows
,如果不起作用,请创建Schema.ini文件。
答案 1 :(得分:0)
尝试一下
Sub Sample()
Dim conn As New ADODB.Connection
Dim RS As New ADODB.Recordset
Dim FilePath As String, SheetName As String
'~~> Replace this with relevant values
FilePath = "C:\Users\routs\Desktop"
Filename = "Sample.Csv"
With conn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=" & FilePath & ";Extended Properties='text'"
.Open
End With
strSQL = "select * from " & Filename
RS.Open strSQL, conn
'~~> Replace this with relevant field
Debug.Print RS("Sale")
End Sub