Actionscript 3,只能读取文件的一部分而不将整个文件加载到内存中

时间:2017-03-16 20:50:39

标签: actionscript-3 flash actionscript air

我正在尝试在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);
    }

1 个答案:

答案 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值,然后文件读取已停止单位读取已加载的数据。