【问题标题】:Read large file line-by-line with ADO Stream?使用 ADO Stream 逐行读取大文件?
【发布时间】:2013-03-01 05:27:19
【问题描述】:

我想使用 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 使用率。那么有没有办法告诉脚本不要将所有文件内容加载到内存中,而只是打开并读取,直到遇到任何行分隔符?

【问题讨论】:

  • 如果你想从第一个 lineseparator 开始,你不应该循环直到 EOS(流结束),我也不确定你是否应该将你的 lineseparator 从默认 CrLf 更改为 Lf 之类的你做到了。

标签: asp-classic vbscript ado


【解决方案1】:

当您使用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

简而言之,这是您可以做的全部优化(或至少据我所知)。

【讨论】:

  • 感谢您的更正,但是我需要循环遍历文件的每一行,而不仅仅是第一行,我想优化代码,这样它就不会占用大量内存。
  • 好吧,我可能误解了你的问题,到时我会更新我的答案。
【解决方案2】:

如果您查看this snippet from J. T. Roff's ADO book,您会发现理论上您可以逐行读取文件(无需将其完全加载到内存中)。我尝试在source参数中使用file: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

一些背景看here

【讨论】:

  • 非常有趣,但似乎我无法正确测试,因为我得到“找不到提供程序”。您能否详细说明“C:\lib\linesutf8.txt”中的示例文件?我尝试了sTDir、“C:/lib/linesutf8.txt”、“C:/lib”、“C:/lib/”、“C:\lib\linesutf8.txt”、“C: \lib"、"C:\lib\" 都失败了。谢谢
  • @PanayotKarabakalov - 如果您收到“Provider not found”错误,那么“Provider=...”属性或您的 ADO 安装有问题。 sTDir 是 .txt 文件(和 schema.ini 文件)所在的文件夹。
  • @Ekkehard.Horner 我的文本文件的路径是 c:\test.txt ,这是我的尝试 pastebin.com/r4Zm1N4d 。我打开命令提示符并运行脚本,但我得到的只是第 10 行的“没有足够的存储空间来处理此命令”(80078008),即“WScript.Stdin.Readline”。您对此错误有任何想法吗?
  • @PanayotKarabakalov - 使用“\”作为路径分隔符;第 10 行是“.Open”语句;它是否适用于小文件?
  • @Ekkehard.Horner - 我想你的最后一条评论是给 user433531 的,对吧? ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 2011-12-22
相关资源
最近更新 更多