首先我想说明的是,由于项目太大,我无法发布源代码。 我正在尝试在 iPad 设备上下载一个大文件 (500+ MB)。 最初我尝试使用 URLLoader,但后来我意识到 iPad 设备的内存资源非常有限。我认为 URLStream 会以 block 的形式下载文件,并且使用 FileStream 我可以将这些 block 保存在设备上(如 AS3: URLStream saving files to desktop? ),但我错了,当我尝试下载大文件时,设备崩溃,因为 RAM设备的容量不够(更准确地说,这变得太大:System.privateMemory) 有谁知道如何分块下载文件,是否可以不使用“套接字连接”?
提前致谢。
编辑: 这是我使用的代码(注释行是仅在下载文件后才关闭 FileStream 的版本。
package components.streamDownloader
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.OutputProgressEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.system.System;
import flash.utils.ByteArray;
/**
*
*/
public class StreamDownloader extends EventDispatcher
{
[Event(name="DownloadComplete", type="com.tatstyappz.net.DownloadEvent")]
[Event(name="Error", type="com.tatstyappz.net.DownloadEvent")]
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
public function StreamDownloader()
{
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
private var file:File;
//private var fileStream:FileStream;
private var urlRequest:URLRequest;
private var urlStream:URLStream;
private var waitingForDataToWrite:Boolean = false;
//--------------------------------------------------------------------------
//
// API
//
//--------------------------------------------------------------------------
public function download(urlRequest:URLRequest, file:File):void {
init();
this.urlRequest = urlRequest;
this.file = file;
//fileStream.open(file, FileMode.WRITE);
urlStream.load(urlRequest);
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
//----------------------------------
// urlStream events
//----------------------------------
protected function urlStream_openHandler(event:Event):void
{
waitingForDataToWrite = false;
dispatchEvent(event.clone());
}
protected function urlStream_progressHandler(event:ProgressEvent):void
{
trace("MEMORY:", System.totalMemoryNumber / 1024 / 1024, "MEMORY P:", System.privateMemory / 1024 / 1024, "FREE MEMORY:", System.freeMemory / 1024 / 1024, "PROGRESS:", event.bytesLoaded / event.bytesTotal );
if(waitingForDataToWrite){
writeToDisk();
}
}
protected function urlStream_completeHandler(event:Event):void
{
if(urlStream.bytesAvailable > 0)
{
writeToDisk();
}
//fileStream.close();
destory();
dispatchEvent(event.clone());
// dispatch additional DownloadEvent
dispatchEvent(new StreamDownloadEvent(StreamDownloadEvent.DOWNLOAD_COMPLETE, urlRequest, file));
}
protected function urlStream_securityErrorHandler(event:SecurityErrorEvent):void
{
dispatchEvent(new StreamDownloadEvent(StreamDownloadEvent.ERROR, urlRequest, file, event.errorID.toString()));
destory();
}
protected function urlStream_ioErrorHandler(event:IOErrorEvent):void
{
dispatchEvent(new StreamDownloadEvent(StreamDownloadEvent.ERROR, urlRequest, file, event.errorID.toString()));
destory();
}
//----------------------------------
// fileStream events
//----------------------------------
protected function fileStream_outputProgressHandler(event:OutputProgressEvent):void
{
waitingForDataToWrite = true;
}
protected function fileStream_ioErrorHandler(event:IOErrorEvent):void
{
dispatchEvent(new StreamDownloadEvent(StreamDownloadEvent.ERROR, urlRequest, file, event.errorID.toString()));
destory();
}
//--------------------------------------------------------------------------
//
// Utils
//
//--------------------------------------------------------------------------
private function init():void
{
urlStream = new URLStream();
//fileStream = new FileStream();
urlStream.addEventListener(Event.OPEN, urlStream_openHandler);
urlStream.addEventListener(ProgressEvent.PROGRESS, urlStream_progressHandler);
urlStream.addEventListener(Event.COMPLETE, urlStream_completeHandler);
urlStream.addEventListener(IOErrorEvent.IO_ERROR, urlStream_ioErrorHandler);
urlStream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, urlStream_securityErrorHandler);
//fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, fileStream_outputProgressHandler)
//fileStream.addEventListener(IOErrorEvent.IO_ERROR, fileStream_ioErrorHandler);
}
private function destory():void
{
urlStream.removeEventListener(Event.OPEN, urlStream_openHandler);
urlStream.removeEventListener(ProgressEvent.PROGRESS, urlStream_progressHandler);
urlStream.removeEventListener(Event.COMPLETE, urlStream_completeHandler);
urlStream.removeEventListener(IOErrorEvent.IO_ERROR, urlStream_ioErrorHandler);
urlStream.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, urlStream_securityErrorHandler);
//fileStream.removeEventListener(OutputProgressEvent.OUTPUT_PROGRESS, fileStream_outputProgressHandler)
//fileStream.removeEventListener(IOErrorEvent.IO_ERROR, fileStream_ioErrorHandler);
urlStream = null;
//fileStream = null;
}
private function writeToDisk():void {
/*var fileData:ByteArray = new ByteArray();
urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
fileStream.writeBytes(fileData,0,fileData.length);
waitingForDataToWrite = false;*/
var bytes:ByteArray = new ByteArray();
urlStream.readBytes( bytes );
var fs:FileStream = new FileStream();
fs.open( file, FileMode.APPEND );
fs.writeBytes( bytes );
fs.close();
}
}
}
最佳答案
正如我在 csomakk 的评论中所说,我已使用 URLStream 分块方法通过 AIR 桌面版、iOS 版和 Android 版成功下载了 300+ MB 文件。
伪代码:
var stream:URLStream = new URLStream();
stream.addEventListener( PROGRESS, progressHandler );
stream.addEventListener( COMPLETE, completeHandler );
stream.load( url );
private function progressHandler( e:ProgressEvent ):void {
this.writeDataToDisk();
}
private function completeHandler( e:Event ):void {
this.writeDataToDisk();
}
private function writeDataToDisk():void {
var bytes:ByteArray = new ByteArray();
this.stream.readBytes( bytes );
var fs:FileStream = new FileStream();
fs.open( file, FileMode.APPEND );
fs.writeBytes( bytes );
fs.close();
}
这个基本逻辑在 300MB 以内都可以正常工作(甚至可能更远。虽然我应该测试一下,但现在我想起来了)。这篇文章写得相当快,所以可能会有一些错误,而且我确实缺少了一些东西,但你明白了。
如果这不起作用,我们需要您提供一些信息:
- 发布任何错误
- 追踪
file.size / 1024 / 1024 + "MB"
fs.close()
之后看看它在崩溃之前还能走多远 - 追踪
System.memory / 1024 / 1024 + "MB" after the
fs.close()` 这样我们就可以监控内存使用情况
对于 2 和 3,我们应该只需要崩溃发生之前的最后一个跟踪语句。
或者,您应该知道您将无法对应用程序中的 500MB 文件执行任何操作。由于其大小,Flash 根本不会加载它。我成功处理 300MB 视频文件的唯一原因是我们从磁盘流式传输它们,而不是将整个内容存储到内存中。
关于actionscript-3 - AIR (As3) - 通过 iPad 应用程序下载大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14583247/