Recursive Folder/Directory Copy with AS3 /Air - actionscript-3

Is it possible to use pause/resume function to this??
source.copyTo( destination );
It would be great if you can send it at the earliest.

I found one solution here CookBook from Adobe
private function copyInto(directoryToCopy:File, locationCopyingTo:File):void
{
var directory:Array = directoryToCopy.getDirectoryListing();
for each (var f:File in directory)
{
if (f.isDirectory)
copyInto(f, locationCopyingTo.resolvePath(f.name));
else
f.copyTo(locationCopyingTo.resolvePath(f.name), true);
}
}

Or you could just use the File.copyTo() method:
var source:File = new File();
source.resolvePath( 'sourceFolder' );
var destination:File = new File();
destination.resolvePath( 'destinationFolder' );
source.copyTo( destination );
If the directories are large and you don't want your app to be stuck waiting for the copy, you can use copyToAsync, which will cause the source file to dispatch Event.COMPLETE when the job's done.

Here is the modified code from above if anyone wants to copy the entire directory; empty folders and all. Notice the "copyEmptyFolders" parameter to be used in the arguments.
//Recursivley copies directory.
private static function copyInto(directoryToCopy:File, locationCopyingTo:File, copyEmptyFolders:Boolean=true):void
{
var directory:Array = directoryToCopy.getDirectoryListing();
for each (var f:File in directory)
{
if (f.isDirectory)
{
// Copies a folder whether it is empty or not.
if( copyEmptyFolders ) f.copyTo(locationCopyingTo.resolvePath(f.name), true);
// Recurse thru folder.
copyInto(f, locationCopyingTo.resolvePath(f.name));
}
else
f.copyTo(locationCopyingTo.resolvePath(f.name), true);
}
}

Related

How to write files to a specific directory?

I'm trying to let the user select a directory and then write files to that directory.
I have this code that lets a user browse for a directory:
var file:flash.filesystem.File = new flash.filesystem.File();
file.browseForDirectory("Select a directory");
file.addEventListener(Event.SELECT, selectHandler);
protected function selectHandler(event:Event):void {
// these contain the path where I want to save files to
Object(fileReference).url;
Object(fileReference).nativePath;
// how do I create a file in that directory?
}
How do I create a file in the directory that the user selects?
Your select handler code does not seem to be correct. You should get the reference of the Folder which is an object of the type File by doing event.currentTarget, and not Object or fileReference.
Next you can create a file using the FileStream class. Your selectHandler code should look like this:
protected function selectHandler(event:Event):void
{
var targetDirectory:File = event.currentTarget as File;
var file:File = targetDirectory.resolvePath("htmlFile.html");
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeUTFBytes("Any Text you want to create");
stream.close();
}
Will work in AIR projects.
Hope this answers your question.

Run an AS3 function only once

I'm making an AIR app and I would like to know if it's possible to run a function only once ?
If the user reboot his device and launch the app, the function won't be trigger again.
Thank you for your answers,
Since you're using adobe AIR, you have a few options.
Write a file that contains your save data.
Using AIR you can write a data file to the user's machine. This is more permanent than SharedObject's, which for various reasons can not work or persist long term.
You can actually serialize entire classes for easy retrieval of complex objects.
Here is an example of a class that managers a save file (for preferences or a game save etc):
package
{
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;
import flash.utils.Dictionary;
import flash.net.registerClassAlias;
public class SaveData
{
//a list of any vars you want to save.
public var firstRun:Boolean = true;
public var someVar:int = 1;
public var anotherVar:Dictionary;
//the file for the user save data
public static function getFile():File {
return File.applicationStorageDirectory.resolvePath("saveFile.data");
}
public static function loadFile():SaveData {
registerClassAlias("flash.utils.Dictionary", Dictionary); //you need to register any non-native classes you want to save
registerClassAlias("saveData", SaveData);
var data:SaveData
//check for a default save file in the application directory (optional, but sometimes it's nice to bundle a default with your application before the user saves their own data
var f:File = new File("app:/saveFile.data");
if(f.exists){
data = loadFromFile(f);
}else {
trace("Default File Doesn't Exist");
}
//check the user storage directory for a save file, and see if it's newer than the one in the application directory
var userFile:File = getFile();
if (userFile.exists) {
if (f.exists && f.modificationDate.time < userFile.modificationDate.time) {
trace("Local File is newer, load it");
data = loadFromFile(userFile);
}else {
trace("Default File is newer");
}
}else {
trace("Save File DOESN'T EXIST YET");
}
if (!data) {
//data didn't load, let's create a new save file
data = new SaveData();
saveToFile(data);
}
saveData = data; //assing to main static accessible var
return data;
}
private static function loadFromFile(f:File):SaveData {
var d:SaveData;
try{
var stream:FileStream = new FileStream();
stream.open(f, FileMode.READ);
d = stream.readObject() as SaveData;
stream.close();
trace("DATA LOADED: " + f.nativePath);
return d;
}catch (err:Error) {
trace("Error Loading Save Data: " + f.nativePath);
}
return null;
}
public static function saveToFile(saveData:SaveData):void {
var fileStream:FileStream = new FileStream();
fileStream.open(getFile(), FileMode.WRITE);
fileStream.writeObject(saveData);
fileStream.close();
}
}
}
Then to use it:
var saveData:SaveData = SaveData.loadFile();
if(saveData.firstRun){
//do you first run code
//now set first run to false
saveData.firstRun = false;
SaveData.saveFile(saveData);
}
use a SharedObject. There is another answer covering this, but since no example was given I'll give one:
var mySO:SharedObject = SharedObject.getLocal("yourAppNameHere");
if(mySO.data.hasHadFirstRun){
//the cookie exists
}else{
//the cookie hasn't indicated there has been a first run yet, so do whatever you need to do
//some code
mySO.data.hasHadFirstRun = true; //now that you've done whatever on the first run, let's save the cookie
mySO.data.flush(); //save (though it will save automatically I believe when you close the application
}
use SQLite.
AIR can create and read SQLite databases, if your application has a need to store other data that would make sense to live in a table structure, it might make sense for you to add on a table for storing user preferences and things like a first run flag - if you wouldn't use the database for anything else though, it would definitely be over-kill.
Find out more about SQLite in AIR here:
http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118666ade46-7d49.html

Folder in read-only mode after movement

Below code to move the folder from one place to another. This code will move the folder. But, the outcome leaves the folder in a read-only state. I tried moving the folder instead of copy-delete. Even that does not help in here. How to overcome this.?
function CopyFolder(){
try{
var fileSystem = new ActiveXObject("Scripting.FileSystemObject");
var sourceFolder = document.getElementById("source").value;
var DestnFolder = document.getElementById("destn").value;
var myFolder;
if (!fileSystem.FolderExists(DestnFolder))
{
fileSystem.CreateFolder(DestnFolder);
}
myFolder = fileSystem.GetFolder(sourceFolder);
myFolder.Copy(DestnFolder);
//myFolder = fileSystem.GetFolder(sourceFolder);
//myFolder.Delete();
myFolder = null;
fileSystem = null;
return DestnFolder;
}
catch(err)
{
alert("error in moving Incident folder to Zip");
}
}
It would be very helpful, If there is any code to remove all dependencies or clear all object which holds any relationship with the fodler(Or content in fodler).

File.copyTo keeps old file name

I try the following code to copy a selected file to the storage directory:
private function onAddFileClick():void
{
m__file = new File();
m__file.addEventListener(Event.SELECT, onFileSelect);
m__file.browseForOpen("Select a sound", [c__filter]);
}
private function onFileSelect(e:Event):void
{
var l__target:File = File.applicationStorageDirectory.resolvePath("test.snd");
m__file.copyTo(l__target, true);
}
The copy works but the target file's name keeps the original file's name. If I try to copy a file name "Kalimba.mp3", the copy will be named "Kalimba.snd" and not "test.snd" as expected. The problem is that after the copy, my reference to the target file does not lead to anything since its nativePath sticks to "test.snd" which does not exist.
I use AIR 3.6 with Flex 4.6.
Renaming is done with File.moveTo().
copy first and then use moveTo() to rename it. Unless just moving it will do it for you! Obviously ;)
So after you copy:
var sourceFile:File = File.applicationStorageDirectory;
sourceFile = sourceFile.resolvePath("Kalimba.snd");
var destination:File = File.applicationStorageDirectory;
destination = destination.resolvePath("test.snd");
try
{
sourceFile.moveTo(destination, true);
}
catch (error:Error)
{
trace("Error:" + error.message);
}

Zip a folder in as3 Adobe AIR

I have created an Air app that after user interaction will creat a folder with bmp's, xml and text doc's.
All works apart from making the final zip which needs to be automatic.
I have been looking for a solution to this but cant find it.
Perhaps I am just not seeing it, and if so, can someone show me please.
My original posting on this is here ---
zip many files with Air as3 flash
The closest thing I have found was this one --- zip a folder using fzip
But for some reason my coment was deleted which was --
I like this. It is the closest I have come to a working solution to my own problem. That said, I tested this and it works nicely as is. Can this script be moded to run without interaction??? I am in need of it for a program that I have written. ANY asistance is welcom........ apart from just pointing me to Adobe referance as it dose not have anything like what I need. (well that I can see or find)
So now I am re-asking the comunity.
For some reason it will work with manual selection and manual save-to, but not aotonomusly.
There must be a workround to this even if it requires another full page of script.
====================================================================
UPDATE:
For closing this off, I have finally got my solution.
You can find it here. "zip file contents have no data".
Hope that my problem can help someone in the future.
Try using the as3 commons zip library.
http://www.as3commons.org/as3-commons-zip/index.html
In order to do this you're going to need to load your directory, loop through all its contents and load each asset.
This code snippet includes a bulk loader to handle that for you.
warning
I pulled most of this code out of a project where I was doing something similar but I have not tested it as is. There may be some syntax errors!
private var zip:Zip;
zip = new Zip();
zip.addEventListener(IOErrorEvent.IO_ERROR, this.createNewZip); //creates a new zip
zip.addEventListener(Event.COMPLETE, handleZipLoaded); //loads the current zip, this is not shown here
zip.load(new URLRequest(File.applicationStorageDirectory.resolvePath("myZip.zip").url)); //path to your zip file
Method to create your new zip file
private function createNewZip(e:IOErrorEvent):void{
trace("no zip");
var stream:FileStream = new FileStream();
stream.open(File.applicationStorageDirectory.resolvePath("myZip.zip"), FileMode.WRITE);
zip.serialize(stream);
stream.close();
}
You can use this to add all items in a directory to your zip file.
private function addDirToZip():void{
var f:File = File.resolvePath("Your Dir");
//this will be called when your directory listing has loaded
f.addEventListener(FileListEvent.DIRECTORY_LISTING, handleDirLoaded);
//you can also get the dir listing inline and not use a listener
//doing it async will prevent ui lock
f.getDirectoryListingAsync();
}
Next your going to need to load all of the files
protected function handleDirLoaded(e:FileListEvent):void{
loadExternal = new Vector.<File>; //vector used to keep a handle on all files
e.target.removeEventListener(FileListEvent.DIRECTORY_LISTING, handleDirLoaded);
for(var i:int = 0 ; i < files.length ; i++){
var f:File = files[i] as File;
if(f.extension == "File Types you want"){ //you can do some file type checking here
loadExternal.push(f);
}
}
//start loading in the files
loadFile();
}
This will go through the loadExternal vector and load all files
private function loadFile():void{
currentFile = loadExternal.shift(); //returns the first item off the array
//load the file
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, handleLoaded);
l.load(new URLRequest(currentFile.url));
}
Once each item is loaded you can store it for addition into the zip
private function handleLoaded(e:Event):void{
var l:Loader = e.target.loader as Loader;
l.contentLoaderInfo.removeEventListener(Event.COMPLETE, handleLoaded);
//storing everything in a dictionary
assets[currentFile.name] = l.content;
//if we still have items to load go and do it all again
if(loadExternal.length != 0){
loadFile();
} else {
//now all files are loaded so lets add them to the zip
addAssetsToZip();
}
}
This is where all the loaded files actually get put into the zip and it is saved
private funcion addAssetsToZip():void{
for(var fileName:String in assets){
var ba:ByteArray = new ByteArray(); //going to write this to the zip
//make an object that holds the data and filename
var data:Object = {};
data.name = fileName;
data.content = assets[fileName];
ba.writeObject(data);
//write this file to the zip
zip.addFile(key, ba, false);
}
//and finally save everything out
zip.close();
var stream:FileStream = new FileStream();
stream.open(File.applicationStorageDirectory.resolvePath("myZip.zip"), FileMode.WRITE);
zip.serialize(stream);
stream.close();
}