Vbscript &引用;没有足够的存储空间来完成此操作“;base64编码zip文件时

Vbscript &引用;没有足够的存储空间来完成此操作“;base64编码zip文件时,vbscript,base64,adodb,xmldom,Vbscript,Base64,Adodb,Xmldom,下面的代码用于将zip文件转换为base64格式 Dim inByteArray, base64Encoded, Const TypeBinary = 1 inByteArray = readBytes("F:path/file.zip") base64Encoded = encodeBase64(inByteArray) Private Function readBytes(file) Dim inStream ' ADODB stream object used S

下面的代码用于将zip文件转换为base64格式

Dim inByteArray, base64Encoded,
Const TypeBinary = 1
inByteArray = readBytes("F:path/file.zip")
base64Encoded = encodeBase64(inByteArray)

Private Function readBytes(file)
    Dim inStream
    ' ADODB stream object used
    Set inStream = CreateObject("ADODB.Stream")
    ' open with no arguments makes the stream an empty container 
    inStream.Open
    inStream.Type = TypeBinary
    inStream.LoadFromFile(file)
    readBytes = inStream.Read()
End Function

Private Function encodeBase64(bytes)
    Dim DM, EL
    Set DM = CreateObject("Microsoft.XMLDOM")
    ' Create temporary node with Base64 data type
    Set EL = DM.CreateElement("tmp")
    EL.DataType = "bin.base64"
    ' Set bytes, get encoded String
    EL.NodeTypedValue = bytes
    encodeBase64 = EL.Text
End Function
我先用一个3MB大小的zip文件试试,效果很好。但当我尝试使用大小为34MB的zip文件时,它会说

存储空间不足,无法完成此操作

排队

encodeBase64 = EL.Text

有什么方法可以处理所有大小的zip文件,因为我的文件大小大多为30MB或更大。

已编辑2017/01/10-(原始答案保留在底部)


已编辑2017/01/10-(再次)-我的一些(并非全部)超时问题是由磁盘故障引起的

通过拆分转换操作来处理输入数据的问题。现在,代码已更改为以两种不同的方式处理缓冲:对于小文件(默认情况下为小于等于10MB的文件配置)使用内存流存储输出,但对于大文件(大于
10MB
)使用临时文件(请参阅代码后的注释)

选项显式
暗缓冲区
buffer=encodeFileBase64(“file.zip”)
WScript.StdOut.WriteLine(CStr(Len(buffer)))
专用函数encodeFileBase64(文件)
'声明ADODB使用的常量
常量adTypeBinary=1
常量adTypeText=2
'声明FSO常量
Const TEMP_文件夹=2
'初始化输出
encodeFileBase64=“”
'实例化FileSystemObject
模糊fso
设置fso=WScript.CreateObject(“Scripting.FileSystemObject”)
'检查输入文件是否存在
如果不存在fso.FileExists(文件),则
退出功能
如果结束
'确定我们将如何处理数据缓冲。
'对大文件使用临时文件
Dim使用临时文件
useTemporaryFile=fso.GetFile(file).Size>10*1048576
'实例化B64转换组件
尺寸b64
Set b64=WScript.CreateObject(“Microsoft.XMLDOM”).CreateElement(“tmp”)
b64.DataType=“bin.base64”
Dim outputBuffer,outputBufferName
如果使用临时文件,则
'创建用作缓冲区的临时文件
outputBufferName=fso.BuildPath(\u
fso.GetSpecialFolder(临时文件夹),\u
fso.GetTempName()
)
设置outputBuffer=fso.CreateTextFile(outputBufferName,True)
其他的
'实例化要用作缓冲区的文本流以避免字符串
'产生内存不足问题的串联操作
设置outputBuffer=WScript.CreateObject(“ADODB.Stream”)
带输出缓冲区
'每个字符两个字节,BOM前缀缓冲区
.Type=adTypeText
.Charset=“Unicode”
打开
以
如果结束
'实例化二进制流对象以读取输入文件
使用WScript.CreateObject(“ADODB.Stream”)
打开
.Type=adTypeBinary
.LoadFromFile(文件)
'迭代输入文件转换文件,转换每个读取的
'块并将转换后的文本追加到输出缓冲区
Dim输入缓冲区
做
inputBuffer=.Read(3145716)
如果为空(inputBuffer),则退出Do
b64.NodeTypedValue=inputBuffer
如果使用临时文件,则
调用outputBuffer.Write(b64.Text)
其他的
调用outputBuffer.WriteText(b64.Text)
如果结束
环
'已读取输入文件,请关闭其关联流
Call.Close()
以
'是时候将文本输出缓冲区的内容检索到
“绳子。
如果使用临时文件,则
'关闭输出文件
调用outputBuffer.Close()
'读取缓冲区文件中的所有数据
encodeFileBase64=fso.OpenTextFile(outputBufferName).ReadAll()
'删除临时文件
调用fso.DeleteFile(outputBufferName)
其他的
'因此,由于流中已经有一个Unicode字符串,我们将
'将其转换为二进制,并使用.Read()直接检索数据
"方法。
带输出缓冲区
'类型转换仅在流开始时才可能
.位置=0
'将流类型从文本更改为二进制
.Type=adTypeBinary
'跳过BOM表
.位置=2
'检索缓冲数据
encodeFileBase64=CStr(.Read())
'确保清除流内容
.位置=0
Call.SetEOS()
“好了,关上小溪
Call.Close()
以
如果结束
端函数
内存会有问题吗?

对。可用内存仍然是一个限制。无论如何,我已经用
cscript.exe
测试了代码,它作为32位进程运行,有90MB的文件,在64位模式下运行,有500MB的文件,没有问题

为什么有两种方法?

  • stream
    方法速度更快(所有操作都在内存中完成,没有字符串连接),但它需要更多内存,因为它在函数末尾将有两个相同数据的副本:流中有一个副本,返回的字符串中有一个副本

  • 临时文件方法速度较慢,因为缓冲数据将写入磁盘,但由于数据只有一个副本,因此需要的内存较少

用于确定是否使用临时文件的
10MB
限制只是一种伪配置,用于防止在32位模式下出现问题。为了安全起见,我在32位模式下处理了90MB的文件,没有任何问题

为什么将
配置为
Unicode
,并通过
.Read()
方法检索数据?

因为
stream.ReadText()
的速度很慢。从内部来看,它会带来很多好处
Option Explicit
Const TypeBinary = 1

Dim buffer
    buffer = encodeFileBase64( "file.zip" ) 
    WScript.StdOut.WriteLine( buffer )

Private Function encodeFileBase64( file )

    Dim b64 
    Set b64 = WScript.CreateObject("Microsoft.XMLDOM").CreateElement("tmp")
        b64.DataType = "bin.base64"

    Dim outputBuffer
    Set outputBuffer = WScript.CreateObject("Scripting.Dictionary")

    With WScript.CreateObject("ADODB.Stream")
        .Open
        .Type = TypeBinary
        .LoadFromFile(file)

        Dim inputBuffer
        Do
            inputBuffer = .Read(3145716)
            If IsNull( inputBuffer ) Then Exit Do

            b64.NodeTypedValue = inputBuffer
            outputBuffer.Add outputBuffer.Count + 1, b64.Text 
        Loop 

        .Close
    End With

    encodeFileBase64 = Join(outputBuffer.Items(), vbCrLf)
End Function