原著:David Pollock
翻译:DCM
我有一个project,需要直接从以二进制形式储存的数据库中读取数据。看来我需要诸如BinaryIO或者BinaryMaster的Xtra去从磁盘上读取了,但是利用FileIO,做稍许工作,也可以做到读写二进制文件。
FileIO专注于一件事情:读写ASCII文本文件。不能读取二进制文件的主要原因是当遇到0字节时,被当作ASCII字符0-即空字符-文件结束的标志。因为二进制文件中有大量的0存在,你也就不能读出所需要的数据了。
FileIO中的getLength和readChar函数
幸运的是,FileIO有许多其它的函数让我们绕过这个限制。首先是Getlength,能够准确地得到文件的字节数(在文本文件中,一个字节代表一个ASCII字节,但在二进制中不同,在后面再来解释)。
其次我们会以ReadChar代替ReadFile。ReadChar读取一个字节或字符后,移到下一个字节并等待。重要的是ReadChar并不关心读到字节是否是0,它将返回一个空字符串给Lingo交移到下一个字节。
二进制数据
现在我们有办法知道文件中有多少字节,也能够读取每一个字节了。接下来的事情是什么数据是我们所需要的。如果我们保存所有读取到的字节,问题不亚于用ReadFile函数了。在Lingo中,0字节等同于empty,或者" ",在字符串中不会增加任何东西。
很明显的变通办法是将所有读出的数据作为一个字符串保存在线性列表里(也有其它办法,例如使用Image object),再由CharToNum函数将这些字符串数据转换成数字。这样,文件中每个字节的值都可加入线性列表中,我们就可以操作这些数据了。下面是其代码:
on readBinaryFile filePath
-- Call handler using the full file path
byteList = []
-- This list will contain all of the byte values retrieved
fileObj = new(xtra "fileIO")
fileObj.openFile(filePath, 1)
-- Open the file with read-only access
if fileObj.status() = 0 then
fileLength = fileObj.getLength()
-- Find the length of the file in bytes
repeat with index = 1 to fileLength
byteList.append(charToNum(fileObj.readChar()))
-- Append the value of each byte of the file to byteList
end repeat
end if
fileObj.closeFile()
-- Close the file
fileObj = 0
-- Clear the FileIO instance from memory
return byteList
end
关键在于弄清Repeat循环,结合使用ReadChar函数,让FileIO保持从文件中读取数据,不管所遇到的字符值。这样我们就有办法完整地读取任何文件。
读取长文件
你会想到的一个问题是,使用readBinaryFile程序读取长文件时会返回一个极大的byteList 变量,占用许多内存。假如我们知道哪部分数据是我们想要的,可以这样作轻微的修改。
on readBinaryFile filePath, startByte, endByte
-- Optional parameters for specifying positions in the file
byteList = []
fileObj = new(xtra "fileIO")
fileObj.openFile(filePath, 1)
if fileObj.status() = 0 then
fileLength = fileObj.getLength()
if startByte.voidP then
-- Read entire file if parameters aren't supplied
startByte = 1
endByte = fileLength
end if