以下代码用于将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文件.它工作正常.但是,当我尝试使用尺寸为34 MB的zip文件时,它说
Not enough storage is available to complete this operation!
在线
encodeBase64 = EL.Text
有什么方法可以处理各种大小的zip文件,因为我的文件大小大多是30MB或更多.
最佳答案 编辑2017/01/10 – (原始答案保持在底部)
编辑2017/01/10 – (再次) – 我的一些(不是全部)超时问题是由磁盘故障引起的.
输入数据的问题通过拆分转换操作来处理.现在代码已经改变为以两种不同的方式处理缓冲:对于小文件(默认配置为高达10MB的文件),内存流用于存储输出,但对于大文件(大于10MB),使用临时文件(见代码后的注释).
Option Explicit
Dim buffer
buffer = encodeFileBase64( "file.zip" )
WScript.StdOut.WriteLine( CStr(Len(buffer)) )
Private Function encodeFileBase64( file )
' Declare ADODB used constants
Const adTypeBinary = 1
Const adTypeText = 2
' Declare FSO constants
Const TEMP_FOLDER = 2
' Initialize output
encodeFileBase64 = ""
' Instantiate FileSystemObject
Dim fso
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
' Check input file exists
If Not fso.FileExists( file ) Then
Exit Function
End If
' Determine how we will handle data buffering.
' Use a temporary file for large files
Dim useTemporaryFile
useTemporaryFile = fso.GetFile( file ).Size > 10 * 1048576
' Instantiate the B64 conversion component
Dim b64
Set b64 = WScript.CreateObject("Microsoft.XMLDOM").CreateElement("tmp")
b64.DataType = "bin.base64"
Dim outputBuffer, outputBufferName
If useTemporaryFile Then
' Create a temporary file to be used as a buffer
outputBufferName = fso.BuildPath( _
fso.GetSpecialFolder( TEMP_FOLDER ), _
fso.GetTempName() _
)
Set outputBuffer = fso.CreateTextFile( outputBufferName, True )
Else
' Instantiate a text stream to be used as a buffer to avoid string
' concatenation operations that were generating out of memory problems
Set outputBuffer = WScript.CreateObject("ADODB.Stream")
With outputBuffer
' Two bytes per character, BOM prefixed buffer
.Type = adTypeText
.Charset = "Unicode"
.Open
End With
End If
' Instantiate a binary stream object to read input file
With WScript.CreateObject("ADODB.Stream")
.Open
.Type = adTypeBinary
.LoadFromFile(file)
' Iterate over input file converting the file, converting each readed
' block to base64 and appending the converted text into the output buffer
Dim inputBuffer
Do
inputBuffer = .Read(3145716)
If IsNull( inputBuffer ) Then Exit Do
b64.NodeTypedValue = inputBuffer
If useTemporaryFile Then
Call outputBuffer.Write( b64.Text )
Else
Call outputBuffer.WriteText( b64.Text )
End If
Loop
' Input file has been readed, close its associated stream
Call .Close()
End With
' It is time to retrieve the contents of the text output buffer into a
' string.
If useTemporaryFile Then
' Close output file
Call outputBuffer.Close()
' Read all the data from the buffer file
encodeFileBase64 = fso.OpenTextFile( outputBufferName ).ReadAll()
' Remove temporary file
Call fso.DeleteFile( outputBufferName )
Else
' So, as we already have a Unicode string inside the stream, we will
' convert it into binary and directly retrieve the data with the .Read()
' method.
With outputBuffer
' Type conversion is only possible while at the start of the stream
.Position = 0
' Change stream type from text to binary
.Type = adTypeBinary
' Skip BOM
.Position = 2
' Retrieve buffered data
encodeFileBase64 = CStr(.Read())
' Ensure we clear the stream contents
.Position = 0
Call .SetEOS()
' All done, close the stream
Call .Close()
End With
End If
End Function
记忆会有问题吗?
是.可用内存仍然是一个限制.无论如何,我已经使用cscript.exe测试代码,运行为32位进程,文件为90MB,64位模式,500MB文件,没有问题.
为什么两种方法?
>流方法更快(所有操作都在内存中完成,没有字符串连接),但它需要更多内存,因为它在函数末尾有两个相同数据的副本:流中有一个副本,一个在将返回的字符串中
>临时文件方法较慢,因为缓冲的数据将写入磁盘,但由于只有一个数据副本,因此需要的内存较少.
用于确定我们是否将使用临时文件的10MB限制只是一种用于防止32位模式问题的悲观配置.我已经在32位模式下处理了90MB文件而没有任何问题,但为了安全起见.
为什么将流配置为Unicode并通过.Read()方法检索数据?
因为stream.ReadText()很慢.在内部,它会进行大量的字符串转换/检查(是的,在documentation中建议),使其在这种情况下无法使用.
下面是原始答案.它更简单并且避免了转换中的内存问题,但是对于大文件来说,这还不够.
拆分读/编码过程
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
笔记:
>不,它不是防弹的.您仍然受构造输出字符串所需空间的限制.对于大文件,您需要使用输出文件,编写部分结果,直到处理完所有输入.
> 3145716只是54的最近倍数(每个base64输出行的输入字节数)低于3145728(3MB).