I have been trying to save game data using a binary formatter and Application.persistentDataPath on my Tango device. After saving however, the file is nowhere to be found.
Right now the path is reading out as "Storage/emulated/0/Android/data/com.mine.project/files/filename.bin", but as stated above, the path doesn't actually exist anywhere.
Is there another way to save all of this data on the Tango that I have yet to find? If not, is there a way to get these files to show up?
This is the code that I am currently using, minus some debugging functions I use.
string path = Application.persistentDataPath + Path.DirectorySeparatorChar + "file.bin";
BinaryFormatter bf = new BinaryFormatter ();
FileStream file = File.Open (path, FileMode.OpenOrCreate);
bf.Serialize(file, data);
file.Close ();
From what I can tell this isn't throwing any errors, I can even find the file again via the File.Exists() function, but I need to find the file again for access through other programs, and so far it has proven impossible.
Meteor is great but it lacks native supports for traditional file uploading. There are several options to handle file uploading:
From the client, data can be sent using:
Meteor.call('saveFile',data) or collection.insert({file:data})
'POST' form or HTTP.call('POST')
In the server, the file can be saved to:
a mongodb file collection by collection.insert({file:data})
file system in /path/to/dir
mongodb GridFS
What are the pros and cons for these methods and how best to implement them? I am aware that there are also other options such as saving to a third party site and obtain an url.
You can achieve file uploading with Meteor without using any more packages or a third party
Option 1: DDP, saving file to a mongo collection
/*** client.js ***/
// asign a change event into input tag
'change input' : function(event,template){
var file = event.target.files[0]; //assuming 1 file only
if (!file) return;
var reader = new FileReader(); //create a reader according to HTML5 File API
reader.onload = function(event){
var buffer = new Uint8Array(reader.result) // convert to binary
Meteor.call('saveFile', buffer);
}
reader.readAsArrayBuffer(file); //read the file as arraybuffer
}
/*** server.js ***/
Files = new Mongo.Collection('files');
Meteor.methods({
'saveFile': function(buffer){
Files.insert({data:buffer})
}
});
Explanation
First, the file is grabbed from the input using HTML5 File API. A reader is created using new FileReader. The file is read as readAsArrayBuffer. This arraybuffer, if you console.log, returns {} and DDP can't send this over the wire, so it has to be converted to Uint8Array.
When you put this in Meteor.call, Meteor automatically runs EJSON.stringify(Uint8Array) and sends it with DDP. You can check the data in chrome console websocket traffic, you will see a string resembling base64
On the server side, Meteor call EJSON.parse() and converts it back to buffer
Pros
Simple, no hacky way, no extra packages
Stick to the Data on the Wire principle
Cons
More bandwidth: the resulting base64 string is ~ 33% larger than the original file
File size limit: can't send big files (limit ~ 16 MB?)
No caching
No gzip or compression yet
Take up lots of memory if you publish files
Option 2: XHR, post from client to file system
/*** client.js ***/
// asign a change event into input tag
'change input' : function(event,template){
var file = event.target.files[0];
if (!file) return;
var xhr = new XMLHttpRequest();
xhr.open('POST', '/uploadSomeWhere', true);
xhr.onload = function(event){...}
xhr.send(file);
}
/*** server.js ***/
var fs = Npm.require('fs');
//using interal webapp or iron:router
WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
//var start = Date.now()
var file = fs.createWriteStream('/path/to/dir/filename');
file.on('error',function(error){...});
file.on('finish',function(){
res.writeHead(...)
res.end(); //end the respone
//console.log('Finish uploading, time taken: ' + Date.now() - start);
});
req.pipe(file); //pipe the request to the file
});
Explanation
The file in the client is grabbed, an XHR object is created and the file is sent via 'POST' to the server.
On the server, the data is piped into an underlying file system. You can additionally determine the filename, perform sanitisation or check if it exists already etc before saving.
Pros
Taking advantage of XHR 2 so you can send arraybuffer, no new FileReader() is needed as compared to option 1
Arraybuffer is less bulky compared to base64 string
No size limit, I sent a file ~ 200 MB in localhost with no problem
File system is faster than mongodb (more of this later in benchmarking below)
Cachable and gzip
Cons
XHR 2 is not available in older browsers, e.g. below IE10, but of course you can implement a traditional post <form> I only used xhr = new XMLHttpRequest(), rather than HTTP.call('POST') because the current HTTP.call in Meteor is not yet able to send arraybuffer (point me if I am wrong).
/path/to/dir/ has to be outside meteor, otherwise writing a file in /public triggers a reload
Option 3: XHR, save to GridFS
/*** client.js ***/
//same as option 2
/*** version A: server.js ***/
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var GridStore = MongoInternals.NpmModule.GridStore;
WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
//var start = Date.now()
var file = new GridStore(db,'filename','w');
file.open(function(error,gs){
file.stream(true); //true will close the file automatically once piping finishes
file.on('error',function(e){...});
file.on('end',function(){
res.end(); //send end respone
//console.log('Finish uploading, time taken: ' + Date.now() - start);
});
req.pipe(file);
});
});
/*** version B: server.js ***/
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var GridStore = Npm.require('mongodb').GridStore; //also need to add Npm.depends({mongodb:'2.0.13'}) in package.js
WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
//var start = Date.now()
var file = new GridStore(db,'filename','w').stream(true); //start the stream
file.on('error',function(e){...});
file.on('end',function(){
res.end(); //send end respone
//console.log('Finish uploading, time taken: ' + Date.now() - start);
});
req.pipe(file);
});
Explanation
The client script is the same as in option 2.
According to Meteor 1.0.x mongo_driver.js last line, a global object called MongoInternals is exposed, you can call defaultRemoteCollectionDriver() to return the current database db object which is required for the GridStore. In version A, the GridStore is also exposed by the MongoInternals. The mongo used by current meteor is v1.4.x
Then inside a route, you can create a new write object by calling var file = new GridStore(...) (API). You then open the file and create a stream.
I also included a version B. In this version, the GridStore is called using a new mongodb drive via Npm.require('mongodb'), this mongo is the latest v2.0.13 as of this writing. The new API doesn't require you to open the file, you can call stream(true) directly and start piping
Pros
Same as in option 2, sent using arraybuffer, less overhead compared to base64 string in option 1
No need to worry about file name sanitisation
Separation from file system, no need to write to temp dir, the db can be backed up, rep, shard etc
No need to implement any other package
Cachable and can be gzipped
Store much larger sizes compared to normal mongo collection
Using pipe to reduce memory overload
Cons
Unstable Mongo GridFS. I included version A (mongo 1.x) and B (mongo 2.x). In version A, when piping large files > 10 MB, I got lots of error, including corrupted file, unfinished pipe. This problem is solved in version B using mongo 2.x, hopefully meteor will upgrade to mongodb 2.x soon
API confusion. In version A, you need to open the file before you can stream, but in version B, you can stream without calling open. The API doc is also not very clear and the stream is not 100% syntax exchangeable with Npm.require('fs'). In fs, you call file.on('finish') but in GridFS you call file.on('end') when writing finishes/ends.
GridFS doesn't provide write atomicity, so if there are multiple concurrent writes to the same file, the final result may be very different
Speed. Mongo GridFS is much slower than file system.
Benchmark
You can see in option 2 and option 3, I included var start = Date.now() and when writing end, I console.log out the time in ms, below is the result. Dual Core, 4 GB ram, HDD, ubuntu 14.04 based.
file size GridFS FS
100 KB 50 2
1 MB 400 30
10 MB 3500 100
200 MB 80000 1240
You can see that FS is much faster than GridFS. For a file of 200 MB, it takes ~80 sec using GridFS but only ~ 1 sec in FS. I haven't tried SSD, the result may be different. However, in real life, the bandwidth may dictate how fast the file is streamed from client to server, achieving 200 MB/sec transfer speed is not typical. On the other hand, a transfer speed ~2 MB/sec (GridFS) is more the norm.
Conclusion
By no mean this is comprehensive, but you can decide which option is best for your need.
DDP is the simplest and sticks to the core Meteor principle but the data are more bulky, not compressible during transfer, not cachable. But this option may be good if you only need small files.
XHR coupled with file system is the 'traditional' way. Stable API, fast, 'streamable', compressible, cachable (ETag etc), but needs to be in a separate folder
XHR coupled with GridFS, you get the benefit of rep set, scalable, no touching file system dir, large files and many files if file system restricts the numbers, also cachable compressible. However, the API is unstable, you get errors in multiple writes, it's s..l..o..w..
Hopefully soon, meteor DDP can support gzip, caching etc and GridFS can be faster...
Hi just to add on to Option1 regarding viewing of the file. I did it without ejson.
<template name='tryUpload'>
<p>Choose file to upload</p>
<input name="upload" class='fileupload' type='file'>
</template>
Template.tryUpload.events({
'change .fileupload':function(event,template){
console.log('change & view');
var f = event.target.files[0];//assuming upload 1 file only
if(!f) return;
var r = new FileReader();
r.onload=function(event){
var buffer = new Uint8Array(r.result);//convert to binary
for (var i = 0, strLen = r.length; i < strLen; i++){
buffer[i] = r.charCodeAt(i);
}
var toString = String.fromCharCode.apply(null, buffer );
console.log(toString);
//Meteor.call('saveFiles',buffer);
}
r.readAsArrayBuffer(f);};
Trying to download a page blob of size 2 GB using java sdk and it fails with Storage exception because the file size downloaded does not match the actual file size
On multiple tries the same result is seen, although there is slight change in the downloaded file size. Setting timeout to maximum value also does not help.
Also, when I download the same vhd using the Azure portal, I see that the download completes but only partially. It is usually comparable to the one downloaded with SDK.
In the SDK code, I can see HTTpUrlConnection is being used. Could that be a problem ? The same code on a Windows machine has similar results but only the downloaded file is few more MB's in size but not complete.
Any thoughts on how to get it working ?
The code snippet used is
URI blobEndpoint = null;
String uriString = "http://" + "sorageaccount" + ".blob.core.windows.net";
blobEndpoint = new URI(uriString);
CloudBlobClient blobClient = new CloudBlobClient(blobEndpoint,
new StorageCredentialsAccountAndKey("abcd", "passed"));
CloudBlobContainer container = blobClient.getContainerReference(Constants.STORAGE_CONTAINER_NAME);
CloudPageBlob pageBlob = container.getPageBlobReference("http://abcd.blob.core.windows.net/sc/someimg.vhd");
System.out.println("Page Blob Name: " + pageBlob.getName());
OutputStream outStream = new FileOutputStream(new File("/Users/myself/Downloads/TestDownload.vhd"));
System.out.println("Starting download now ... ");
BlobRequestOptions options = new BlobRequestOptions();
options.setUseTransactionalContentMD5(true);
options.setStoreBlobContentMD5 (true); // Set full blob level MD5
options.setTimeoutIntervalInMs(Integer.MAX_VALUE);
options.setRetryPolicyFactory(new RetryLinearRetry());
pageBlob.download(outStream, null, options, null);
outStream.close();
I have no question, just sharing 3 days of frustration and ultimate success.
The above is what I got from Netbeans using its GridBagLayout mode. Below is what I wanted.
I couldn't get what I wanted within a reasonable time using Netbeans, so I thought I would be able to cut, paste, and modify the generated code to make the form look like what I want.
I was right and the time spent in getting what I wanted was minimal, using the Netbeans "outline" that I started late last night.
Here's my code:
public class DoThis extends JFrame {
... (variable declarations removed)
public DoThis() {
initComponents();
}
private void initComponents() {
GridBagConstraints gridBagConstraints;
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridBagLayout());
pnlFileStuff = new JPanel();
pnlFileStuff.setBorder(BorderFactory.createEtchedBorder());
pnlFileStuff.setLayout(new GridBagLayout());
lblRootNode = new JLabel("Root node:");
gridBagConstraints = new GridBagConstraints();
pnlFileStuff.add(lblRootNode, gridBagConstraints);
txtRootNode = new JTextField("C:\\Users");
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.ipadx = 520; // One key
gridBagConstraints.anchor = GridBagConstraints.WEST;
pnlFileStuff.add(txtRootNode, gridBagConstraints);
btnBrowse = new JButton("Browse...");
gridBagConstraints = new GridBagConstraints();
pnlFileStuff.add(btnBrowse, gridBagConstraints);
lblFilenamePattern = new JLabel("Filename pattern:");
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
pnlFileStuff.add(lblFilenamePattern, gridBagConstraints);
txtFilenamePattern = new JTextField("*.*");
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.ipadx = 250; // the other key
gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = GridBagConstraints.WEST;
pnlFileStuff.add(txtFilenamePattern, gridBagConstraints);
getContentPane().add(pnlFileStuff, new GridBagConstraints());
pack();
}
public static void main(String args[]) {
invokeLater(new Runnable() {
public void run() {
new DoThis().setVisible(true);
}
});
}
}
As it turns out, I only needed to do one additional thing in Netbeans--only one of the ipadx instances labeled "key" in the code. Sort of embarrassing to admit. And I didn't have to!
Just call it a learning experience that I decided to share, for better or worse. I think some newbie might profit from this post.
"Lessons" "learned":
(1) It's hard as heck to use Netbeans in "GridBagLayout mode". It's too far from WYSIWYG and far from intutitive. (This from a guy who had never used GridBayLayout and had never read about it until several days ago.) As one link suggested by S.O. that I followed stated, "Unfortunately, GridBagLayout is infernally awkward and error-prone to use." No argument here.
(2) Spending enough time struggling with Netbeans was worth it, in that, without it, it was almost impossible to read textbooks and tutorials and get anything close to desired outcome (YMMV).
(3) The code Netbeans generates in "GridBagLayout mode" is MUCH closer to human-written code than the usual incomprehensible hundreds of lines of krazy kode (that it generates in "free design" mode), which is virtually impossible to follow, let alone cut, paste, and edit (though I've had minimal success doing so). (Never again.)
(4) The generated GridBagLayout code is reasonably easy to cut, paste, and edit to generate the desired outcome (given that it was in the ballpark to begin with, and ignoring ample frustration with its quirks).
Most importantly (for ME), I finally feel free from Netbeans and may be on the way to developing some skill at writing GUI code from scratch, something I've avoided like the plague for months!!
I would be remiss not to revisit this thread and state that learning how to use GridBagLayout without Netbeans GUI builder is attainable by anyone. In less than a week of learning and getting help and advice from SO, I have finally arrived at creating a GUI that (unlike that generated by Netbeans) is easily editable and extendable--because I wrote the code by hand. The GUI that I'd been using and bugging SO with questions about for months (e.g., how to keep display from flashing during execution, which led to SwingWorker and other complications) has been replaced by the one below, which I created in a night and "perfected" the next day (today):
I'm not bragging; far from it. I barely know squat. Like "perfected" means "got output, and it doesn't flash, and it's readable, but it's ugly as sin."
Just providing hope for other newbies, I hope.
I have an image stored in a Bitmap object that I'd like to stick into an OpenXML document. I've tried using a MemoryStream as an intermediate step as follows:
ImagePart part = container.AddNewPart<ImagePart>("image/jpeg", imageId);
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Jpeg);
part.FeedData(ms);
}
but that always results in empty files in the media folder and PowerPoint displaying an error instead of the images. I know that the MemoryStream has the image data correctly as I've written it out to a file without issue. When I try to load an image from a FileStream it works just fine.
How can I get this Bitmap into an OpenXML document?
I was almost there, I just needed to reset the MemoryStream's position to the beginning after saving the Bitmap to it.
ms.Position = 0;
That line should be added between the Save and FeedData calls.