我正在尝试在Air桌面应用中加载一个10mb的600mb文件块。起初我尝试加载整个文件,但是我遇到了“系统内存不足”错误,或者SWF只是退出而没有错误。
我还没有把文件的一部分只读到一个字节数组中,清除数组然后读取下一部分。这样做效果更好,但它仍然会在文件末尾出现内存问题。
据我了解,下面的方法应该只读取所请求文件的部分。但我认为由于某种原因,从我想要的块的开始到结束的文件实际上是读取的。我的剪切代码如下所示:
var file:File = File.desktopDirectory.resolvePath('input.txt');
var fileStream:FileStream = new FileStream();
fileStream.addEventListener(Event.COMPLETE, onLoaded);
fileStream.openAsync(file, FileMode.READ);
fileStream.position = _currentPos;
加载时:
var fileStream:FileStream = event.target as FileStream;
_fileSize = fileStream.bytesAvailable;
bytes.clear();
fileStream.readBytes(bytes, 0, 10000000);
然后我对字节做了一些事情并再次调用上面的代码,这次是位置是前一个位置加上一次读取的长度。
当我检查字节数组时,我可以看到大小等于文件的开头到读取的结尾。在读取开始之前,字节数组不包含元素中的数据,这正是我所期望的。
我只是在阅读我想要的块或整个文件吗?
如果我不能,我可以这样做吗?
如何解决内存问题?
我得到的错误是
Error: Error #1000: The system is out of memory.
at flash.filesystem::FileStream/readBytes()
编辑:
经过更多测试后,我确信整个文件都会被读入内存。
System.privateMemory报告文件大小刚刚超过文件大小的内存使用情况,当我检查FileStream时,我看到它本身的大小而不是我想要的块。
编辑2:我现在已经添加了readAhead和progress事件,但它实际上以相同的方式运行,除了我控制预读大小。 readAhead是否实际上阻止文件从文件开始读取到读取位置的开始?
就好像fileStream.position并没有真正做任何事情。
我的新代码如下:
private function read(pos:int):void {
_bytes.clear();
var file:File = File.desktopDirectory.resolvePath('big.mp4');
var fileStream:FileStream = new FileStream();
fileStream.readAhead = 10000000;
fileStream.addEventListener(ProgressEvent.PROGRESS, readProgressHandler)
fileStream.openAsync(file, FileMode.READ);
fileStream.position = _pos;
function readProgressHandler(event:ProgressEvent):void {
if (fileStream.bytesAvailable >= 10000000) {
fileStream.removeEventListener(ProgressEvent.PROGRESS, readProgressHandler)
fileStream.readBytes(_bytes, _pos, 10000000);
fileStream.close();
//get next bit
go();
}
}
}
private function go():void {
_pos = _pos + 10000000;
read(_pos);
}
答案 0 :(得分:3)
如果要异步读取文件而不想加载整个文件,则应设置readAhead属性。
此属性的默认值为无穷大:默认情况下为文件 打开以异步读取读取到文件末尾。
另请注意,在读取整个文件时会调度COMPLETE
事件,因此您可能希望使用PROGRESS
事件
表示流上新数据的可用性。
并且不要将FileStream
视为ByteArray
,因为它不是。它使用相同的数据输入/输出交互,但您从中读取的数据不会存储在RAM中 - 您只需从硬盘驱动器读取数据。
例如,ByteArray
具有length
属性,该属性不是文件流的属性。
您还可以找到对您有用的This demonstration。
修改强>
异步读取的整个目的是在每个progress事件侦听器调用中获取文件的一部分,这样就不会反复打开和关闭该文件。下面的示例从文件中读取3MB。你可以在任何你想要的位置开始阅读。
var _pos:Number = 100000; //starting positon - could be any within a file.
var bytes:ByteArray = new ByteArray();
var totalToRead:Number = 3 * 1024 * 1024;
var file:File = File.desktopDirectory.resolvePath("SILENCE GROOVE - live at Kompas Audio .mp3");
var fileStream:FileStream = new FileStream();
fileStream.readAhead = 10000000;
fileStream.addEventListener(ProgressEvent.PROGRESS, readProgressHandler);
fileStream.openAsync(file, FileMode.READ);
fileStream.position = _pos;
function readProgressHandler(event:ProgressEvent):void {
var tr:Number = Math.min(totalToRead - bytes.length , fileStream.bytesAvailable); //bytes to read.
fileStream.readBytes(bytes, bytes.length, tr);
if (bytes.length < totalToRead) return;
fileStream.removeEventListener(ProgressEvent.PROGRESS, readProgressHandler);
fileStream.close();
trace(bytes.length / (1024 * 1024), "MB readed.");
}
更多详情:
确保事情清楚。您无需采取任何额外步骤将此拆分为10MB块。您可以将totalToRead设置为700MB,并随时读取该文件的数据(一旦可用)。 readAhead
属性只是告诉你应该将多少字节加载到内存中,即使你没有立即读取它们。您可能会在每个ProgressEvent
获得较少的数据,但事件将是调度程序,直到您点击readAhead
值,然后文件读取已停止单位读取已加载的数据。