Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (579)
games submitted by our members
Games in WIP (500)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Obtaining a usable Url.getFile() from a Resource?  (Read 3043 times)
0 Members and 1 Guest are viewing this topic.
Offline philfrei
« Posted 2011-06-06 10:05:03 »

I have successfully obtained a Url from a resource. But url.getFile() returns different things in different contexts. For example, in my Eclipse IDE:
1  
/C:/Documents%20and%20Settings/Phil/workspace/Fivefold/bin/com/adonax/fivefold/audio/elders.ogg


If I'm running the same code from a Jar:
1  
file:/C:/Documents%20and%20Settings/Phil/Desktop/Java/fivefold/ffogg.jar!/com/adonax/fivefold/audio/elders.ogg

Note the presence of the "!" in this one.

So, it is possible to do the following which works in both contexts (though it really feels like a kluge):
1  
2  
3  
4  
String s = s.replace("%20", " "); 
s = s.replace("!", "");
s = s.replace("file:", "");
s = s.substring(1);

But I sure would like to know either or both:
1) what the heck is going on with getFile(), why is it adding these things and what will happen when I try to do this in another OS or as an Applet?
2) is there a better way to get a filename for a working "resource" that is in a Jar?

Reason for question: there is a function in JCraft's JOrbis that allows one to obtain a frame count but I can only make it work for VorbisFile objects created with a filename string. When I make a VorbisFile object with an InputStream, it decides the file is not "seekable". (I would have to dig deeper into the JOrbis code to find out why this is.) If I could get that framecount another way, that would make the above question moot, but still kind of interesting to me. The whole Jar/File/Resource complex has always been a toughie.

Many thanks!    

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline biro

Junior Member


Medals: 1
Projects: 1



« Reply #1 - Posted 2011-06-06 11:25:18 »

Hello,
I'm not sure if I understand your question correct...
But the main difference is, that in your first code-line you loaded the File from outside a jar-file and from the second code-line from inside a jar-file. That is because you use the class.getRessource() method, that uses the path from your ressource, which can be inside a jar-file, which means the ! in your second code-line.

To the Question what happens on another OS, I would guess That the link is a little changed, because it has another filesystem, Linux par example has "\" as it's root folder, while windows has no root-folder, the nearest thing to the root-folder on windows is the C:/ volume, so your first link would look like:
1
   
file:/\usr\Phil\...\workspace\Fivefold\bin\com\adonax\fivefold\audio\elders.ogg

the / after file:/ stands for the root-folder, please notice that linux or unix all in all doesn't use / for the folder-file seperator, but \ for them!!!
usr is the Folder that inhabits the user-homefolders. (The name can change from Linux OS to Linux OS)

To the second the Question:
I'm not sure why you need a better way? Do you get an error when you use this command to open your ogg File? Because your file-link should be changed acording to your OS under your JRE, so that the command should work everywhere.

Hope my knowledge helps.

P.S. I use Windows as my main OS, so I hope for a comment from someone who uses Linux more often!

biro
Offline cylab

JGO Knight


Medals: 34



« Reply #2 - Posted 2011-06-06 11:44:28 »

You can't obtain a file from within a jar-archive (the ! is the separator between the location of the containing jar file and the path inside the archive of the contained file).

So if you really need the file, you have to read it from the InputStream and write it to some temp file you can use afterwards.

Mathias - I Know What [you] Did Last Summer!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline pjt33
« Reply #3 - Posted 2011-06-06 14:23:55 »

To the Question what happens on another OS, I would guess That the link is a little changed, because it has another filesystem, Linux par example has "\" as it's root folder, while windows has no root-folder, the nearest thing to the root-folder on windows is the C:/ volume, so your first link would look like:
1
   
file:/\usr\Phil\...\workspace\Fivefold\bin\com\adonax\fivefold\audio\elders.ogg

the / after file:/ stands for the root-folder, please notice that linux or unix all in all doesn't use / for the folder-file seperator, but \ for them!!!
usr is the Folder that inhabits the user-homefolders. (The name can change from Linux OS to Linux OS)
Huh Linux uses / as a path separator. Windows uses \, although in some contexts (e.g. url address bars) / will be translated. /usr usually contains data (system resources). The user directories are in /home on most (all?) Linux distros; on OS X they're in /Users; not sure about other Unices.
Offline biro

Junior Member


Medals: 1
Projects: 1



« Reply #4 - Posted 2011-06-06 16:54:06 »

Hello,
Quote
Linux uses / as a path separator. Windows uses \, although in some contexts (e.g. url address bars) / will be translated. /usr usually contains data (system resources). The user directories are in /home on most (all?) Linux distros; on OS X they're in /Users; not sure about other Unices.
sr, that I got that one wrong, but I only said how I remembered it to be, and it looks like it was wrong -> That's the reason why I asked for an answer from someone who uses Linux more often Cheesy

Quote
You can't obtain a file from within a jar-archive (the ! is the separator between the location of the containing jar file and the path inside the archive of the contained file).

So if you really need the file, you have to read it from the InputStream and write it to some temp file you can use afterwards.
Sorry to correct you... but you can. I often get my pictures out of my jar Files, and other things too. I think you meant, that you can't ADD things to your jar-Archive while you're using it.

biro


Offline m_waddams

Junior Member


Medals: 2
Projects: 1



« Reply #5 - Posted 2011-06-06 17:03:35 »

Reason for question: there is a function in JCraft's JOrbis that allows one to obtain a frame count but I can only make it work for VorbisFile objects created with a filename string. When I make a VorbisFile object with an InputStream, it decides the file is not "seekable". (I would have to dig deeper into the JOrbis code to find out why this is.) If I could get that framecount another way, that would make the above question moot, but still kind of interesting to me. The whole Jar/File/Resource complex has always been a toughie.
I guess a BufferedInputStream should be "seekable"? Maybe try this:
1  
2  
InputStream is = Game.class.getClassLoader().getResourceAsStream("sounds/" + sound);
BufferedInputStream bis = new BufferedInputStream(is);
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #6 - Posted 2011-06-06 18:13:52 »

To the Question what happens on another OS, I would guess That the link is a little changed, because it has another filesystem, Linux par example has "\" as it's root folder, while windows has no root-folder, the nearest thing to the root-folder on windows is the C:/ volume, so your first link would look like:
1
   
file:/\usr\Phil\...\workspace\Fivefold\bin\com\adonax\fivefold\audio\elders.ogg

the / after file:/ stands for the root-folder, please notice that linux or unix all in all doesn't use / for the folder-file seperator, but \ for them!!!
usr is the Folder that inhabits the user-homefolders. (The name can change from Linux OS to Linux OS)
Huh Linux uses / as a path separator. Windows uses \, although in some contexts (e.g. url address bars) / will be translated.
Are there actually any cases where '/' won't work in windows? I just use / everywhere and have never run into a problem. Using File.pathSeparator everywhere is just plain ugly.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline cylab

JGO Knight


Medals: 34



« Reply #7 - Posted 2011-06-06 18:42:48 »

Sorry to correct you... but you can. I often get my pictures out of my jar Files, and other things too.

It's not about getting the file data out of a jar file, but about getting a valid file location of a resource inside a jar to be able to feed it to APIs working with filenames instead of InputStreams.

Since the resource is inside another file (the jar) you cannot obtain a valid file location. It simply does not exist on the computers filesystem - only the containing jar does.

Mathias - I Know What [you] Did Last Summer!
Offline Mr. Gol

Senior Member


Medals: 1



« Reply #8 - Posted 2011-06-06 19:08:52 »

Are there actually any cases where '/' won't work in windows? I just use / everywhere and have never run into a problem. Using File.pathSeparator everywhere is just plain ugly.

Forward slashes work fine on Windows. The only cases where I use the system-dependent path separator are when I need to communicate the path to the user.
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #9 - Posted 2011-06-06 21:47:21 »

To sum up:
-You can't obtain a java.io.File that points to a resource inside of another file, like a zip file or a Jar file.
-Unix uses "/" and Windows uses "\" as a default but also allows "/", however beware that "/" is also an escape character on Windows, while "\" is an escape character on Unix.

Ok? Beautiful Cheesy

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline cylab

JGO Knight


Medals: 34



« Reply #10 - Posted 2011-06-06 22:57:49 »

(...) however beware that "/" is also an escape character

Ok? Beautiful Cheesy

Erm... No Wink "\" is an escape character...

Mathias - I Know What [you] Did Last Summer!
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #11 - Posted 2011-06-06 23:58:46 »

"/" is an escape character on Windows, "\" is an escape character on Unix.

Offline philfrei
« Reply #12 - Posted 2011-06-07 00:01:03 »

Thanks everyone!

I also asked the question over at JavaRanch http://www.coderanch.com/t/540718/Streams/java/curious-stuff-returned-Url-getFileand got basically the same answer: a file packed in a Jar isn't a file. Alternative courses of action: 1) rewrite the constructor of VorbisFile to accept a URL or InputStream, 2) make a temp copy of the resource and access that as a File.

@m-waddams -- I tried your suggestion, converting to a BufferedInputStream. Simple substitution did not work, unfortunately. Digging a bit further, what is going on in JOrbis is to create a RandomAccessFile from the file location string. The "seekable" boolean is only set if a RandomAccessFile has been created. And I don't see any way to create a RandomAccessFile from a URL, only File constructors.

@biro -- To clarify, I can open and play an Ogg just fine. My goal is to query the file's header to find out, in advance, how many frames are contained in the file. JCraft's JOrbis implementation exposes this info via an object called VorbisFile. This object is not involved in playback! It's constructor relies on a File name string.

Continuing on a second post...to follow shortly...

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline philfrei
« Reply #13 - Posted 2011-06-07 00:17:02 »

continuing from previous post...

So, I'm considering a few different options.

1) Parse the URL.getFile() into a "useable" string. Seems like a kluge and asking for trouble, but it also seems to work. The question is how well will it work in the future, and will it work for various OSes. I should post a trial file and ask people with Mac or Linux to try it out. The various replies (thank you, again!) about different ways of displaying files has me thinking it might work but it might be a little dicey. [EDIT: suddenly this approach stopped working. So, was I hallucinating when I thought it WAS working?  Huh]

2) Go ahead and do a temp file write. This might not be too costly, as in the Audio subsystem I am creating, this would only occur with the creation of the higher level objects (I'm implementing an "improved" Loop player and a Chaining sort of player to allow "branching" background music or sound events). There would be no cost at the point in time where the OggVorbisCueWrapper is called to play. Also, the temp file remains compressed. We aren't decoding and writing the full-sized file.

3) Investigate some code I found in Horstmann using ZipInputStream. He has some example code that displays the contents of a Zip archive and allows the selection of a file within that archive. (Vol. II, Eighth Ed., pg. 34.) I'm guessing that if this can be successfully implemented, it would be the fastest and safest option. I will report back if I am successful. [EDIT: fuzzy thinking. Yes, can inspect inside a zip/jar and identify relative file names. But the file is still inside a jar and not available as a RandomAccessFile.]

4) Continue to dig inside of JOrbis for ways to find where this data I want is stored and if there is another way to get at it.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline philfrei
« Reply #14 - Posted 2011-06-07 00:32:00 »

The discussion below really highlights, to my mind, the ambiguity and confusion around resources packed in Jars. When is a File not a File? I can understand the statement that the "file name" of the packed resource is not a "valid file location". Yet I find that I *can* create a string that allows Java to open a File that is in a Jar, albeit with a bunch of kluges like converting "%20" to " " and eliminating "!" & "file:" and a starting "/". Does that fact contradict the first statement? This seems paradoxical to me. I also find it hard to understand how a file thus opened is even readable, since presumably its contents are in a Zipped format rather than in its original form.
Sorry to correct you... but you can. I often get my pictures out of my jar Files, and other things too.

It's not about getting the file data out of a jar file, but about getting a valid file location of a resource inside a jar to be able to feed it to APIs working with filenames instead of InputStreams.

Since the resource is inside another file (the jar) you cannot obtain a valid file location. It simply does not exist on the computers filesystem - only the containing jar does.


"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #15 - Posted 2011-06-07 03:48:18 »

Have you tried looking at the source?

http://www.docjar.org/html/api/java/net/URL.java.html
Offline philfrei
« Reply #16 - Posted 2011-06-07 04:19:35 »

Nice. Bookmarked the site.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline pjt33
« Reply #17 - Posted 2011-06-07 08:12:08 »

4) Continue to dig inside of JOrbis for ways to find where this data I want is stored and if there is another way to get at it.
If JOrbis is open source and you don't mind forking it (whether or not you offer the patch back to them), one approach would be to add another constructor which takes a byte[]. This would wind up being roughly equivalent to the read-the-stream-and-write-it-to-disk approach, except without the write-it-to-disk. Of course, it's a matter of trading off memory usage against disk access.

The problem with trying to work directly with the zip is that random access into a zipped file will require you to scan the whole thing and build up an index, at which point you may as well have simply decompressed it. The only way this could reasonably work is if the compression method used for the file is NONE, which is a bit brittle.
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #18 - Posted 2011-06-07 11:01:56 »

The discussion below really highlights, to my mind, the ambiguity and confusion around resources packed in Jars. When is a File not a File?
You (and the JOrbis guys) have got things backwards IMHO. Files are just for physical, local files. What you really want to be doing is using Urls (or URIs) everywhere. Urls are a superset of Files - they can be paths to things on the internet, on a local file system, or in a virtual file system (ie. a file within a jar).

The best solution would be to change JOrbis to accept an Url rather than a File. But if you don't want to do that then extracting it to a temp dir is probably your best solution.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline pjt33
« Reply #19 - Posted 2011-06-07 11:18:51 »

You (and the JOrbis guys) have got things backwards IMHO. Files are just for physical, local files. What you really want to be doing is using Urls (or URIs) everywhere. Urls are a superset of Files - they can be paths to things on the internet, on a local file system, or in a virtual file system (ie. a file within a jar).

The best solution would be to change JOrbis to accept an Url rather than a File. But if you don't want to do that then extracting it to a temp dir is probably your best solution.
If he changes JOrbis then he'll just be doing the same thing of extracting to a temp location inside the library rather than outside it. If you look back up, the reason it wants a File is to create a RandomAccessFile. There's no interface
1  
2  
3  
4  
5  
interface IRandomAccessByteSource
{
    void seek(long pos);
     int read(byte[] b, int off, int len);
}
which can be used instead, and even if you add an interface there's no general mechanism for implementing it around a URL other than reading the entire contents of the URL to a temporary byte[] or file.
Offline delt0r

JGO Coder


Medals: 22


Computers can do that?


« Reply #20 - Posted 2011-06-07 15:32:47 »

I am with Orangy Tang on this. You should use URLs. You don't even need to use different separators with urls as it is the same on all platforms. My entire resource  system for the game uses URLs. It works really well, i can point to files in jars, or even extend the URL handlers for a custom game "pak" file design if i want. Also i have used the JOrbis with it, i don't recall having any problems. 

I have no special talents. I am only passionately curious.--Albert Einstein
Offline BoBear2681

JGO Coder


Medals: 18



« Reply #21 - Posted 2011-06-07 21:21:07 »

"/" is an escape character on Windows

I don't think this is right.  In what context can you something on Windows with '/'?
Offline philfrei
« Reply #22 - Posted 2011-06-07 22:30:25 »

Some headway with figuring out the specs on Ogg: the frame counts that I want are stored in the "Granule Position" portion of the header for every Page. An Ogg file comprises a series of Pages. So, I'm thinking one can maybe stream the file, parse the headers and "throw away" the vorbis compression data itself. A lot depends on how clear my head feels when I get to this later today!

I think, philosophically, one wants to use URL or InputStream as much as possible with a game, as that is the mechanism given for loading resources from a Jar. Creating a dependancy where one needs to write files on a client seems to me to be asking for avoidable trouble. The problem here is that the JOrbis code that provides VorbisFile info (such as frame length) relies on a RandomAccessFile implementation.

Yes, OggVorbis files can play back perfectly well without finding out the frame counts. My goal is a API that allows one to "overlap" file playback where the loop time can be specified via a plus or minus value added to the existing frame count. In other words, 0 = looping as usually implemented, -1000 would be start the second iteration one second before the end of the file, 1000 would be to leave a one second gap.  It's possible to make the API simply be one that uses an absolute, positive value, but I think the relative positioning will be a lot easier to use.

Another possible direction: I may instead make a pre-compilation utility that extracts frame counts and stores a text file of file names and frame lengths, then pack the resulting text file with the ogg files as a resource amd load it into a HashMap at game loading time. It adds a step when compiling, but it is a small step. The game time savings would only occur during loading, but if one is building soundscapes with 1000's of SFX files, I suppose that could make it worth something.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline philfrei
« Reply #23 - Posted 2011-06-08 07:57:04 »

Yeah, made the pre-compilation thang.
The utility opens each audio file and puts its file name and frame length into a text file. Does them all, in one swoop. Then, the program opens this file with a Scanner (which can run off of resource's InputStream) and loads a HashMap that can be consulted when I make my various multiple-Cue-playing constructs and want to know cue timings.

It seems like a bit of a cop out to go so far with possibly adding to JOrbis, but I think this may be a more practical design, long range. I kind of like having some of the functionality of this system out of reach of decompilers, as well as decreasing the startup load.

Anyway, it works! And an exported Jar is running some looping .ogg cues like a charm. So, maybe time to detour and go back an build this stuff into Hexara. We should be able to drop its 3 minute load time down to about 15-20 seconds.

Thanks, all!

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (31 views)
2014-04-15 18:08:23

BurntPizza (28 views)
2014-04-15 03:46:01

UprightPath (43 views)
2014-04-14 17:39:50

UprightPath (26 views)
2014-04-14 17:35:47

Porlus (43 views)
2014-04-14 15:48:38

tom_mai78101 (64 views)
2014-04-10 04:04:31

BurntPizza (124 views)
2014-04-08 23:06:04

tom_mai78101 (224 views)
2014-04-05 13:34:39

trollwarrior1 (190 views)
2014-04-04 12:06:45

CJLetsGame (198 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!