Is it possible to load a local file without having to ask the user to browse to it first in an AIR Application? - apache-flex

I'm writing a small application for myself and instead of using a database I'd like to just use Excel to store the small amount of data I have on my local file system. I want to be able to load that data without having to use the typical FileReference browse() method as it would just be annoying to do every time I use the application.
The code below seems to find the file fine as the file.exists method below and most of the other attributes seem to be correct but the file.data is always null.
I'm guessing this is a security issue and that's why I'm running into this problem but I thought I'd ask and see if there is in fact a way around this problem.
var file:File = new File(fullPath + "\\" + currentFolder + ".txt");
if(file.exists) {
var byteArray:ByteArray = file.data;
}

If you want to read the content of a file, use the following code:
var stream:FileStream = new FileStream();
stream.open("some path here", FileMode.READ);
var fileData:String = stream.readUTFBytes(stream.bytesAvailable);
trace(fileData);
The data property is inherited from FileReference class and it will be populated only after a load call (see this link).

You're close, you just need to combine that with a FileStream object
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var str:String = fileStream.readMultiByte(file.size, File.systemCharset);
trace(str);
more info here

Related

Flex 3 & Air 2: Automatically detect when files on a directory are updated

A crazy idea just dropped from the sky and hit me in the head xD. I was wondering if it is possible to make and App capable of listening when the user "adds" new files to a directory.
Example:
The User opens up our Application.
The user adds new files on the desktop (using the Microsoft Explorer).
Our application automatically detects that new files have been added and executes a function or whatever.
Sound interesting right?
Maybe, this could be done using a programming language like Visual Basic and open the executable with the NativeProcess api and listen for an stdOut event... (:
Anyone got and idea to share with us? :)
Thanks
Lombardi
AIR can handle this natively...
the FileSystemList class fires an event directoryChange whenever a file in the watched directory changes.
You can even use it to watch for drives being mounted (I think Christian Cantrell showed that one off)
Ok, I think I'm getting closer, check out this solution! :)
private var CheckDelay:Timer = new Timer(5000, 0);
private function InitApp():void
{
CheckDelay.addEventListener(TimerEvent.Timer, CheckForNewFiles, false, 0, true);
CheckDelay.start();
}
private function CheckForNewFiles(event:TimerEvent):void
{
var FS:FileStream = new FileStream();
var Buffer:File = File.applicationStorageDirectory.resolvePath("FilesBuffer.cmd");
FS.open(Buffer, FileMode.Write);
FS.writeUTFBytes("cd " + File.desktopDirectory.nativePath + "\r\n" +
"dir /on /b > " + File.applicationStorageDirectory.resolvePath("FileList.txt").nativePath);
FS.close();
var Process:NativeProcess = new NativeProcess();
var NPI:NativeProcessStartupInfo = NativeProcessStartupInfo(); // What a large name! xD
NPI.executable = Buffer;
Process.start(NPI);
Process..addEventListener(NativeProcessExitEvent.EXIT, ReadFileList, false, 0, true);
}
private function ReadFileList(event:Event):void
{
var FS:FileStream = new FileStream();
var Buffer:File = File.applicationStorageDirectory.resolvePath("FilesBuffer.cmd");
FS.open(Buffer, FileMode.Read);
var FileData:String = FS.readUTFBytes(FS.bytesAvailable);
FS.close();
var FileArray:Array = FileData.split("\r\n");
var TempArray:ArrayCollection = new ArrayColletion();
var TempFile:File;
for(var i:int = 0;i<FileArray.length;i++){
TempFile = new File(FileArray[i]);
TempArray.addItem(TempFile);
}
}
At the end we got an Array (TempArray) that we could use on a datagrid (for example) with colums like: "extension, File Name, FilePath, etc.."
The files are updated every 5 seconds.
And, why we use all that code instead of a simple "File.getDirectoryListing()"? Because we are updating our application every 5 seconds, if why use getDirectoryListing(), our application will take much more RAM and also, the cmd command is much faster... :)
If you have a better idea, please share it with us! Thank you! :D
1 excellent solution for Windows: use Visual Studio, build the .net app found here http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx
In Adobe AIR use the native process to listen for change events dispatched by .net

Downloading data posted to server as a file from Flex

This should be trivial, and I'm pretty sure I did it once before.
I'm trying to post data up to a server and have it bounced back to me as a file download, prompting the native browser file download box. I know the server part works just fine becasue I can post from a demo web form, but when I run the following Flex 3 code, I can't even get the request to fire.
var fileRef:FileReference = new FileReference();
private function saveXmlAsFile(event:MouseEvent):void
{
var fileRequest:URLRequest = new URLRequest();
fileRequest.method = URLRequestMethod.POST;
fileRequest.url = "http://foo.com/dataBounce";
var urlVariables:URLVariables = new URLVariables();
urlVariables.content = "Test content to return" ;
// fileRequest.contentType = "application/x-www-form-urlencoded ";
urlVariables.fileName = "test.xml";
fileRef.addEventListener(SecurityEvent.ALL, onSecurityError);
fileRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError2);
fileRef.addEventListener(IOErrorEvent.NETWORK_ERROR, onNetworkError);
fileRef.addEventListener(Event.COMPLETE, onComplete);
try
{
fileRef.download(fileRequest, "test.xml");
}catch(error:Error) {
model.logger.error("unable to download file");
}
}
Note, when the call to fileRef.download is called, I can't see any request being made across the network using the traditional Firebug or HTTPWatch browser tools.
EDIT: I should add that this is for < Flash Player 10, so I can't use the newer direct save as file functionality.
Any suggestions? Thanks.
You need to add fileRef.upload to trigger the upload.
Also I would move the download statement to the onComplete so the file isn't requested before it's been uploaded.
Your explanation is pretty clear, but when I look at your code, I'm feel like I'm missing something.
The code looks like you're trying to do half of the upload part and half of the download part.
I think the code you currently have posted would work to trigger a download if you set the .method value to GET. I believe you will also need to include the filename as part of the .url property.
However, to post something and then trigger a download of it, you need two separate operations - the operation to post the data and then an operation to download it, which should probably be called from the upload operation's onComplete handler.
OK, I believe I figured out one of the things that's going on.
When you don't set the URLRequest.data property, it defaults the request method to "GET".
So, the working code looks like, with the data set to the posted URL variables:
private var fileRef:FileReference;
private function saveRawHierarchy(event:MouseEvent):void
{
var fileRequest:URLRequest = new URLRequest();
fileRequest.method = URLRequestMethod.POST;
fileRequest.url = "http://foo/bounceback";
var urlVariables:URLVariables = new URLVariables();
urlVariables.content = "CONTENT HERE";
urlVariables.fileName = "newFileName.xml";
fileRequest.data = urlVariables;
fileRef = new FileReference();
fileRef.addEventListener(Event.COMPLETE, onComplete);
try
{
fileRef.download(fileRequest, "appHierarchies.xml");
}catch(error:Error) {
model.logger.error("unable to download file");
}
}
Not sure what was wrong about the request not being made before, though.

Flex sending snapshot without using base64Encode

var is:ImageSnapshot = myImagesnapshot;
var str:String = ImageSnapshot.encodeImageAsBase64(is);
As of now, I am sending my jpeg data to the server with the code above.
The problem is that it almost doubles the size of the data.
Is there a way to send the image data directly without using any encoding.
base64 increases size by a third, so if you really have about 100% overhead, you have a problem elsewhere.
haven't looked at the sources to well, but from the reference it seems, you could retrieve the binary data directly.
just tuck that into a URLRequest and send it per POST.
Here is a sample of sending image data without using Base64 :
var myEncoder:JPGEncoder = new JPGEncoder(100);
var byteArray:ByteArray = myEncoder.encode(bitmapData);
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var url:String = "../../default.php";
var saveJPG:URLRequest = new URLRequest(url);
saveJPG.requestHeaders.push(header);
saveJPG.method = URLRequestMethod.POST;
saveJPG.data = byteArray;
On PHP side, I need to access :
$globalS["HTTP_raw_post_data"]
You can save the snapshot as jpg or png.
Take a look at:
http://blog.flexexamples.com/2007/12/07/using-the-imagesnapshot-class-to-capture-images-as-jpegs-or-pngs-in-flex-3/

how to download files to a default dir without poping an option window in Flex/Air?

I'm writing a app with Flex/air,and i need a function that downloading files to the default dir without a pop-up window.i tried to use ftp instead of http but found it's not supported by air.how can i solve this problem?
This should be possible in AIR. I don't know if there's a direct API approach, but you should be able to load the bytes into memory and then flush them into a file. In pseudo-pseudo-code using File and FileStream:
// get the bytes
var loader:URLLoader = new URLLoader();
loader.load("http://www.stackoverflow.com");
...
var bytes:ByteArray = loader.data;
// get the file in the correct location
var f:File = File.documentsDirectory.resolvePath("myfile.txt");
// write the file
var fs:FileStream = new FileStream(f, FileMode.WRITE);
fs.writeBytes(bytes);
fs.close();
There are a few examples out there to look at.
None of this is possible in Flash Player because of the security limits #viatropos suggests.
I don't think you can do that as it's a Security violation. The user must be prompted with a download window so they can choose the directory. I think the thinking goes "if you don't prompt the user, then a Flash/Flex app could download a bunch of junk to their computer without their permission", and that would make adobe look bad :/. I wish you could though.
You can, however, download it using a server side script without asking the user for permission. I do that with ruby to accomplish what you're describing.
Hope that helps,
Lance
You can but only air version because you have to use FileStream
var ff:File = File.desktopDirectory.resolvePath("sample.dwg");
var u:String = obj_l.d1.selectedItem.data + "" + obj_l.d2.selectedItem.label;
var ll3:URLLoader = new URLLoader ();
u = GETURL() + u;
rr.url = u;
//ff.download(rr);
ll3.dataFormat = URLLoaderDataFormat.BINARY;
ll3.load(rr);
ll3.addEventListener(Event.COMPLETE , function (e:Event):void {
var stream:FileStream = new FileStream ();
stream.open(ff,FileMode.WRITE);
stream.writeBytes(ll3.data);
});

How can you save out a String into a file in AS3?

I have a string the user has typed and I want to save it into a file on the users harddrive. Can you do that? And if so, how?
Yes you can, with FileReference.
This is basically how it's done:
var bytes:ByteArray = new ByteArray();
var fileRef:FileReference=new FileReference();
fileRef.save("fileContent", "fileName");
Doesn't look too hard, does it?
And here's a video-tutorial on it too:
http://www.gotoandlearn.com/play?id=76
And the documentation:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/
Hope that helps.
Since I had a function to output bytes to a file (because I was doing something with bitmaps), I reused it to output a string as well, like this:
var filename:String = "/Users/me/path/to/file.txt";
var byteArray:ByteArray = new ByteArray();
byteArray.writeUTFBytes(someString);
outFile(filename, byteArray);
private static function outFile(fileName:String, data:ByteArray):void {
var outFile:File = File.desktopDirectory; // dest folder is desktop
outFile = outFile.resolvePath(fileName); // name of file to write
var outStream:FileStream = new FileStream();
// open output file stream in WRITE mode
outStream.open(outFile, FileMode.WRITE);
// write out the file
outStream.writeBytes(data, 0, data.length);
// close it
outStream.close();
}
In addition, you must have Flash Player 10 and a Flex Gumbo SDK installed in your Flex Builder 3.
You can also have a look the following example:
http://blog.flexexamples.com/2008/08/25/saving-files-locally-using-the-filereference-classs-save-method-in-flash-player-10/
In Flex 3 no you can't do it unless you upload the file to the server and then download the file via a url to the desktop.
In Air or Flex 4 you can save it directly from the application to the desktop as detailed above.

Resources