zip many files with Air as3 flash - actionscript-3

OK . I am reasonably capable, but still learning.
This is for a program I am writing in AIR.
Basicaly I am needing to grab the files of mixed type and content from a given folder and zip them.
Here is the code I have put together and it sort of works.
Problem I have is that the files in the zip all have zero byte's in them. Efectivly empty.
What have I missed or done wrong?
import flash.filesystem.File;
import flash.events.Event;
import deng.fzip.*;
var directory:File = File.desktopDirectory.resolvePath("FOLDER/");
var zip:FZip = new FZip();
var files:Array = directory.getDirectoryListing();
for(var i:uint = 0; i < files.length; i++)
{
zip.addFile(files[i].name, files[i].data);
trace(files[i].name);
}
var ba:ByteArray = new ByteArray();
zip.serialize(ba);
ba.position = 0;
var finalZIP:File = File.desktopDirectory.resolvePath("TEST.zip");
var fs:FileStream = new FileStream();
fs.open(finalZIP, FileMode.WRITE);
fs.writeBytes(ba);
fs.close();
EDIT=:
While running the code, I have noticed this in the errors panel.
....app\scripts_classes\deng\fzip\FZipFile.as, Line 362 Warning: 1106: Empty statement found where block of code expected. Did you type ';' accidentally?
and it seems to be fine from what I can see, but then I did not write the Fzip script.

File.data is only populated after a call to File.load.
For synchronous loading of bytes, look at FileStream. These docs give a rundown.

Related

How do I write a huge bytearray to file progressively and avoid that dreaded memory error

I'm working on an Air project that downloads huge (zip) files, then unzips them and finally deletes the original .zip file it downloaded.
Everything's running smoothly except when I want to write the unzipped file to disk.
Trouble is, I keep running into the issue of this little monster of an error.
Error: Error #1000: The system is out of memory.
Here's the part of the code that is giving me grief. This works perfectly when the file is small (tested on a 3 MB file) but as soon as I try one of my large files (458 MB), I get the error.
private function unzipFile()
{
var pulledFile:FZipFile;
var index:int = 0;
var chunkSize:int = 1000000;
Console.log("Unzipping file...");
var zip:FZip = new FZip();
zip.addEventListener(Event.COMPLETE, onUnzipComplete);
var fileStream:FileStream = new FileStream();
zip.load(new URLRequest(urlToUnzip));
function onUnzipComplete(e:Event)
{
pulledFile = zip.getFileAt(0);
var file:File = File.documentsDirectory.resolvePath(pulledFile.filename);
fileStream.openAsync(file, FileMode.WRITE);
writeChunk();
}
function writeChunk()
{
var bytesToGet:int = pulledFile.content.bytesAvailable;
if (bytesToGet > chunkSize)
bytesToGet = chunkSize;
Console.log("Writing chunk " + (int((pulledFile.content.length - pulledFile.content.bytesAvailable) / chunkSize) + 1) + " of " + (int(pulledFile.content.length / chunkSize) + 1));
var fileData:ByteArray = new ByteArray();
pulledFile.content.readBytes(fileData, 0, bytesToGet);
fileStream.writeBytes(fileData, 0, fileData.length);
if (index < pulledFile.content.bytesAvailable)
{
writeChunk();
index += bytesToGet;
}
else
{
fileStream.close();
Console.log("Unzipping complete");
}
}
}
The code crashes specifically on the line
var bytesToGet:int = pulledFile.content.bytesAvailable;
How do I still progressively write content to a file without knowing how many bytes are available to me? If I don't have access to the bytesAvailable property, how do I know I'm done writing?
I'm using the FZip library for decompression.
This was tough, but I figured it out. The trick is to use the "serialize" method of the FZip and avoid touching the properties of the content ByteArrayaltogether.
Here's the final code that works.
private function unzipFile()
{
var pulledFile:FZipFile;
Console.log("Decompressing file...");
var zip:FZip = new FZip();
zip.addEventListener(Event.COMPLETE, onUnzipComplete);
var fileStream:FileStream = new FileStream();
zip.load(new URLRequest(urlToUnzip));
function onUnzipComplete(e:Event)
{
pulledFile = zip.getFileAt(0);
var file:File = File.documentsDirectory.resolvePath("Easywatch/" + pulledFile.filename);
fileStream.open(file, FileMode.WRITE);
zip.serialize(fileStream, false);
fileStream.close();
Console.log("Decompression complete");
}
}

Flash ActionScript 3: Reading text from a file

There's my problem: I want to load the data from a text file (Named "myText.txt") with Flash CS5.5 . It contains some lines, and I want to store these lines in an Array. This is what I've got from now:
var myLoader:URLLoader = new URLLoader(new URLRequest("myText.txt");
var myArray:Array = new Array();
myLoader.addEventListener(Event.COMPLETE, loadComplete(myArray));
function loadComplete(myArray:Array):Function {
return function(e:Event):void {
myArray = myLoader.data.split("\n");
for(var i:int = 0; i < myArray.length; ++i){
trace(myArray[i]); // To check if it works at this point
}
}
}
for(var i:int = 0; i < myArray.length; ++i){
trace(myArray[i]); // To check if it gets modified
}
The fact is that the fist part works, it loads the text file and it stores in myArray, and traces it; but it stores only in the local version of myArray, it doesn't modify the reference, so the for outside of the function doesn't trace anything.
I had read that Arrays were passed by reference in flash, so I don't understand why it doesn't work.
I would appreciate the help.
EDIT
The thing now is that this is just a test file, I want this code to be in a function that I will use a lot. The ideal would be to have a static function in an AS Class File named "Utils", with other useful functions. The code of the "Utils.as" file would be like this:
package Include {
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.events.Event;
public class Utils {
public function Utils() {
}
public static function fileToArray(path:String):Array {
var linesArray = new Array();
// Code to load the file stored in 'path' (the 'path' String
// also has the name of the file in it), split by '\n' and store every line
// in the 'linesArray' Array.
// Example: path = "file:////Users/PauTorrents/Desktop/program/text.txt"
return linesArray;
}
// other functions
}
}
Thanks for the help.
A few things need addressing here.
First, your for loop at the end will always run before the load completes, so it will never trace anything. AS3 does not lock the thread when a URLoader loads, so it will move on with the rest of the code in the block while it waits to load the file.
Second, it's really ugly returning an annonumous function as the result of your load complete handler.
Here is how I would do this:
var myLoader:URLLoader = new URLLoader(new URLRequest("myText.txt");
var myArray:Array = new Array();
myLoader.addEventListener(Event.COMPLETE, loadComplete, false, 0, true);
function loadComplete(e:Event):void{
myArray = myLoader.data.split("\n");
for(var i:int = 0; i < myArray.length; ++i){
trace(myArray[i]); // To check if it works at this point
}
//now move on with the rest of your program/code
}

XMP data encrypted on Canon EOD D1000

I have a question regarding encryption, once again this relates to reading serial numbers from the aux:SerialNumber namespace.
When I open my file in AS3 from photos of the Canon EOS D1000, it can't read this bit in the ByteArray var i:int = p.search('<x:xmpmeta xmlns:x="\'dobe:ns:meta/\''); because well its encrypted.
What makes this interesting is, if I open the file in Photoshop then save it and close it the XMP data is correct and my app can read it.
My question would be how would I decrypt the XMP data from within AS3? Is there a way to do it. Or another way to read it?
This is the method I use:
private function getXMP(ba:ByteArray):XML
{
var LP:ByteArray = new ByteArray();
var PACKET:ByteArray = new ByteArray();
var l:int;
ba.readBytes(LP, 2, 2);
//http://www.adobe.com/devnet/xmp.html read part 3: Storage in Files.
//that will explain the -2 -29 and other things you see here.
l = LP.readInt() - 2 -29;
ba.readBytes(PACKET, 33, l);
var p:String = trim(""+PACKET);
var i:int = p.search('<x:xmpmeta xmlns:x="adobe:ns:meta/"');
//Delete all in front of the XMP XML
p = p.substr(i);
//For some reason this left some rubbish in front, so I'll hardcode it out for now
var ar:Array = p.split('<');
var s:String = "";
var q:int;
var j:int = ar.length;
for(q=1;q<j;q++)
{
s += '<'+ar[q];
}
i = s.search('</x:xmpmeta>');
i += ('</x:xmpmeta>').length;
s = s.slice(0,i);
//Delete all behind the XMP XML
//trace(s);
return XML(s);
}

Data Corruption Bug in flash.filesystem.FileStream or Developer Error?

I was implementing some data structure backed by a file and used random read and write access to update the structure.
And stumbled over either a bad bug or my code is not correct.
After hours of checking and debugging it boiled down to the following snippet, that isolates the erroneous? behavior.
Inside the loop i am supposedly writing, reading and overwriting the byte at position 0.
You would expect, after the code has run, to end up with a file containing 1 byte 0x39.
Instead the file grows, the writing is not happening at position 0 but at EOF. Runnig the code several times will result in the file growing larger and larger.
If you comment the line fs.readByte(); out, the code is behaving as expected.
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
var tf:File=File.userDirectory.resolvePath("test.txt");
var fs:FileStream=new FileStream();
fs.open(tf,FileMode.UPDATE);
for (var i=0;i<10;i++){
fs.position=0;
fs.writeByte(0x30+i);
fs.position=0;
fs.readByte(); //if you comment this line out, results are as expected
}
fs.close();
trace(tf.size);
Please, if anybody is testing this and come to the same conclusion as me, that this is
a bug, please vote this bug at adobe's bugbase, so they hopefully consider fixing it.
VOTE BUG at ADOBE's bugbase!
Otherwise I would appreciate if someone could tell me what I am doing wrongly.
tx leo
EDIT: some clarification
//Alright, since the loop example caused some confusion about whether or not
//there would be use for such code I'll try with another snippet, that is hopefully
//closer to some real application.
//
//The code updates some bytes in the file
//and afterwards reads some bytes somewhere else in the file, eg. a header field.
//This time not in a loop but triggered by a timer, which could of course also
//be some event handler.
//
//I hope this makes the problem more apparent
import flash.utils.ByteArray;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
var tf=File.userDirectory.resolvePath("test.txt");
var fs:FileStream=new FileStream();
var timerID:int;
var count:int=0;
var fileAction:Function=function(){
var dataToWrite:ByteArray=new ByteArray();
var dataToRead:ByteArray=new ByteArray();
dataToWrite[0]=0x31;
dataToWrite[1]=0x32;
fs.position=2;
fs.writeBytes(dataToWrite);
fs.position=0;
fs.readBytes(dataToRead,0,2); //this read will corrupt the previous write!!!
//instead updating two bytes at 0x02
//it will write to the end of file,
//appending two bytes
count++;
if (count>10) {
clearInterval(timerID);
fs.close();
trace("Excpected file size: 4")
trace("Actual size: "+tf.size);
}
}
fs.open(tf,FileMode.UPDATE);
fs.position=0;
fs.writeByte(0x30);
fs.writeByte(0x30);
timerID=setInterval(fileAction,100);
While I agree that your expectations are founded based on the documentation, I'm not sure what use it is to read what was just written, especially within a loop on a FileStream object, as it is an unnecessarily performance hit. Can you provide a usecase?
Perhaps there are undocumented restrictions within the FileStream API that avoid excessive slow downs or that impede synchronous or asynchronous processing.
If you must read a byte after it's been written within a loop, you can do so with a ByteArray object, which would then be written once to the FileStream
package
{
//Imports
import flash.display.Sprite;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
import flash.utils.ByteArray;
//Class
public class Main extends Sprite
{
//Constructor
public function Main():void
{
var ba:ByteArray = new ByteArray();
for (var i:uint = 0; i < 10; i++)
{
ba.position = 0;
ba.writeByte(0x30 + i);
ba.position = 0;
ba.readByte();
}
var fs:FileStream = new FileStream();
var tf:File = File.desktopDirectory.resolvePath("test.txt");
fs.open(tf, FileMode.UPDATE);
fs.writeBytes(ba);
fs.close();
trace(tf.size);
}
}
}

Actionscript 3 does not work .. it didn't give errors

I am creating a clock using this code:
var date:Date = new Date();
var time:Timer = new Timer(1000);
time.addEventListener(TimerEvent.TIMER, actualiser);
time.start();
function actualiser(e:TimerEvent){
date = new Date();
var s:uint = date.seconds;
var m:uint = date.minutes;
var h:uint = date.hours;
sec_mc.rotation =(s * 6);
min_mc.rotation =(m * 6);
heur_mc.rotation =(h * 30) +m/2;
}
But, it seems that the code is not executing, I can’t even trace anything written in constructor of my document class. When I run it nothing happens and when I try to debug I get the alert message saying:
You cannot debug this SWF because it does not contain ActionScript
What can be wrong?
Try to check the code in a new fla. Write the following in your 1st frame action panel. This does give proper output and you can see the traces in the output panel. There is no issue with the code logic. Might be some issue with the movieclip being used.
var date:Date = new Date();
var time:Timer = new Timer(1000);
time.addEventListener(TimerEvent.TIMER, actualiser);
time.start();
function actualiser(e:TimerEvent){
date = new Date();
var s:uint = date.seconds;
var m:uint = date.minutes;
var h:uint = date.hours;
trace(h+":"+m+":"+s);
}
In case of CS5 , try the following steps :
WINDOWS:
1. Quit Flash
2. In a text editor, open the jvm.ini file from the following location:
2.1. Windows XP: System Hard Disk\Documents and Settings\user\Local Settings\Application Data\Adobe\Flash CS5\language\Configuration\ActionScript 3.0\jvm.ini
2.2. *Windows Vista or Windows7:* System Hard Disk\Users\user\AppData\Local\Adobe\Flash CS5\language\Configuration\ActionScript 3.0\jvm.ini
(You might need to turn on “show hidden files”)
3. Change -Xmx128m to -Xmx256m and save the file.
EDIT: Uhm. Is that all you have? Because you need to import the needed packages, etc. Also, are you sure you linked everything up?