Bug 1229 : createInput fails to open a file stream
Last modified: 2009-04-13 07:11




Status:
RESOLVED
Resolution:
INVALID -
Priority:
P2
Severity:
normal

 

Reporter:
lagerpet
Assigned To:
fry

Attachment Type Created Size Actions

Description:   Opened: 2009-04-12 10:54
Rev 0165
Windows XP & Vista

I have created a sketch to load and display MD2 Quake character animation
files. As part of the program I create a FileInputStream using the
createInput(String fname) method in PApplet. This works fine in Processing
but when I use the export option and then upload the applet it fails to
create the file stream.

This can be demonstrated with the following code


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;

FileInputStream fin;
FileChannel fc;
ByteBuffer buf;
String content;

void setup()
{
size(400,400);
openBuffer("models/dummy/dummy.tris");
content = readString(12,'\0');
closeBuffer();
println(content);
}

void draw(){
background(200,200,255);
}

boolean openBuffer(String mdlFile){
try {
fin = (FileInputStream)createInput(mdlFile);
}
catch (Exception ex){
System.out.println("Can't create file stream");
return false;
}
try{
fc = fin.getChannel();
}
catch(Exception ex) {
System.out.println("Can't create channel");
return false;
}
if(fin == null){
System.out.println("File Channel is NULL");
return false;
}
try{
buf = ByteBuffer.allocateDirect((int)fc.size());
if(buf == null){
System.out.println("failed to allocate buffer buf = null");
}
fc.read(buf);
// BIG_ENDIAN is the default - might be for Java
// but the file was created with a C++ program
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.rewind();
}
catch(Exception ex) {
System.out.println("Can't allocate buffer");
return false;
}
return true;
}

private void closeBuffer(){
try {
fin.close();
}
catch (IOException e) {
System.out.println("Unable to close model file");
}
}

String readString(int nbytes, char stopAt){
int nextPos = buf.position() + nbytes;
char ch;
StringBuilder s = new StringBuilder("");
for(int i = 0; i < nbytes; i++){
ch = (char)buf.get();
if(ch != stopAt)
s.append(ch);
else
break;
}
buf.position(nextPos);
return new String(s);
}

The Java console gives the following output

Applet Status: Applet loaded.
Applet Status: Applet resized and added to parent container
Applet Status: Applet initialized
Applet Status: Applet made visible
Applet Status: Starting applet
Applet Status: Applet started
Applet Status: Told clients applet is started
Can't create file stream
Exception in thread "Animation Thread" java.lang.NullPointerException
at bug001.java:91)
at bug001.java:35)
at processing.core.PApplet.handleDraw(PApplet.java:1400)
at processing.core.PApplet.run(PApplet.java:1328)
at java.lang.Thread.run(Unknown Source)
Additional Comment #1 From fry 2009-04-12 15:14
either you haven't put the file into your data folder, or when exported,
you've missed that it will no longer be a regular file, but an item inside
the exported .jar file.
Additional Comment #2 From lagerpet 2009-04-13 02:49
It works in Processing so the file is present in the data folder.

I am aware that the data folder is included with the jar when exported from
Processing but to be on the safe side I checked and it is there.

I have been looking at the PApplet source code and the createInput() method
of PApplet calls the createInputRaw() method which checks in the following
order

1) sees if i is a URL
2) checks for the file using dataPath
3) tries to find it as a resource from 'data/'
4) tries to find it as a resource without 'data/'
5) tries to find it as a local file

So would it not find it in the 'jar'? (I have create a library for
Processing called GUI4Procesing and that includes images in the library jar
and it found them no problem.)

Just in case I missed something I tried some further experiments and
created the following file system on the webserver.

|
|-index.html
|-bug001.jar
|-dummy.tris
|- data
|- dummy.tris
|- models
|-dummy
|-dummy.tris

So there are now 4 copies of the file (including the one in the jar) in
every location I can think of but I still get an exception from createInput()

I am probably missing something obvious and would appreciate your help.




>
>
>
> Additional Comment #1 From
> fry
> 2009-04-12 15:14
>
> <!--
> addReplyLink(1); //-->[reply]
>
>
>
>
> either you haven't put the file into your data folder, or when
exported,
> you've missed that it will no longer be a regular file, but an item inside
> the exported .jar file.
>
>
Additional Comment #3 From lagerpet 2009-04-13 04:42
Since I replied I have thought about it and I hope I have come up with a
clearer example of the problem.

The code below will attempt to load an image using loadImage and then
attempt to get an input stream on the SAME file. If both are successful the
image will appear with a blue background, if only the loadImage is
successful then it will appear in a pink background.

When run from Processing there is a blue background and from the website a
pink background.

This is interesting because for a png file loadImage(filename) will call
loadBytes(filename) which calls createInput(filename) but does it successfully.

When I call createInput(filename) directly (website) I get the following
report from Java Console in Firefox

Applet Status: Applet loaded.
Applet Status: Applet resized and added to parent container
Applet Status: Applet initialized
Applet Status: Applet made visible
Applet Status: Starting applet
Applet Status: Applet started
Applet Status: Told clients applet is started
Can't create file stream for models/dummy/dummy.png
java.lang.ClassCastException: java.util.zip.ZipFile$1 cannot be cast to
java.io.FileInputStream
at bug003.java:35)
at processing.core.PApplet.handleDraw(PApplet.java:1400)
at processing.core.PApplet.run(PApplet.java:1328)
at java.lang.Thread.run(Unknown Source)

I get the same result if I use a simple text file with createInput(filaname)

################ CODE #################

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;

FileInputStream fin;
String fname = "models/dummy/dummy.png";
int bg = color(200,200,255);
PImage img;

void setup()
{
size(400,400);
img = loadImage(fname);
try {
fin = (FileInputStream)this.createInput(fname);
}
catch (Exception e){
System.out.println("Can't create file stream for "+fname);
e.printStackTrace();
}
if(fin != null){
println("Open file " + fname + " successfully");
try{
fin.close();
}
catch (Exception e){
println("Can't close file " + fname);
}
}
else
bg = color(255,200,200);
}

void draw(){
background(bg);
if(img != null)
image(img,100,100);
}

Additional Comment #4 From fry 2009-04-13 05:51
createInput() returns an InputStream, not a FileInputStream, so you cannot
cast it to a FileInputStream; that's why you're getting the error with the
image file.

just because the file loads inside the Processing environment does not mean
that it's in the data folder. it will also load if found in the sketch folder.
Additional Comment #5 From lagerpet 2009-04-13 07:11
I assumed that since it returned a FileInputStream when run in Processing
it would do the same when upload to a website. I ran a small test and in
fact it returns a java.util.zip.ZipFile$1 (must admit I've not come across
this Java class before - back to the drawing board for me)

Sorry for any inconvenience and thanks for your quick response.

Peter