Actionscript 3 如何在Flex中显示文件流的保存进度?

Actionscript 3 如何在Flex中显示文件流的保存进度?,actionscript-3,apache-flex,file-io,asynchronous,progress,Actionscript 3,Apache Flex,File Io,Asynchronous,Progress,我正在制作一个简单的工具,让用户最终将图像保存到磁盘上。 为此,我使用了FileStream类及其writeBytes()方法 这工作得很好。当我试图用一个简单的mx:ProgressBar显示保存进度时,出现了问题。我试过一些方法,但似乎都不管用 下面是ActionScript的一段代码: private function save(file:File, image:MyImageClass):void { var data:BitmapData = new BitmapData(wi

我正在制作一个简单的工具,让用户最终将图像保存到磁盘上。 为此,我使用了
FileStream
类及其
writeBytes()
方法

这工作得很好。当我试图用一个简单的
mx:ProgressBar
显示保存进度时,出现了问题。我试过一些方法,但似乎都不管用

下面是ActionScript的一段代码:

private function save(file:File, image:MyImageClass):void {
    var data:BitmapData = new BitmapData(width, height, true, 0x000000);
    image.draw(data, _cols);
    var bytes:ByteArray = new PNGEncoder().encode(data);
    fileStream = new FileStream();
    fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
    fileStream.addEventListener(Event.CLOSE, onClose);
    try {
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(bytes);
    } catch (e:Error) {
        Alert.show("Error trying to save the image: " + e.message);
    } finally {
        fileStream.close();
    }
}

private function onProgress(event:OutputProgressEvent):void {
    var progressRatio:Number = (1 - (event.bytesPending / event.bytesTotal));
    progressBar.setProgress(progressRatio, 1);
    trace(progressRatio);
    if (event.bytesPending == 0)
        event.target.close();
}

private function onClose(event:Event):void {
    trace("closed");
}
以及进度条的mxml:

<mx:ProgressBar id="progressBar" mode="manual"/>

执行此操作时,我得到了一个冻结的接口,当文件完全保存时,该接口被释放,并且在控制台上我同时获得了所有跟踪。进度条保持在0%,直到界面解冻并变为100%

我知道Flash是单线程的,但我认为
FileStream.openAsync()
方法应该做一些肮脏的工作,让我的接口负责。完成这项简单且(我认为)普通的任务应该不会那么难

问题是:我做错了什么


提前感谢

正在保存的文件有多大

就保存文件而言,您的代码似乎很好。然而,我怀疑实际需要很长时间的是将文件编码为PNG格式。不幸的是,
PNGEncoder
没有发送任何进度事件。但是你应该检查一下,或者考虑使用ActionScript工作人员在不同的线程中进行编码。

快速证明方法:在编码到PNG之前/之后添加跟踪语句。大延迟是对应于此阶段,还是对应于实际保存


如果这没有帮助,请指定文件的大小,以及您是获得0、1还是多个输出进度事件。

要保存的文件有多大

就保存文件而言,您的代码似乎很好。然而,我怀疑实际需要很长时间的是将文件编码为PNG格式。不幸的是,
PNGEncoder
没有发送任何进度事件。但是你应该检查一下,或者考虑使用ActionScript工作人员在不同的线程中进行编码。

快速证明方法:在编码到PNG之前/之后添加跟踪语句。大延迟是对应于此阶段,还是对应于实际保存


如果这没有帮助,请指定文件的大小,以及您是获得0、1还是多个输出进度事件。

我同意Sunil,但我想补充一两件事

首先,我建议使用
BitmapData
类的新方法对图像进行编码,因为它更快更容易。因此,您的代码将更改为以下内容:

var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = data.encode(data.rect, new PNGEncoderOptions());
bytes.position = 0;
while(bytes.bytesAvailable > 0) {
    fileStream.writeByte(bytes.readByte());
    trace("progress:", bytes.position / bytes.length * 100); // multiply by 100 for percentage
}
您可以跟踪文件的编写进度(尽管我怀疑这不会花费太多时间,正如Sunil所说),如下所示:

var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = data.encode(data.rect, new PNGEncoderOptions());
bytes.position = 0;
while(bytes.bytesAvailable > 0) {
    fileStream.writeByte(bytes.readByte());
    trace("progress:", bytes.position / bytes.length * 100); // multiply by 100 for percentage
}

请注意,这种方法需要一名工作人员,否则只有在保存完成后,进度才会直观地更新。

我同意Sunil的观点,但我想补充一两点

首先,我建议使用
BitmapData
类的新方法对图像进行编码,因为它更快更容易。因此,您的代码将更改为以下内容:

var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = data.encode(data.rect, new PNGEncoderOptions());
bytes.position = 0;
while(bytes.bytesAvailable > 0) {
    fileStream.writeByte(bytes.readByte());
    trace("progress:", bytes.position / bytes.length * 100); // multiply by 100 for percentage
}
您可以跟踪文件的编写进度(尽管我怀疑这不会花费太多时间,正如Sunil所说),如下所示:

var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = data.encode(data.rect, new PNGEncoderOptions());
bytes.position = 0;
while(bytes.bytesAvailable > 0) {
    fileStream.writeByte(bytes.readByte());
    trace("progress:", bytes.position / bytes.length * 100); // multiply by 100 for percentage
}

请注意,这种方法需要一名工作人员,否则只有在保存完成后,进度才会直观地更新。

Sunil是正确的。写这个文件几乎不需要花一点时间。它正在解码阻止应用程序的字节数组。我实现了以下代码来测试它

private function save(file:File):void
{
    var bytes:ByteArray = new ByteArray();
    //233348 - very fast (requires 6000 x 10000 bitmap pixels)
    //252790 - very fast (requires 6500 x 10000 bitmap pixels)
    //2488990 - need a whole magnitude more of data in order to show the progress messages
    for (var i:int = 0; i < 2488990; i++)
    {
        bytes.writeByte(1);
    }
    var fileStream:FileStream = new FileStream();
    fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
    fileStream.addEventListener(Event.CLOSE, onClose);
    try {
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(bytes);
    } catch (e:Error) {
        //Alert.show("Error trying to save the image: " + e.message);
    } finally {
        fileStream.close();
    }
}
私有函数保存(文件:文件):无效
{
变量字节:ByteArray=newbytearray();
//233348-非常快(需要6000 x 10000位图像素)
//252790-非常快(需要6500 x 10000位图像素)
//2488990-需要更多的数据才能显示进度消息
对于(变量i:int=0;i<2488990;i++)
{
字节。写入字节(1);
}
var fileStream:fileStream=newfilestream();
fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS,onProgress);
addEventListener(Event.CLOSE,onClose);
试一试{
openAsync(文件,FileMode.WRITE);
fileStream.writeBytes(字节);
}捕获(e:错误){
//Alert.show(“尝试保存图像时出错:+e.message”);
}最后{
fileStream.close();
}
}

您需要在解码任务上使用进度指示器,而不是在文件写入任务上使用进度指示器。Workers似乎是解决这一问题的最佳解决方案,但这取决于您需要以哪个版本的运行时为目标。

Sunil是正确的。写这个文件几乎不需要花一点时间。它正在解码阻止应用程序的字节数组。我实现了以下代码来测试它

private function save(file:File):void
{
    var bytes:ByteArray = new ByteArray();
    //233348 - very fast (requires 6000 x 10000 bitmap pixels)
    //252790 - very fast (requires 6500 x 10000 bitmap pixels)
    //2488990 - need a whole magnitude more of data in order to show the progress messages
    for (var i:int = 0; i < 2488990; i++)
    {
        bytes.writeByte(1);
    }
    var fileStream:FileStream = new FileStream();
    fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
    fileStream.addEventListener(Event.CLOSE, onClose);
    try {
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(bytes);
    } catch (e:Error) {
        //Alert.show("Error trying to save the image: " + e.message);
    } finally {
        fileStream.close();
    }
}
私有函数保存(文件:文件):无效
{
变量字节:ByteArray=newbytearray();
//233348-非常快(需要6000 x 10000位图像素)
//252790-非常快(需要6500 x 10000位图像素)
//2488990-需要更多的数据才能显示进度消息
对于(变量i:int=0;i<2488990;i++)
{
字节。写入字节(1);
}
var fileStream:fileStream=newfilestream();
fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS,onProgress);
addEventListener(Event.CLOSE,onClose);
试一试{
openAsync(文件,FileMode.WRITE);
fileStream.writeBytes(字节);
}捕获(e:错误){
//Alert.show(“尝试保存图像时出错:+e.message”);
}最后{
fileStream.close();
}
}

您需要在解码任务上使用进度指示器,而不是在文件写入任务上使用进度指示器。Worker似乎是解决这一问题的最佳方案,但这取决于您需要以哪个版本的运行时为目标。

只是一个更正;Flash播放器不是单线程的。虽然他们不给progra