… oder wie soll ich die Grafik von MS deuten?
Quelle: http://joeduffyblog.com/2013/12/27/csharp-for-systems-programming/
… oder wie soll ich die Grafik von MS deuten?
Quelle: http://joeduffyblog.com/2013/12/27/csharp-for-systems-programming/
To shorten things and not to repeat ourselves (usually the closing always looks the same) Google Commons offers the utility class com.google.common.io.Closeables. In this class you can find two static helper methods close(Closeable) and closeQuietly(Closeable). Both take an argument of type Closeable—like a FileInputStream—and call the close() method on this object eventually. If the argument is null, nothing happens; in our hand-coded version we use an extra if (out != null) to prevent a NullPointerException from out.close() if out is null.
The following example uses Closeable.closeQuietly(Closeable) to close a stream. Any potential IOExceptions caused by close() is swallowed by closeQuietly().
package com.tutego.googlecommon.io;
import java.io.*;
import java.util.logging.*;
import com.google.common.io.*;
public class CloseablesDemo {
private static final Logger log = Logger.getLogger( CloseablesDemo.class.getName() );
public static void main( String[] args ) {
InputStream in = null;
try {
in = Resources.getResource( CloseablesDemo.class, „test.txt“ ).openStream();
BufferedReader br = new BufferedReader( new InputStreamReader( in, „utf-8“ ) );
System.out.println( br.readLine() );
} catch ( IOException e ) {
log.log( Level.SEVERE, „IOException thrown while reading line“, e );
} finally {
Closeables.closeQuietly( in );
}
}
}
Using closeQuietly() shortens a program but it does not notify about any exception caused by the inner close() method. A lot of programmers ignore this exception and shortens there closing block to
try { out.close(); } catch ( Exception e ) {}
This style is dangerous, usually not for readers but for all modifying writers. If a writing stream can’t be closed the IOException shows a severe problem that probably the output is not complete and data is missing. For that reason the utility class Closeable offers a second message, close() which, in contrast to closeQuietly() first is denoted by an IOException clause and secondly controls with a boolean parameter if in case of an IOException caused by close() this exception should be swallowed or rethrown.
To summarize these methods:
class Closeables
static void close(Closeable closeable, boolean swallowIOException) throws IOException
Closes the closeable if it is not null. The boolean parameter controls whether an exception will be rethrown (pass false for swallowIOException) or swallowed (pass true).
static void closeQuietly Closeable closeable)
If closeable is not null this method calls closeable.close(). If close() throws an IOException this exception is swallowed by closeQuietly().Because closeQuietly(closeable) swallows the exception it is internally written as close(closeable, true).
Die Änderungen sind im Wiki dokumentiert: und referenziert https://code.google.com/p/guava-libraries/wiki/Release16.
Die Änderungen sind im Wiki dokumentiert: und referenziert https://code.google.com/p/guava-libraries/wiki/Release16.
Neu in Java 8 ist die Methode find(…) in Files um Dateien nach gewissen Kriterien zu finden.
final class java.nio.file.Files
Beispiel und Hinweis: Finde alle Ordner unter dem Standard-Windows Bilder-Verzeichnis und gib sie aus:
Files.find( Paths.get( System.getProperty( „user.home“ ) )
.resolve( „Pictures“ ),
Integer.MAX_VALUE,
(p,attr) -> Files.isReadable( p ) && attr.isDirectory()
).forEach( System.out::println );
Intern greift find(…) auf den gleichen Mechanismus wie walk(…) zurück, doch ist eine Eigenimplementierung mit Hilfe von walk(…) mitunter besser, da wir beim visitFileFailed(…) Fehler ignorieren können – bei find(…) führen Fehler direkt zum Abbruch. Bei Windows führt eine rekursive Suche schnell zu einem java.nio.file.AccessDeniedException durch einen Ordner, bei dem Java nicht dran darf und dann ist mit find(…) sofort Schluss.
Die Utility-Klasse Files bietet vier statische Methoden (zwei mehr in Java 8), die, bei einem Startordner beginnend, die Verzeichnisse rekursiv ablaufen.
final class java.nio.file.Files
Bei allen Varianten bestimmt der erste Parameter den Startordner. Während walk(…)einen java.util.stream.Stream liefert (die Methoden sind neu in Java 8), erwarten die anderen beiden walkFileTree(…)-Methoden ein Objekt mit Callback-Methoden, die walkFileTree(…) beim Ablaufen des Verzeichnisbaums aufruft
In der Klasse Files finden sich vier Methoden (eine mehr unter Java 8), um zu einem gegebenen Verzeichnis alle Dateien und Unterverzeichnisse aufzulisten:
final class java.nio.file.Files
Die Rückgabe DirectoryStream<T> ist ein Closeable (und somit AutoCloseable) sowie Iterable<T>, und so unterscheidet sich die Möglichkeit zur Anfrage der Dateien im Ordner grundsätzlich von der Methode list(…) in der Klasse File, die immer alle Dateien in einem Feld auf einmal zurückliefert. Bei einem DirectoryStream wird Element für Element über den Iterator geholt; trotz des Namensanhangs „Stream“ ist der DirectoryStream kein Strom im Sinne von java.util.stream. Ein Stream<String> hingegen liefert die kompakte Methode list(Path), sie nutzt intern einen DirectoryStream.
try ( DirectoryStream<Path> files =
Files.newDirectoryStream( Paths.get( „c:/“ ) ) ) {
for ( Path path : files )
System.out.println( path.getFileName() );
}
Aus der Tatsache, dass die Dateien und Unterverzeichnisse nicht in einem Rutsch geholt werden, leitet sich die Konsequenz ab, dass der DirectoryStream/Stream<String> geschlossen werden muss, da nicht klar ist, ob der Benutzer wirklich alle Dateien abholt oder nach den ersten 10 Einträgen aufhört. Die Schnittstelle DirectoryStream erweitert die Schnittstelle Closeable (und die ist AutoCloseable, weshalb unser Beispiel ein try-mit-Ressourcen nutzt) und Stream implementiert AutoCloseable, daher ist es guter Stil, den DirectoryStream/Stream am Ende zu schließen, um blockierte Ressourcen freizugeben. try-mit-Ressourcen gibt immer etwaige Ressourcen frei, auch wenn es beim Ablaufen des Verzeichnisses zu einer Ausnahme kam.
Da die Klasse Path nur Pfade, aber keine Dateiinformationen wie die Länge oder Änderungszeit repräsentiert und Path auch keine Möglichkeit bietet, Dateien anzulegen und zu löschen, übernimmt die Klasse Files diese Aufgaben.
Mit den Methoden readAllBytes(…), readAllLines(…), lines(…) bzw. write(…) kann Files einfach ein Dateiinhalt einlesen oder Strings bzw. ein Byte-Feld schreiben.
URI uri = ListAllLines.class.getResource( „/lyrics.txt“ ).toURI();
Path path = Paths.get( uri );
System.out.printf( „Datei ‚%s‘ mit Länge %d Byte(s) hat folgende Zeilen:%n“, path.getFileName(), Files.size( path ) );
int lineCnt = 1;
for ( String line : Files.readAllLines( path /*, StandardCharsets.UTF_8 vor Java 8 */) )
System.out.println( lineCnt++ + „: “ + line );
final class java.nio.file.Files
Die Aufzählung OpenOption ist ein Vararg, und daher sind Argumente nicht zwingend nötig. StandardOpenOption ist eine Aufzählung vom Typ OpenOption mit Konstanten wie APPEND, CREATE, …
Hinweis: Auch wenn es naheliegt, die Files-Methode zum Einlesen mit einem Path-Objekt zu füttern, das ein HTTP-URI repräsentiert, funktioniert dies nicht. So liefert schon die erste Zeile des Programms eine Ausnahme des Typs »java.nio.file.FileSystemNotFoundException: Provider „http“ not installed«.
Path path = Paths.get( new URI „http://tutego.de/javabuch/aufgaben/bond.txt“ ) );
List<String> content = Files.readAllBytes( path );
System.out.println( content );
Vielleicht kommt in der Zukunft ein Standard-Provider von Oracle, doch es ist davon auszugehen, dass quelloffene Lösungen diese Lücke schließen werden. Schwer zu programmieren sind Dateisystem-Provider nämlich nicht.
Sollen die Daten nicht direkt aus einer Datei in eine byte-Feld/String-Liste gehen bzw. aus einer byte-Feld/String-Sammlung in eine Datei, sondern von einer Datei in einen Datenstrom, so bieten sich zwei copy(…)-Methoden an:
final class java.nio.file.Files
Neben den statischen Files-Methoden newOutputStream(…) und newInputStream(…) gibt es zwei Methoden, die zeichenorientierte Ströme liefern, also Writer/Reader.
final abstract java.nio.file.Files
BufferedReader und BufferedWriter sind Unterklassen von Reader/Writer die zum Zwecke der Optimierung Dateien im internen Puffer zwischenspeichern.
Die MAC-Adresse (von Media-Access-Control) ist eine (im Idealfall) eindeutige Adresse eines Netzwerkgeräts. MAC-Adressen sind für Ethernet-Verbindungen essenziell, da auf der physikalischen Übertragungsebene Signale zu einer gewünschten Netzwerkkarte aufgebaut werden. Wegen der Eindeutigkeit eignen sie sich gut als Schlüssel, und es ist interessant, auch in Java diese Adresse auszulesen. Das geht mit der Klasse NetworkInterface recht unkompliziert. Alle lokale Netzwerkschnittstellen liefert NetworkInterface.getNetworkInterfaces(), ist die IP-Adresse bekannt, können wir NetworkInterface.getByInetAddress(InetAddress) nutzen.
for ( NetworkInterface ni : Collections.list( NetworkInterface.getNetworkInterfaces() ) ) { byte[] adr = ni.getHardwareAddress(); if ( adr == null || adr.length != 6 ) continue; String mac = String.format( "%02X:%02X:%02X:%02X:%02X:%02X", adr[0], adr[1], adr[2], adr[3], adr[4], adr[5] ); System.out.println( mac ); }
Auf der Windows Kommandozeile liefert ipconfig /all alle MAC-Adressen, die dort „physikalische Adresse” heißen.
Details siehe http://wiki.apidesign.org/wiki/IOS.
Laut Media Control ist mein Java-Buch das bestverkaufte Computing-Buch des Jahres 2013. Ausgewertet wurden alle Titel zu Computing-Themen (Programmierung, Netze, Server, Web ) aller Verlage.
import java.util.concurrent.atomic.AtomicInteger; import javafx.application.Application; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; import javafx.scene.Cursor; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Polygon; import javafx.stage.Stage; class DrawingPane extends Pane { public DrawingPane( Image image, Polygon poly ) { poly.setFill( Color.web( "ANTIQUEWHITE", 0.8 ) ); poly.setStroke( Color.web( "ANTIQUEWHITE" ) ); poly.setStrokeWidth( 2 ); getChildren().addAll( new ImageView( image ), poly ); for ( int i = 0; i < poly.getPoints().size(); i += 2 ) { Circle circle = new Circle( poly.getPoints().get( i ), poly.getPoints().get( i + 1 ), 5 ); circle.setFill( Color.web( "PERU", 0.8 ) ); circle.setStroke( Color.PERU ); circle.setStrokeWidth( 2 ); AtomicInteger polyCoordinateIndex = new AtomicInteger( i ); circle.centerXProperty().addListener( new ChangeListener<Number>() { @Override public void changed( ObservableValue<? extends Number> observable, Number oldValue, Number newValue ) { poly.getPoints().set( polyCoordinateIndex.get(), newValue.doubleValue() ); } } ); circle.centerYProperty().addListener( new ChangeListener<Number>() { @Override public void changed( ObservableValue<? extends Number> observable, Number oldValue, Number newValue ) { poly.getPoints().set( polyCoordinateIndex.get() + 1, (Double) newValue ); } } ); setDragHandler( circle ); getChildren().add( circle ); } } private double dragDeltaX, dragDeltaY; private void setDragHandler( Circle circle ) { circle.setOnMousePressed( new EventHandler<MouseEvent>() { @Override public void handle( MouseEvent mouseEvent ) { dragDeltaX = circle.getCenterX() - mouseEvent.getSceneX(); dragDeltaY = circle.getCenterY() - mouseEvent.getSceneY(); } } ); circle.setOnMouseDragged( new EventHandler<MouseEvent>() { @Override public void handle( MouseEvent mouseEvent ) { circle.setCenterX( mouseEvent.getSceneX() + dragDeltaX ); circle.setCenterY( mouseEvent.getSceneY() + dragDeltaY ); circle.setCursor( Cursor.MOVE ); } } ); circle.setOnMouseEntered( new EventHandler<MouseEvent>() { @Override public void handle( MouseEvent mouseEvent ) { circle.setCursor( Cursor.HAND ); } } ); circle.setOnMouseReleased( new EventHandler<MouseEvent>() { @Override public void handle( MouseEvent mouseEvent ) { circle.setCursor( Cursor.HAND ); } } ); } } public class JavafxDemo extends Application { @Override public void start( Stage stage ) { Image image = new Image( "http://tours-tv.com/uploads/maps/map-Medizinische-Hochschule-Hannover-karta.jpg" ); Polygon poly = new Polygon( 10, 10, 100, 10, 200, 100, 50, 200 ); stage.setScene( new Scene( new DrawingPane( image, poly ), 450, 300 ) ); stage.show(); } public static void main( String[] args ) { launch( args ); } }
import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.application.Application; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.CubicCurve; import javafx.scene.shape.Line; import javafx.stage.Stage; import javafx.util.Duration; public class CubicCurveDemo extends Application { @Override public void start( Stage stage ) { double startX = 200, startY = 200; DoubleProperty controlX1 = new SimpleDoubleProperty( 20 ); DoubleProperty controlY1 = new SimpleDoubleProperty( 20 ); DoubleProperty controlX2 = new SimpleDoubleProperty( 400 ); DoubleProperty controlY2 = new SimpleDoubleProperty( 20 ); double endX = 300, endY = 200; // Linie von [controlX1, controlY1] nach [startX, startY] Line line1 = new Line( 0, 0, startX, startY ); line1.startXProperty().bind( controlX1 ); line1.startYProperty().bind( controlY1 ); line1.setStrokeWidth( 2 ); // Linie von [controlX2, controlY2] nach [endX, endY] Line line2 = new Line( 0, 0, endX, endY ); line2.startXProperty().bind( controlX2 ); line2.startYProperty().bind( controlY2 ); line2.setStrokeWidth( 2 ); // Animierte Kontrollpunkte Timeline timeline = new Timeline( new KeyFrame( Duration.millis( 1000 ), new KeyValue( controlX1, 300 ), new KeyValue( controlY2, 300 ) ) ); timeline.setCycleCount( Timeline.INDEFINITE ); timeline.setAutoReverse( true ); timeline.play(); CubicCurve curve = new CubicCurve( startX, startY, 0, 0, 0, 0, endX, endY ); curve.controlX1Property().bind( controlX1 ); curve.controlY1Property().bind( controlY1 ); curve.controlX2Property().bind( controlX2 ); curve.controlY2Property().bind( controlY2 ); curve.setFill( null ); curve.setStroke( Color.BLUEVIOLET ); curve.setStrokeWidth( 3 ); stage.setScene( new Scene( new Group( line1, line2, curve ), 450, 300 ) ); stage.show(); } public static void main( String[] args ) { launch( args ); } }
Siehe http://dooapp.github.io/FXForm2/, Änderungen der Updates bei http://blog.dooapp.com/2013/11/fxform-two-releases-and-lot-of-new.html.
Nicht immer kommen die Bilder vom Datensystem oder aus dem Internet. Mit der Java-Bibliothek lassen sich einfach auch eigene (Buffered)Image-Objekte anlegen. Dazu bieten sich – wieder historisch bedingt – verschiedene Varianten an:
Ein Bild über createCompatibleImage(…) zu erzeugen, hat den großen Vorteil, dass das Daten- und Farbmodell optimal gewählt ist. Der einzige Nachteil dieser Methode ist die große Menge an benötigten Hilfsobjekten – was zusätzliche Schreibarbeit bedeutet:
GraphicsConfiguration gfxConf = GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().getDefaultConfiguration();
int width = 600, height = 400;
BufferedImage image = gfxConf.createCompatibleImage( width, height );
Neben createCompatibleImage(int, int) gibt es auch eine Variante, die die Angabe einer Transparenz ermöglicht.
abstract class java.awt.GraphicsConfiguration
Image-Objekte (BufferedImage ist eine Unterklasse) geben über getGraphics() das Graphics-Objekt zurück, mit dem sich das Bild bemalen lässt. Im Fall eines speziellen BufferedImage-Objekts ist es jedoch üblich, die Methode createGraphics() einzusetzen, da sie ein Graphics2D-Objekt – eine Unterklasse von Graphics – liefert, mit dem weitere Zeichenoperationen möglich sind. Außerdem ruft getGraphics() sowieso createGraphics() auf …
Beispiel: Initialisiere ein Bild img mit weiß.
Graphics2D g = img.createGraphics();
g.setColor( Color.WHITE );
g.fillRect( 0, 0, b – 1, h – 1 );
Alternativ kann zum Löschen des Hintergrunds auch g.setBackground(Color.WHITE); g.clearRect(…); verwendet werden.
Der Konstruktor der Klasse BufferedImage wird mit den Maßen parametrisiert und zusätzlich mit einem Speichermodell für die Bildinformationen. Das ermöglicht die Verwendung von beliebigen Farb- und Speichermodellen:
int h = 400,
b = 600;
BufferedImage img = new BufferedImage( b, h, BufferedImage.TYPE_INT_RGB );
Das notwendige dritte Argument kennzeichnet den Speichertyp; hier sind die Farben durch je 8 Bit Rot, Grün und Blau abgebildet. Um weitere 2 der über 10 Bildtypen zu nennen: TYPE_USHORT_GRAY (Graubilder) oder TYPE_INT_ARGB (RGB mit jeweils 8 Bit sowie Alpha).
class java.awt.image.BufferedImage
extends Image
implements RenderedImage, Transparency, WritableRenderedImage
[1] Details finden Sie unter http://weblogs.java.net/blog/chet/archive/2004/08/toolkitbuffered.html.
Die auf allen Systemen vordefinierten Standardzeichensätze sind etwas dürftig, obwohl die Font-Klasse selbst jeden installierten Zeichensatz einlesen kann. Da ein Java-Programm aber nicht von der Existenz eines bestimmten Zeichensatzes ausgehen kann, ist es praktisch, einen Zeichensatz mit der Installation auszuliefern und dann diesen zu laden; das kann die Font-Klasse mit der statischen Methode createFont(…) sein. Aus einem Eingabestrom liest die Methode den TrueType-Zeichensatz und erstellt das entsprechende Font-Objekt, Bsp.:
Font font = Font.createFont( Font.TRUETYPE_FONT,
getClass().getResourceAsStream( „/NASALIZA.TTF“) );
Das erste Argument ist immer Font.TRUETYPE_FONT. Das zweite Argument bestimmt den Eingabestrom zur Binärdatei mit den Zeichensatzinformationen. Die Daten werden ausgelesen und zu einem Font-Objekt verarbeitet.
Waren die Beschreibungsinformationen in der Datei ungültig, so erzeugt die Font-Klasse eine FontFormatException(„Unable to create font – bad font data“). Dateifehler fallen nicht darunter und werden extra über eine IOException angezeigt. Der Datenstrom wird anschließend nicht wieder geschlossen.
An dieser Stelle verwundert es vielleicht, dass die Arbeitsweise der statischen Methode createFont(…) der des Konstruktors ähnlich sein müsste, aber der Parameterliste die Attribute fehlen. Das liegt daran, dass die Methode automatisch einen Zeichensatz der Größe 1 im Stil Font.PLAIN erzeugt. Um einen größeren Zeichensatz zu erzeugen, müssen wir ein zweites Font-Objekt anlegen, was am einfachsten mit der Methode deriveFont(…) geschieht.
class java.awt.Font
implements Serializable
Soll nicht direkt der Font verwendet werden, sondern soll der Zeichensatz unter seinem Namen in den Namensraum gelegt werden, sodass er später auch über den Font-Konstruktor gefunden werden kann, lässt er sich mit registerFont(Font) anmelden. Das sieht etwa so aus:
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont( font );