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

Posted

技术标签:

【中文标题】Actionscript 3,只能读取文件的一部分而不将整个文件加载到内存中【英文标题】:Actionscript 3, can only part of a file be read without loading the whole file into memory 【发布时间】:2017-08-08 05:51:10 【问题描述】:

我正在尝试在 Air 桌面应用程序中加载 600mb 文件的 10mb 块。起初我尝试加载整个文件,但出现“系统内存不足”错误,或者 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 是否实际上阻止了从文件开头到读取位置开始读取文件?

好像 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);
    

【问题讨论】:

尝试在每次释放使用的数据时调用 System.gc()。垃圾收集器应该自己挑选释放的数据,但如果你不断地读取新数据,GC 可能没有机会完成它的工作。我还建议跟踪 System 类内存值,以更好地了解您的系统在读取过程中发生了什么:help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/… 谢谢,GC 确实帮助避免了一点内存错误,但它并没有真正解决问题,因为我想读取更大的文件。 好吧,我刚刚打开了 FileStream 文档,看看我发现了什么:help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/… 我添加了预读并如上所述修改了我的问题,因为我不确定它的解决方案。 一个问题。为什么还要使用异步模式? 【参考方案1】:

如果您想异步读取文件并且不想加载整个文件,您应该设置readAhead 属性。

此属性的默认值为无穷大:默认情况下,文件 打开以异步读取,直到文件末尾。

还要注意COMPLETE 事件是在读取整个文件时调度的,因此您可能想改用PROGRESS 事件

表示流上新数据的可用性。

不要将FileStream 视为ByteArray,因为它不是。它使用相同的数据输入/输出接口,但您从中读取的数据不存储在 RAM 中 - 您只需从硬盘驱动器读取数据。 ByteArray 例如有 length 属性,它不是文件流的属性。

您还可以找到对您有用的This demonstration。

编辑

异步读取的全部目的是在每次进度事件侦听器调用时获取文件的一部分,这样您就不会一遍又一遍地打开和关闭文件。下面的示例从文件中读取 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 值,然后文件读取已售出停止单元您读取的已加载数据。

【讨论】:

我在上面编辑了我的问题,因为我在使用 readAhead 时遇到了同样的问题,我使用的基本代码与 Adob​​e 示例中的相同,但 readAhead 并没有说明只从偏移量读取,这就是我想我需要。 谢谢,我现在理解并实现了。我想我把它复杂化了,因为我没有意识到读取可用字节会导致下一部分被自动读取。我想我必须更新职位。非常感谢。

以上是关于Actionscript 3,只能读取文件的一部分而不将整个文件加载到内存中的主要内容,如果未能解决你的问题,请参考以下文章

ActionScript 3 使用ActionScript 3异步读取文件

使用ActionScript 3异步读取文件

ActionScript 3 使用AS3读取不同的文件类型

将actionscript 3中的xml文件中的值读取到组合框中

如何使用 actionscript 3 将 ascii 文件加载到数组中

ActionScript 3 解析/读取SWF标题