8

我想使用 ADO Stream 从具有 UTF-8 编码的本地大文本文件中读取行,所以我尝试

Set objStream = CreateObject("ADODB.Stream")
objStream.Charset = "utf-8"
objStream.Type = 2
objStream.Open
objStream.LoadFromFile = strFile
objStream.LineSeparator = 10
Do Until objStream.EOS
    strLine = objStream.ReadText(-2)
Loop

但是结果是脚本占用了大量的 RAM 和 CPU 使用率。那么有没有办法告诉脚本不要将所有文件内容加载到内存中,而只是打开它并阅读直到它遇到任何行分隔符?

4

2 回答 2

12

当您使用Stream对象时,我认为很明显,但是,.LoadFromFile用整个文件内容填充当前流,并且没有任何自定义选项来从文件加载部分数据。

至于读取 1 行,您已经使用.ReadText(-2), (-2 = adReadLine) 完成了此操作。

Set objStream = CreateObject("ADODB.Stream")
objStream.Charset = "utf-8"
objStream.Type = 2
objStream.Open
'objStream.LoadFromFile = strFile ''I see a typo here
objStream.LoadFromFile strFile
objStream.LineSeparator = 10      ''that's Ok
'Do Until objStream.EOS           ''no need this
    strLine = objStream.ReadText(-2)
'Loop
objStream.Close ''add this though!

[编辑]好吧,对于.LineSeparator您只能使用 3 个常量:

Constant Value Description

adCRLF   -1    Default. Carriage return line feed 
adLF     10    Line feed only 
adCR     13    Carriage return only 

如果您需要拆分Do..Loop其他字母,这.ReadText是阅读文本流的唯一选择,您可以将其与InStr函数结合使用,Exit Do然后找到您的自定义分隔符。

Const cSeparator = "_" 'your custom separator
Dim strLine, strTotal, index
Do Until objStream.EOS
    strLine = objStream.ReadText(-2)
    index = InStr(1, strLine, cSeparator)
    If index <> 0 Then
        strTotal = strTotal & Left(strLine, index-1)
        Exit Do
    Else
        strTotal = strTotal & strLine
    End If
Loop

很快,这就是你可以做的全部优化(或者至少据我所知)。

于 2013-03-01T21:05:02.897 回答
3

如果您查看JT Roff 的 ADO book 中的这个片段,您会发现理论上您可以逐行读取文件(无需将其完全加载到内存中)。我尝试在源参数中使用文件:protocol,但没有成功。

所以让我们尝试另一种方法:要将 .txt 文件视为 UTF8 编码的普通(一列)ADO 数据库表,您需要在源目录中有一个 schema.ini 文件:

[linesutf8.txt]
ColNameHeader=False
CharacterSet=65001
Format=TabDelimited
Col1=SampleText CHAR WIDTH 100

然后你可以这样做:

  Dim sTDir  : sTDir   = "M:/lib/kurs0705/testdata"
  Dim sFName : sFName  = "[linesutf8.txt]"
  Dim oDb    : Set oDb = CreateObject("ADODB.Connection")
  Dim sCs    : sCs     = Join(Array( _
          "Provider=MSDASQL" _
        , "Driver={Microsoft Text Driver (*.txt; *.csv)}" _
        , "DBQ=" + sTDir _
  ), ";")
  oDb.open sCs
  WScript.Stdin.Readline
  Dim oRs    : Set oRs = oDb.Execute("SELECT * FROM " & sFName)
  WScript.Stdin.Readline
  Do Until oRS.EOF
     WScript.Echo oRS.Fields(0).Value
     oRs.MoveNext
  Loop
  oRs.Close
  oDb.Close

对于一些背景看这里

于 2013-03-02T16:42:11.180 回答