as3 selecting a file dynamically - actionscript-3

i need to select a video file and convert it to a byte array. the file i am trying to select has been recorded by the cameraUi interface. i can get the path to the file using
fileName = media.file.url;
readFileIntoByteArray(filePath, inBytes);
when i am passing it into the byte array i need to select directory first and then pass in the the rest of the path.
private function readFileIntoByteArray(fileName:String, data:ByteArray):void
{
var inFile:File = File.userDirectory;
inFile = inFile.resolvePath(fileName);
trace (inFile.url);
inStream.open(inFile , FileMode.READ);
inStream.readBytes(data);
}
this leads to duplication of the first part of the path.
i want to keep this dynamic as it will be run on different devices. i hard coded the file into the the variables section of flash debugger and it worked also i get an error if i leave out file.userDirectory
thanks in advance any help would be appreciated

You should always use File.applicationStorageDirectory instead of File.userDirectory. Due to security risk will vary to vary different device. File.applicationStorageDirectory will work any device.
Robust way of working with filepath
var firstPartPath:String = File.applicationStorageDirectory.nativePath;
var fullPath:String = File.applicationStorageDirectory.resolvePath("fileName.jpg").nativePath;
var expectedPath:String = fullPath.replace(firstPartPath,""); // "/fileName.jpg"
Here expectedPath value you should pass around your project instead of hard code value like c:\users\XXXX\ and save into database also use expectedPath value.
For latter access file just pass only expectedPath.
var inFile:File = File.applicationStorageDirectory.resolvePath(expectedPath);
Needn't worry about forward and backword slashes. File resolvePath() take care for you.
private function readFileIntoByteArray(fileName:String, data:ByteArray):void
{
var inFile:File = File.applicationStorageDirectory.resolvePath(fileName);
trace (inFile.url);
trace (inFile.nativePath);
trace (inFile.exists); //if file present true else false.
inStream.open(inFile , FileMode.READ);
inStream.readBytes(data);
}

Related

AS3 SharedObject read/write file location change

I’m using the following AS3 code to write and read data in two arrays to a local file, using Animate CC 2019 on Windows 10 and AIR 30.0 for Desktop/Flash (.swf) publishing settings. I use two input text boxes, input1 & input2, to add new data to the arrays.
When I test the FLA, the data file created has a .sol extension and is placed in a folder path:
C:\Users\username\AppData\Roaming\FLA filename\Local Store#SharedObjects\FLA filename.swf\
If I publish and install the program using an .air installer package, the exact same file, in the same folder path, is also accessed by the installed version of the program. Same location is used if I install on another computer running Windows 7, so the file location seems pretty consistent.
Question:
How can I force the code to save to a different location on the local hard drive on Windows? For example, in the documents folder or to create a new folder on the system drive and save the file there? Or, even better, prompt the user to choose the folder and file himself?
Please consider I’m looking for an answer using SharedObject, if possible, and not alternative methods like URLLoader, File, FileStream, FileMode. The reason is this way I can store multiple array contents in a file, without having to deal with the in-file data arrangement. So, I can read back the data for each array easily as shown below.
Thanks in advance
This is the code I use to access the local file:
var datavariable:SharedObject = SharedObject.getLocal("filiename");
var data1:Array = new Array ();
var data2:Array = new Array ();
btn_read.addEventListener(MouseEvent.CLICK, readfromfile);
btn_write.addEventListener(MouseEvent.CLICK, writetofile);
btn_new.addEventListener(MouseEvent.CLICK, newentry);
//To add new data from input text boxes to the arrays:
function newentry(e:Event):void
{
data1.push(input1.text);
data2.push(input2.text);
}
//To write to the local file:
function readfromfile(e:Event):void
{
data1 = datavariable.data.d1
data2 = datavariable.data.d2
}
//To read from the local file:
function writetofile(e:Event):void
{
datavariable.data.d1 = data1
datavariable.data.d2 = data2
datavariable.flush();
}
I don't know of a way of changing the shared object storage location. That mechanism is designed to be abstracted out from the developer.
Since you are using AIR, you can actually forget shared objects, and just write your own files anywhere your app has permission to do so. You can do this using the same format as shared object and don't have to worry about in file data arrangement (you save an object, you read back an object - just like Shared Object does), the only difference is you load/save the file where you choose.
Here is an example:
function writetofile(e:Event):void
{
//create an object that holds your data, this will act the same as the 'data' value of a shared object
var saveObject = {
d1: data1,
d2: data2
}
//using the File and FileStream classes to read/save files
var file:File = File.applicationStorageDirectory.resolvePath("saveData.data"); //or where and whatever you want to store and call the save file
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeObject(saveObject); //write the object to this file
fileStream.close(); //close the File Stream
}
function readfromfile(e:Event):void
{
var file:File = File.applicationStorageDirectory.resolvePath("saveData.data");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var savedObject = fileStream.readObject();
fileStream.close();
data1 = savedObject.d1;
data2 = savedObject.d2;
}
If you want to save complex objects (objects that aren't primitives), you need to register the class first. This goes for shared objects as well. See this answer for example of that.

Outputting an uint / Number value as a String in ActionScript3

Let me preface this by stating that I am not terribly familiar with ActionScript, so forgive any seemingly obvious things that I may be missing.
I current have a very simple function with an AS3 application that will output a file when a button is clicked using a FileReference object as seen below :
//Example download event
public function download(event:MouseEvent):void
{
//Build a simple file to store the current file
var outputFile:FileReference = new FileReference();
//Perform a function to build a .wav file from the existing file
//this returns a ByteArray (buffer)
downloadBuffer = PrepareAudioFile();
//Attempt to build the filename (using the length of bytes as the file name)
var fileName:String = downloadBuffer.length.toString() + ".wav";
//Save the file
audioFile.save(downloadBuffer, fileName);
}
There appears to be an error occurring somewhere within here that is resulting in the File not being outputted at all when I attempt to concatenate the file name as seen above. However, if I replace the fileName variable with a hard-coded option similar to the following, it works just fine :
audioFile.save(downloadBuffer, "Audio.wav");
Ideally, I would love to derive the duration of the file based on the length of the byteArray using the following :
//Get the duration (in seconds) as it is an audio file encoded in 44.1k
var durationInSeconds:Number = downloadBuffer.length / 44100;
//Grab the minutes and seconds
var m:Number = Math.floor(durationInSeconds / 60);
var s:Number = Math.floor(durationInSeconds % 60);
//Create the file name using those values
audioFile.save(downloadBuffer, m.toString() + "_" + s.toString() + ".wav");
Any ideas would be greatly appreciated.
Where is the problem other than missing the parentheses in m.toString()?
Aren't you missing a .lenght before the division of downloadBuffer as well?
I was finally able to come up with a viable solution that required explicit typing of all of the variables (including using a separate variable for the .toString() operations) as seen below :
public function download(event:MouseEvent):void
{
//Build a simple file to store the current file
var outputFile:FileReference = new FileReference();
//Perform a function to build a .wav file from the existing file
//this returns a ByteArray (buffer)
downloadBuffer = PrepareAudioFile();
//When accessing the actual length, this needed to be performed separately (and strongly typed)
var bufferLength:uint = downloadBuffer.length;
//The string process also needed to be stored in a separate variable
var stringLength:String = bufferLength.toString();
//Use the variables to properly concatenate a file name
var fileName:String = dstringLength + ".wav";
//Save the file
audioFile.save(downloadBuffer, fileName);
}
It's bizarre that these had to explicitly be stored within separate values and couldn't simply be used in-line as demonstrated in the other examples.

Flash Builder will not read local JSON file . .

So I've tried to build a small utility to view the contents of a JSON file in an easy-to-understand manner (for non-tech people).
I have Googled far and wide, high and low, but every example that shows how to consume a JSON file in Flash Builder uses the HTTP service, pointing to a file on the web.
Here I am, sitting in front of my MacBook, wondering why I can't make this work. In the documentation I've found (sort of relating to this issue), they always show Windows examples, and they seem to work fine:
C://me/projects/json/my_json.json
Perhaps I'm completely missing the obvious, but is this possible on a Mac as well?
I've tried
file:///Users/me/projects/json/my_json.json
That doesn't work. I've tried some "resolve to path" syntax, but the HTTP service does not seem to allow for anything but file paths in quotes.
Would anyone be able to pint me in the right direction?
Use the File API. It's really easy, here's a quick code sample:
// Get a File reference, starting on the desktop.
// If you have a specific file you want to open you could do this:
// var file:File = File.desktopDirectory.resolvePath("myfile.json")
// Then skip directly to readFile()
var file:File = File.desktopDirectory;
// Add a listener for when the user selects a file
file.addEventListener(Event.SELECT, onSelect);
// Add a listener for when the user cancels selecting a file
file.addEventListener(Event.CANCEL, onCancel);
// This will restrict the file open dialog such that you
// can only open .json files
var filter:FileFilter = new FileFilter("JSON Files", "*.json");
// Open the file browse dialog
file.browseForOpen("Open a file", [filter]);
// Select event handler
private function onSelect(e:Event):void
{
// Remove listeners on e.currentTarget
// ...
// Cast to File
var selectedFile:File = e.currentTarget as File;
readFile(selectedFile);
}
private function onCancel(e:Event):void
{
// Remove listeners on e.currentTarget
// ...
}
private function readFile(file:File):void
{
// Read file
var fs:FileStream = new FileStream();
fs.open(selectedFile, FileMode.READ);
var contents:String = fs.readUTFBytes(selectedFile.size);
fs.close()
// Parse your JSON for display or whatever you need it for
parseJSON(contents);
}
You hinted at this in your post about examples being for Windows and you being on a Mac but I'll state it explicitly here: you should always use the File API because it is cross platform. This code will work equally well on Windows and Mac.

Flex: Export Excel via Servlet

I want a user to press an excel button and get prompted to download an excel file. I normally do it like this:
var dest:String = excelEndpoint;
var request:URLRequest = new URLRequest();
request.url = dest;
fr.download( request,'Locates.xls' );
fr.addEventListener(HTTPStatusEvent.HTTP_STATUS, handleStatus);
fr.addEventListener(IOErrorEvent.IO_ERROR, handleErr);
However, now I need to pass an object to the servlet. Seeing that you can't do that with URLRequest I tried using HTTPService:
var service:HTTPService = new HTTPService();
service.url = excelEndpoint;
service.method = "POST";
service.showBusyCursor = true;
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send( myObject);
Now I can get my data (myObject) to the servlet successfully, but I don't get prompted for a download.
How can I do that? Is it even possible with HTTPService?
Thanks for any helpful tips.
I don't think there is anything you can do w/ a remote request from the Flash Player to prompt the user to download something. The way I have done this in the past is two fold:
Remote request pings server that generates the excel file and saves it to a temporary directory. The request returns a URL to the Flex app as the result of the call.
When Flex app gets the result--a URL--it creates a URL request and pops it open in a new window, prompting the user to download the generated excel sheet.
I don't see a way to do this in one shot; because the return value from the Flex HTTPService call goes to the Flash Player, not the browser.
SOLVED:
I wanted to accomplish this with 1 remote call and the way I found to do this while passing an object that contained collections is this:
var uv:URLVariables = new URLVariables();
uv.typesColl = myObj.types.toString();
uv.partiesColl = myObj.parties.toString();
uv.statuses = myObj.statuses.toString();
Basically, create a property on the URLVariables object for each collection and then set all collections toString();
Hope that helps someone.

Encrypting configuration sections

I'm trying to programmatically encrypt configuration sections of App.config and Web.config files. In the following code, I set the path configuration file I want to edit in the configFilePath variable and then expect it to encrypt the connectionStrings section.
var config = ConfigurationManager.OpenExeConfiguration(configFilePath);
var section = config.GetSection("connectionStrings");
if (section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings");
}
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings");
This runs fine without any errors but makes no changes to the given file. It's like it's not really accessing the file I want to access.
Any ideas?
Right, answering my own question...
The code was indeed not opening the right config file. To do that we need to use ConfigurationManager.OpenMappedExeConfiguration() instead of ConfigurationManager.OpenExeConfiguration().
So, the first line of the code above changes to:
var map = new ExeConfigurationFileMap { ExeConfigFilename = configFilePath };
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);