操作系统  办公  实用知识  设计  开发  WEB开发  移动开发  数据库  软件工程  网管  安全  管理  信息化  答疑  渠道 

用FileIO读取二进制数据(一)

2004-6-7 作者:十年磨一剑 转载自:奥古多媒体 网友评论 0 条 点击进入论坛

用FileIO读取二进制数据

我有一个project,需要直接从以二进制形式储存的数据库中读取数据。看来我需要诸如BinaryIO或者BinaryMaster的Xtra去从磁盘上读取了,但是利用FileIO,做稍许工作,也可以做到读写二进制文件。
FileIO专注于一件事情:读写ASCII文本文件。不能读取二进制文件的主要原因是当遇到0字节时,被当作ASCII字符0-即空字符-文件结束的标志。因为二进制文件中有大量的0存在,你也就不能读出所需要的数据了。

FileIOk中的 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


 

[下一页]


 


if (fileLength >= startByte) and (fileLength >= endByte) then
fileObj.setPosition(startByte-1)
-- Position FileIO to read from the correct point in the file
repeat with index = startByte to endByte
byteList.append(charToNum(fileObj.readChar()))
end repeat
end if
end if

fileObj.closeFile()
fileObj = 0
return byteList
end

例子:读取MP3标签

使用这个程序的真实例子是读取MP3文件标签。MP3文件标签存储在最后的128个字节中。本例子包含有一个Director movie,说明是如何做到这一点的(需要FileXtra和FileIO Xtra)。(关于文件格式,可参考:http://www.wotsit.org)
此例子程序从MP3文件中读取了诸如歌名、歌手、专辑名、年份、风格等信息。

on readMP3tags filePath

fileLength = getFileSizeInBytes (filePath)
if fileLength > 0 then
byteList = readBinaryFile (filePath, fileLength - 127, fileLength)
tagStr = ""
repeat with index = 1 to byteList.count
tagStr = tagStr & numToChar (byteList[index])
end repeat

tags = [#title: tagStr.char[4..33], #artist: tagStr.char[34..63], #album: tagStr.char[64..93], #year: tagStr.char[94..97], #genre: getGenre (charToNum (tagStr.char[128]) + 1)]

repeat with index = 1 to tags.count
memberName = string (tags.getPropAt (index))
newText = clipString (tags[index])
member (memberName).text = newText
end repeat
end if

end

一些数据类型的定义:
String:ASCII文本,每字符8位(1字节).
Unsigned integers(8,16,32,64bits) 无符号型表明仅为正值,表示范围由位数决定。一个16位整数,介于0到65535(2^16-1).
Signed integers(8,16,32,64 bits) 有符号型表明可正可负。由于无符号型整数由位数决定表示范围,不同的是有符号型整数有一半是负数。这样,16位有符号整数型表示范围从-32768到32767.

用FileIO保存位图

bitmap_export.dir是一个从演员表中的位图数据导出文件的例子。我们能决定位图文件的布局。伎巧是确保文件头信息是正确的。这里数据类型的知识可大显身手了,位图格式用到了8位、16位、32位无符号型整数,如同ASCII文本数据一样有着各种自有的属性。

在转换数据这一部分,在bitmap_export中的exportBitMap句柄上,你可增加支持位图格式的其它特性,使其更复杂。这包括利用调色板创建图象,压缩图象时用长编码,认不同位深保存图象等。

其它文件格式

经由FileIO能够探查和保存的文件形式丰富多样,包括声音、位图、数据库、数字影片等你所能拷进硬盘的文件。现在我不敢说没人会在Director 中建立一个QuickTime文件,或去试着重建数据库,但是对于速度不是问题的小任务,便宜的FileIO不在话下。

已有 0 位对此文章感兴趣的网友发布了看法    
我来评两句 登录邮箱: 密码:
  匿名发表
今日推荐
技术文库(共有 46430 篇文章)
操作系统
办公软件
实用知识
网络管理
软件开发
WEB开发
软件工程
数据库
设计在线
信息安全
行业信息化
管理信息化
重点推荐
电子杂志订阅
点击电子杂志名称查看样刊
输入E-mail地址即可订阅
E-mail