Resource to File

@Fancy : was ist daran dynamisch / automatisch?

Deswegen habe ich noch affe.png und xbild.png eingefügt, weil die alle verschiedene namen haben…

jar file sehe ich mir mal an, danke.
nio2 - ist das ein framework, oder eine library? wenn nicht guck ichs mir an, ebenfalls danke. ich arbeite unter java 7.

NIO bzw. ab Java 7 NIO 2 ist Bestandteil von Java SE und die Klassen bzw. Interfaces befinden sich im Package java.nio. Brauchst also nichts extra zu laden und einzubinden oder dergleichen, ist alles dabei.

Gar nichts! :wink:

Aber überlege mal, was Du mit Deinem dynamisch geladenem Array machen würdest. Du weißt nicht, an welcher Stelle welches Bild steht, da die Reihenfolge von vielen Faktoren abhängt. Wenn Du also nun z.B. Dein Affenbild darstellen willst, musst Du es irgendwie bestimmen/benennen, um darauf zugreifen zu können. Spätestens dann ist es mit der Dynamik also sowieso dahin.

Der Vorteil mit dem Enum ist das an genau einer Stelle Deine Bilder geladen werden und anschließend typsicher im Programm zur Verfügung stehen. Kommt ein neues Bild hinzu, musst Du eine Stelle im Programm ändern. Fehlt eines der Bilder, wird sofort eine Exception geworfen.

Wenn ich Dich allerdings falsch verstanden habe und Du an dem konkreten Inhalt Deines Arrays gar nicht interessiert bist, dann trifft das so natürlich nicht zu. Allerdings brauchst Du dann vermutlich kein (Array)List, sondern ein Set würde vermutlich reichen.

Viele Grüße
Fancy

naja, das wäre ja eigentlich auch egal, denn darum gehts hier nicht ^^
trozdem danke für den vorschlag.

Noch mal eine Frage:

Ist es überhaupt möglich, das es sowohl in der ide als auch als jar datei funktioniert?

Also ein Jar-Archiv verzeichnisweise zu scannen ist nicht wirklich trivial, zumal Verzeichnisse in solchen (selbiges gilt für Zip-Archive) gar nicht existieren. Das ist der Grund, warum keine leeren Verzeichnisse gezipped werden können. Demnach geht das nur per JarFile, JarInputStream und “.getName().startsWith(“myPath”)”, wobei “myPath” das absolute Verzeichnis innerhalb der Jars ist.
In deinem Fall nützt dir auch “getClass().getRessource()” nichts, das müsste wenn schon “getClass.gerClassLoader().getRessource()” heissen. der Unterschied ist, dass der ClassLoader im Gegensatz zu Class nicht pfadrelativ funktioniert. Aber auch dass funzt aus den zuvor genannten Gründen nicht mit Verzeichnissen.
In der IDE (Eclipse) funktioniert es eigentlich auch nur FÄLSCHLICHERWEISE! Dieses Verhalten der IDE ist also nicht 100%ig korrekt. Und nein, für Archive gibt es keinen einfacheren Weg, ausser jenen, sich selbst ein Directory mit Verzeichniseinträgen zu basteln.

import java.net.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;

public final class JarFile {
	private final URL jarBase, base;
	private final Manifest mf;
	private final Set<URL> dir;

	JarFile(URL base, Manifest mf) throws IOException {
		InputStream in = base.openStream();
		this.base = base;
		jarBase = new URL("jar:" + base.toString() + "!/");
		this.mf = mf;
		dir = new HashSet<>();
		try {
			JarInputStream jin = new JarInputStream(in);
			ZipEntry je;
			while ((je = jin.getNextEntry()) != null) {
				String[] dirs = je.getName().split("/");
				for (int n = 0; n < dirs.length; n++) {
					dir.add(new URL(jarBase, dirs[0]));
					if (n < dirs.length - 1) {
						dirs[0] += "/" + dirs[n + 1];
					}
				}
			}
			jin.close();
		} catch (IOException e) {
			try {
				dir.add(new URL(jarBase, "<<<broken>>>"));
			} catch (MalformedURLException ee) {
				// ignore
			}
		}
	}

	public URL getBaseURL() {
		return base;
	}

	public URL getContentURL() {
		return jarBase;
	}

	public Collection<URL> list(JarEntry entry) {
		HashSet<URL> rc = new HashSet<>();
		String entryName = entry.getName();
		for (URL u : dir) {
			String name = u.toString().replace(jarBase.toString(), "");
			if (name.contains(entryName)) {
				rc.add(u);
			}
		}
		return Collections.unmodifiableCollection(rc);
	}

	public Collection<URL> list() {
		return Collections.unmodifiableCollection(dir);
	}

	public Manifest getManifest() {
		return mf;
	}

	public boolean contains(JarEntry entry) {
		try {
			return dir.contains(new URL(jarBase, entry.toString()));
		} catch (MalformedURLException e) {
			return false;
		}
	}
}```

wenn der Ordner als resource in der ide ist, so ist das laden das selbe wie vom jar

könntest du das genauer erleutern?

Es ist vollkommen egal, ob aus einer IDE gestartet oder ob es eine Jar ist oder sonst was. Es kommt für Ressourcen nur drauf an, ob diese im Classpath liegen. Wenn ja, dann kann man auf diese immer auf dieselbe Weise zugreifen (die getResource-Methoden). Vorteil dabei ist, dass z.B. so ein Ordner, der in den Classpath aufgenommen wurde, sonst wo liegen kann, er muss nicht im “Programmverzeichnis” oder daneben oder sowas liegen. Man muss nur drauf achten, dass beim Start des Programms der Classpath richtig gesetzt wird. So, klingt alles schön und gut, leider hat diese Vorgehensweise auch einen Nachteil. Schreibzugriffe sind so nicht möglich, zumindest nicht, wenn die Ressource, auf die man zugreift, sich innerhabl eines Archives befindet. Ob Schreibzugriffe bei Ressourcen, die vom Dateisystem aus geladen werden, funktionieren, habe ich noch nie ausprobiert, aber ist auch eher unwichtig, denn wenn ich Schreibzugriffe habe, dann natürlich über das entsprechende Vorgehen auf dem Dateisystem, dafür ist der Classpath in meinen Augen eher ungeeignet. Aber wie gesagt, alles, was sich innerhalb von Archiven, also auch von Jars, befindet, ist nicht über File ansprechbar. Also musst du das Archiv entweder zuerst entpacken (kann ja auch die anwendung selbst übernehmen) oder aber über alternative Wege auf die Inhalte zugreifen, z.B. JarFile, als Ressource laden oder über NIO2.

Was das jetzt mit einer IDE zu tun hat, ist, dass die gängingen IDEs s.g. Source-Folder im Projekt anlegen können (meist ist src so ein Source-Folder). Alles, was sich in den Source-Foldern befindet, wird beim Kompilieren in die Ausgabeordner (bin, out, output, classes, target, whatever) kopiert und ist dann ebenfalls über den Classpath verfügbar. Kann auch sein, dass diese Dateien dann auch über Dateisystemzugriffe in Relation zur Anwendung verwendbar sind, aber das muss nicht sein, denn Eclipse z.B. setzt als working directory das Projektverzeichnis und nicht den bin-Ordner (das muss man wissen, das führt bei vielen zu imensen Problemen und falschem Verständnis für die gesamte Materie bezüglich Ressourcen und Dateiorganisation der Anwendung). Dieser lässt sich aber auch ändern, aber ist nicht nötig, habe ich jedenfalls noch nie gebraucht. Einfach lernen mit dem Classpath richtig zu arbeiten, dann muss man über sowas auch nicht nachdenken.

gibts da irgendwelche links für anfänger oder so?
und gibt es da eine klare antwort auf meine frage - geht es oder eben nicht? Das es, egal wie mans startet, funktioniert?

natuerlich geht es…

https://www.google.dk/search?q=java+load+resources -> StackOverflow gibt immer gute Hinweise. Es ist auch ein Video unter den Links. Vielleicht hilft da was

Wohl bemerkt! Der Zugriff über File funktioniert innerhalb von Jar-Archiven natürlich nicht. Dort funktionieren nur URLs (->“jar:file://myPath/myJar.jar!/”) und das auch nur auf File-Resourcen und nicht auf Verzeichnis-Ressourcen (letztere existieren in einem Jar nun mal nicht).

@Akeshihiro : Was das mit 'ner IDE zu tun hat? Eclipse z.B. macht sich beim Testen in der Entwicklungsphase nicht die Mühe, die Klassen in Jars zu packen. Der Classpath wird schlicht auf den Binary-Ordner des Projektes erweitert. Innerhalb von Eclipse kann man also während der Entwicklung per Fileprotokoll auf die Ressourcen zugreifen, was nach dem packen in ein Archiv natürlich nicht mehr funktioniert.

Das ist richtig, aber eben genau darum soll man da ja auch gewissenhaft arbeiten. Wenn ich eine Ressource als Resource lade und nicht über ein Dateisystem, dann muss ich mich logischerweise nur auf Leseoperationen beschränken, denn es kann später richtigerweise sein, dass das alles in einer Jar rumliegt oder in einem Zip-Archiv oder auch was völlig anderes. Man sollte sich daher lieber mit dem Gedanken anfreunden, dass alles, was innerhalb eines Projektes rumliegt, prinzipiell nicht als Datei anzusehen ist, sondern als Ressource, es sei denn ich weiß bei bestimmten Dateien ganz sicher, dass diese nicht verpackt sein werden.

Meine Grundregel für sowas war und ist daher: Ressourcen, die ich lesend verwende, locker und ohne große Überlegungen über den Classpath laden, was auch immer alles im Classpath sein mag, und alles, was ich beschreiben will, ausschließlich über eine Dateisystemabstraktion ansprechen, nach alter Vorgehensweise also File-Objekte und Streams. Daran sind also keinewegs die IDEs schuld, wenn das falsch gemacht wird, so nach dem Motto “aber in Eclipse funtionierts doch”. Hinzu kommen auch noch ganz andere Geschichten wie Arbeitsverzeichnis etc. pp. Das sind alles Sachen, die existieren, die haben per Default eine gewisse Arbeitsweise, die aber geändert werden kann und im Endeffekt ist alles über ein Dateisystem verstreut oder vielleicht sogar im Netzwerk und man arbeitet nie auch nur in der Nähe der gestarteten Jar-Datei der Anwendung. Das sind alles Dinge, die sollte man beachten und möglichst schnell lernen mit ihnen richtig umzugehen, sonst wird es immer wieder wegen falscher Handhabung knallen.

und genau deswegen frage ich auch sowas :stuck_out_tongue:

Tja, viel was kann ich dir da so aus dem Stehgreif nicht mitgeben. Aber mit den Stichpunkten “java resource getresource classpath” solltest du mit Google eigentlich eine Menge finden, gerade bei Stackoverflow gibt es da jede menge gute Beiträge. Ansonsten eigentlich nur ein bisschen damit rumspielen, so habe ich sehr viel darüber erfahren.

um es mal zusammenzufassen:

ich schon seit einem monat nach einer allgemeingültigen lösung um in java ein “verzeichniss” unabhängig
von jar oder ide und grösse und inhalt auszulesen.

Mit dem classpath dingsbums habe ich mich aber noch kein einziges mal auseinandergesetzt, eine klare lösung
konnte auch noch keiner bieten.

Naja dann versuch ichs mal mit classpath und gucke mal ob ich verstehe was das überhaupt ist…

[QUOTE=mymaksimus]…eine klare lösung konnte auch noch keiner bieten.[/QUOTE]Das ist nicht ganz richtig…
Wenn es nur um das Laden von Dateien (Ressourcen) geht, solltest du Zugriffe auf das Filesystem weit hinter dir lassen und nur noch mit URLs arbeiten. Da gibt es zwar keine Verzeichniscrawler, aber die sind ja auch nicht wichtig, weil es andere Mittel und Wege gibt, Ressourcenamen festzulegen.
Streams bekommt man von URLs auch (".openStream()") und dabei ist es egal, ob die URL in ein Filesystem oder ins Netzwerk führt. Wenn man sich erstmal dran gewöhnt hat das meiste über URLs zu machen, ists einfacher als irgendwas mit Files zu versuchen.

ja sry, ich klinge immer so als würde ich allen etwas unterstellen… tut mir leid
das war eigentlich kritik an mich selbst, weil ich nicht in der lage bin lösungsvorschläge umzusetzen…
gut, ich verzichte in zukunft auf files… Wieso sollte man java programme auch so unkomfortabel in ordnern ausliefern - eine doppelklickdatei ist doch viel praktischer

okay aber trozdem:
wie könnte ich das nun ganz konkret machen? (das ziel ist ja bereits bekannt)
openStream() gibt mir wieder eine url zurück - was mach ich jetzt mit der um an die dateinamen zu kommen?

openStream() gibt dir einen InputStream und keine URL.

Um an den Dateinamen zu kommen, müsstest du an deinem URL-Objekt nicht openStream() aufrufen, sondern getFile().

Als Tipp am Rande: Die API von Java ist immer gut für sowas. Da die Suche auf dieser Weise aber vielleicht eher unkomfortabel sein kann, bei Google java api und dann das, was man sich anschauen möchte, eingeben, z.B. java api url, funktioniert oft auch nur mit Methodennamen. Das hier ist die API zur URL-Klasse, da kannst du das sehr gut nachschauen.

gut werde ich machen. ääh ja ich meine ja input stream und nicht url sry. aber moment… wenn ich mit getFile() an den dateinamen komme… dann muss ich den dateinamen ja schon kennen sonst würde ich ja nicht an die url kommen… oh man ich blick nich mehr duch :frowning:

@Akeshihiro : Nu verwirr den Jungen doch nicht so…

Also ja, eine URL hat eine “getFile()”-Methode… Diese nutzt einem aber auch nur etwas, wenn das URL-Protokoll “file” lautet. In allen anderen Protokollen ist dies, wenn überaupt vorhanden, eine Filereferenz auf ein entferntes Filesystem oder auf ein Archiv.
@mymaksimus : Komm also nicht auf die Idee, diese Referenz nutzen zu wollen.