vb.net xls 到 csv 带引号?
Posted
技术标签:
【中文标题】vb.net xls 到 csv 带引号?【英文标题】:vb.net xls to csv with quotes? 【发布时间】:2011-03-09 18:50:27 【问题描述】:我有一个 xls 文件,或一个不带引号的 csv,使用 vb.net 需要将其转换为每个单元格周围都有引号的 csv。如果我在 MS Access 中打开不带引号的 xls/csv,请将每一列设置为文本,然后将其导出为我需要的格式。有没有更简单的方法?如果没有,我如何在 vb.net 中复制它?谢谢。
【问题讨论】:
你能举一个数据的例子吗? "1","2","3","4" 是我需要的,而不是 1,2,3,4。 【参考方案1】:如果您使用.Net OLE DB provider,您可以在您的数据文件所在文件夹中的 schema.ini 文件中指定 .csv 格式的详细信息。对于“未引用”的 .csv,请参阅规范 应该是这样的
[noquotes.csv] <-- file name
ColNameHeader=True <-- or False
CharacterSet=1252 <-- your encoding
Format=Delimited(,) <--
TextDelimiter= <-- important: no " in source file
Col1=VendorID Integer <-- your columns, of course
Col2=AccountNumber Char Width 15
对于“引用”的 .csv,只需更改名称并删除 TextDelimiter= 行(在文本字段周围加上引号是默认设置)。
然后连接到文本数据库并执行语句
SELECT * INTO [quotes.csv] FROM [noquotes.csv]
(因为这会创建quotes.csv,您可能希望在每次实验运行之前删除该文件)
新增处理“必须引用空字段”
这是一个 VBScript 演示,但重要的是 .GetString() 的参数,您可以轻松地将其移植到 VB:
Dim sDir : sDir = resolvePath( "§LibDir§testdata\txt" )
Dim sSrc : sSrc = "noquotes.csv"
Dim sSQL : sSQL = "SELECT * FROM [" & sSrc & "]"
Dim oTxtDb : Set oTxtDb = New cADBC.openDb( Array( "jettxt", sDir ) )
WScript.Echo goFS.OpenTextFile( goFS.BuildPath( sDir, sSrc ) ).ReadAll()
Dim sAll : sAll = oTxtDb.GetSelectFRO( sSQL ).GetString( _
adClipString, , """,""", """" & vbCrlf & """", "" _
)
WScript.Echo """" & Left( sAll, Len( sAll ) - 1 )
和输出:
VendorID;AccountNumber;SomethingElse
1;ABC 123 QQQ;1,2
2;IJK 654 ZZZ;2,3
3;;3,4
"1","ABC 123 QQQ","1,2"
"2","IJK 654 ZZZ","2,3"
"3","","3,4"
(德语区域设置,因此字段分隔符;和十进制符号,)
此 VB.Net 代码的相同输出:
Imports ADODB
...
Sub useGetString()
Console.WriteLine("useGetString")
Const adClipString As Integer = 2
Dim cn As New ADODB.Connection
Dim rs As ADODB.Recordset
Dim sAll As String
cn.ConnectionString = _
"Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=M:\lib\kurs0705\testdata\txt\;" _
& "Extended Properties=""text;"""
cn.Open()
rs = cn.Execute("SELECT * FROM [noquotes.csv]")
sAll = rs.GetString( adClipString, , """,""", """" & vbCrLf & """", "" )
cn.Close()
sAll = """" & Left( sAll, Len( sAll ) - 1 )
Console.WriteLine( sAll )
End Sub
【讨论】:
这听起来很棒,我会试试看。 是否可以在不指定每一列的情况下执行此操作?我想让它更通用,以便它能够转换任何 csv 文件。 如果您不指定列,驱动程序将猜测您想要(不)引用的类型和可能(不)引用字段。如果这是个问题,您可以在执行“SELECT INTO”语句之前以编程方式编辑 schema.ini 文件。 我不这么认为;我发现像“空字段可能用引号括起来”这样的语句,我的驱动程序没有这样做,而且我不记得为此目的的 schema.ini 属性。但这肯定不是结论性的。如果这对您的项目来说是致命的,并且您想引用所有字段,那么创造性地使用 ADO GetString 方法可能是一种无需循环即可进行转换的方法。 cADBC 是 ADODB.Connection 的包装类,oTxtDB 是该类(连接)的一个实例; goFS 是一个用于 IO 操作的 FileSystemObject; sALL 是将 .GetString 应用于记录集的结果。专注于 .GetString 的参数:字段分隔符设置为 '","',记录分隔符设置为 '"\r\n"'。然后我们只需要添加第一个“并切断虚假的最后一个”即可引用所有字段。【参考方案2】:查看this link 的方法。 您可以做的是确保引号出现在将列数据放入文件的循环中,将引号附加到每个列数据的开头和结尾。
例如使循环如下:
For InnerCount = 0 To ColumnCount - 1
Str &= """" & DS.Tables(0).Rows(OuterCount).Item(InnerCount) & ""","
Next
【讨论】:
那行得通。我想看看是否有任何其他解决方案,因为每次我不得不通过 vb.net 在 excel 文件中工作时,速度非常慢。 当我提出不同的解决方案时,我可能有偏见。但是考虑这种方法的人应该思考 3 个问题:您是否希望 (1) 引用所有字段值而不考虑类型? (2) 每行都有一个尾随? (3) 在具有不可变字符串的语言中使用 2. 级别循环中的字符串连接? @Ekkehard.Horner 这些都是非常值得思考的问题。【参考方案3】:Public Class clsTest
Public Sub Test
Dim s as string = "C:\!Data\Test1.csv"
Dim Contents As String = System.IO.File.ReadAllText(s)
Dim aryLines As String() = Contents.Split(New String() Environment.Newline , StringSplitOptions.None)
Dim aryParts() As String
Dim aryHeader() As String
Dim dt As System.Data.DataTable
For i As Integer = 0 To aryLines.Length - 1
aryParts = SplitCSVLine(aryLines(i))
If dt Is Nothing And aryHeader Is Nothing Then
aryHeader = CType(aryParts.Clone, String())
ElseIf dt Is Nothing And aryHeader IsNot Nothing Then
dt = DTFromStringArray(aryParts, 1000, "", aryHeader)
Else
DTAddStringArray(dt, aryParts)
End If
Next
dt.dump
End Sub
Public Shared Function SplitCSVLine(strCSVQuotedLine As String) As String()
Dim aryLines As String() = strCSVQuotedLine.Split(New String() Environment.NewLine, StringSplitOptions.None)
Dim aryParts As String() = Nothing
For i As Integer = 0 To aryLines.Length - 1
Dim regx As New Text.RegularExpressions.Regex(",(?=(?:[^\""]*\""[^\""]*\"")*(?![^\""]*\""))")
aryParts = regx.Split(aryLines(i))
For p As Integer = 0 To aryParts.Length - 1
aryParts(p) = aryParts(p).Trim(" "c, """"c)
Next
Next
Return aryParts
End Function
Public Shared Function DTFromStringArray(ByVal aryValues() As String, Optional ByVal intDefaultColumnWidth As Integer = 255, Optional ByVal strTableName As String = "tblArray", Optional ByVal aryColumnNames() As String = Nothing) As DataTable
If String.IsNullOrWhiteSpace(strTableName) Then strTableName = "tblArray"
Dim dt As DataTable = New DataTable(strTableName)
Dim colNew(aryValues.GetUpperBound(0)) As DataColumn
If aryColumnNames Is Nothing Then
ReDim aryColumnNames(aryValues.Length)
Else
If aryColumnNames.GetUpperBound(0) < aryValues.GetUpperBound(0) Then
ReDim Preserve aryColumnNames(aryValues.Length)
End If
End If
For x As Integer = aryColumnNames.GetLowerBound(0) To aryColumnNames.GetUpperBound(0)
If String.IsNullOrWhiteSpace(aryColumnNames(x)) Then
aryColumnNames(x) = "Field" & x.ToString
Else
aryColumnNames(x) = aryColumnNames(x)
End If
Next
For i As Integer = 0 To aryValues.GetUpperBound(0)
colNew(i) = New DataColumn
With colNew(i)
.ColumnName = aryColumnNames(i) '"Value " & i
.DataType = GetType(String)
.AllowDBNull = False
.DefaultValue = ""
.MaxLength = intDefaultColumnWidth
.Unique = False
End With
Next
dt.Columns.AddRange(colNew)
Dim pRow As DataRow = dt.NewRow
For i As Integer = aryValues.GetLowerBound(0) To aryValues.GetUpperBound(0)
pRow.Item(i) = aryValues(i)
Next
dt.Rows.Add(pRow)
Return dt
End Function
Public Shared Sub DTAddStringArray(ByRef dt As DataTable, ByVal aryRowValues() As String)
Dim pRow As DataRow
pRow = dt.NewRow
For i As Integer = aryRowValues.GetLowerBound(0) To aryRowValues.GetUpperBound(0)
pRow.Item(i) = aryRowValues(i)
Next
dt.Rows.Add(pRow)
End Sub
End Class
【讨论】:
考虑添加一个关于你在做什么以及它如何回答 OP 的问题的解释。以上是关于vb.net xls 到 csv 带引号?的主要内容,如果未能解决你的问题,请参考以下文章