Slide navigation: Forward with space bar, → arrow key, or PgDn. Backwards with ← or PgUp.
Copyright © Cay S. Horstmann 2016
java.util.stream
java.nio.file.Files
class:
Path path = Paths.get(filenameString); // We'll cover paths later this lesson InputStream in = Files.newInputStream(path); OutputStream out = Files.newOutputStream(path);
URL url = new URL("http://horstmann.com/index.html"); InputStream in = url.openStream();
byte[]
array:
byte[] bytes = ...; InputStream in = new ByteArrayInputStream(bytes);
ByteArrayOutputStream
and then collect the bytes:
ByteArrayOutputStream out = new ByteArrayOutputStream(); Write to out byte[] bytes = out.toByteArray();
read
method returns a single byte (as an int
) or -1 at the end of input:
InputStream in = ...; int b = in.read(); if (b != -1) { byte value = (byte) b; ... }
byte[] bytes = ...; int len = in.read(bytes);
ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; while ((len = in.read(bytes)) != -1) out.write(bytes, 0, len); bytes = out.toByteArray();
byte[] bytes = Files.readAllBytes(path);
OutputStream out = ...; int b = ...; out.write(b); byte[] bytes = ...; out.write(bytes); out.write(bytes, start, length);
out.close();
try
-with-resources block:
try (OutputStream out = ...) { out.write(bytes); }
Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
byte[] bytes = url.openStream().readAllBytes();There is also
readNBytes
.InputStream.transferTo(OutputStream)
transfers all bytes from an input stream to an output stream.Reader.transferTo(Writer)
PrintWriter
, Scanner
, etc. can be specified as Charset
instead of String
new Scanner(path, StandardCharsets.UTF_8)
Scanner.tokens
gets a stream of tokens, similar to Pattern.splitAsStream
from Java 8:
Stream<String> tokens = new Scanner(path).useDelimiter("\\s*,\\s*").tokens();
StandardCharsets.UTF_8
for Charset
parameters, "UTF-8"
for string parameters.Reader
for any input stream:
InputStream inStream = ...; Reader in = new InputStreamReader(inStream, charset);
read
method reads one char
value.
String content = new String(Files.readAllBytes(path), charset);
List<String> lines = Files.readAllLines(path, charset); try (Stream<String> lines = Files.lines(path, charset)) { ... }
import java.nio.file.*;
import java.nio.charset.*;
Files.readAllLines(Paths.get("poem.txt"), StandardCharsets.UTF_8)
Files.readAllLines(Paths.get("poem-win1252.txt"), StandardCharsets.UTF_8)
// Throws MalformedInputException
Files.readAllLines(Paths.get("poem-win1252.txt"), Charset.forName("windows-1252"))
// Ok
Files.readAllLines(Paths.get("poem.txt"), Charset.forName("windows-1252"))
// Looks weird
Scanner
to split input into numbers, words, and so on:
Scanner in = new Scanner(path, "UTF-8"); while (in.hasNextDouble()) { double value = in.nextDouble(); ... }
in.useDelimiter("\\PL+"); while (in.hasNext()) { String word = in.next(); ... }
import java.nio.file.*; import java.nio.charset.*; Scanner in = new Scanner(Paths.get("poem.txt"), "UTF-8"); while (in.hasNext()) System.out.println(in.next()); // Now try again with in.useDelimiter("\\PL+");
PrintWriter out = new PrintWriter(Files.newBufferedWriter(path, charset)); PrintWriter out = new PrintWriter(filenameString, charsetString);
out.print
, out.println
, or out.printf
to produce output.try (PrintWriter out = ...) { ... }
Files.write(path, contentString.getBytes(charset)); Files.write(path, lines, charset);
Files.write(path, lines, charset, StandardOpenOption.APPEND);
import java.nio.file.*; import java.nio.charset.*; PrintWriter out = new PrintWriter("test.txt", "UTF-8") for (int i = 1; i <= 100; i++) out.printf("%6d%n", i * i); // Now open another console and typecat squares.txt
out.close(); // In the other console, typecat squares.txt
Writer
object. Example: Throwable.printStackTrace(PrintWriter out)
StringWriter
:
StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer));
String stackTrace = writer.toString();
StringWriter writer = new StringWriter(); new Throwable().printStackTrace(new PrintWriter(writer)); writer.toString()
DataInput
/DataOutput
interfaces have methods readInt
/writeInt
, readDouble
/writeDouble
, and so on.DataInputStream
/DataOutputStream
:
DataInput in = new DataInputStream(Files.newInputStream(path)); DataOutput out = new DataOutputStream(Files.newOutputStream(path));
"r"
for reading or "rw"
for writing:
RandomAccessFile file = new RandomAccessFile(filenameString, "rw");
getFilePointer
method yields the current position (as a long
).seek
method moves to a new position.int value = file.readInt(); file.seek(file.getFilePointer() - 4); file.writeInt(value + 1);
FileChannel channel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE)
ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, channel.size());
get
, getInt
, getDouble
, and so on to read, and the equivalent put
methods to write:
int position = ...; int value = buffer.getInt(position); buffer.put(position, value + 1);
java memoryMap.MemoryMapTest /opt/jdk1.8.0/src.zip java memoryMap.MemoryMapTest2 /opt/jdk1.8.0/src.zip
Path
objects specify abstract path names (which may not currently exist on disk)./
or C:\
Paths.get
to create paths:
Path absolute = Paths.get("/", "home", "cay"); Path relative = Paths.get("myapp", "conf", "user.properties");
/
or \
is supplied for the default file system.Path homeDirectory = Paths.get("/home/cay");
p.resolve(q)
computes “p
then q
”.q
is absolute, that's just q
.p
, then follow q
:
Path workPath = homeDirectory.resolve("myapp/work");
resolve
is relativize
, yielding “how to get from p
to q
”.
Paths.get("/home/cay").relativize(Paths.get("/home/fred/myapp"))
yields "../fred/myapp"
.normalize
removes ./
or directory/../
and other redundancies.toAbsolutePath
makes a path absolute. Path p = Paths.get("/home", "cay", "myapp.properties"); Path parent = p.getParent(); // The path/home/cay
Path file = p.getFileName(); // The last element,myapp.properties
Path root = p.getRoot(); // The initial segment/
(null
for a relative path) Path first = p.getName(0); // The first element Path dir = p.subpath(1, p.getNameCount()); // All but the first element
for (Path component : path) { ... }
File
class, use:
File file = path.toFile(); Path path = file.toPath();
import java.nio.file.*; Path p = Paths.get(".") p = p.toAbsolutePath() p.resolve("../lesson2") p.resolve("../lesson2").normalize() p.getParent() p.getFileName() p.getRoot() p.getName(0) p.getNameCount()
Files.createDirectory(path); // All but the last component must exist Files.createDirectories(path); // Missing components are created
Files.createFile(path);
Path tempFile = Files.createTempFile(dir, prefix, suffix); Path tempFile = Files.createTempFile(prefix, suffix); Path tempDir = Files.createTempDirectory(dir, prefix); Path tempDir = Files.createTempDirectory(prefix);
Files.createTempFile(null, ".txt")
might return a path such as
/tmp/1234405522364837194.txt
Files.exists(path)
checks whether a path currently exists.Files.isDirectory(path)
, Files.isRegularFile(path)
, Files.isSymbolicLink(path)
to find out whether the path is a directory, file, or symlink.isHidden
, isExecutable
, isReadable
, isWritable
of the Files
class.Files.size(path)
reports the file size as a long
value.copy
or move
method:
Files.copy(fromPath, toPath); Files.move(fromPath, toPath);
Files.copy(fromPath, toPath, StandardCopyOption.REPLACE_EXISTING, SteandardCopyOption.COPY_ATTRIBUTES); Files.move(fromPath, toPath, StandardCopyOption.ATOMIC_MOVE);
Files.delete(path); // Throws exception if path
doesn't exist
boolean deleted = Files.deleteIfExists(path);
Files.list(dirpath)
yields a Stream<Path>
of the directory entries.try (Stream<Path> entries = Files.list(pathToDirectory)) { ... }
Files.walk(dirpath)
to visit all descendants of subdirectories as well.... java/nio/ByteBufferAsDoubleBufferB.java java/nio/charset java/nio/charset/CoderMalfunctionError.java java/nio/charset/CharsetDecoder.java java/nio/charset/spi java/nio/charset/spi/CharsetProvider.java ... java/nio/charset/UnsupportedCharsetException.java java/nio/HeapFloatBufferR.java ...
find
instead of walk
for greater efficiency:
Files.find(path, maxDepth, (path, attr) -> attr.size() > 100000)
Files.list(Paths.get("../..")).forEach(System.out::println) Files.walk(Paths.get("../..")).forEach(System.out::println) Files.find(Paths.get("../.."), Integer.MAX_VALUE, (p, attr) -> attr.size() > 100000).forEach(System.out::println)
Files.walk
to copy a directory tree:
Files.walk(source).forEach(p -> { try { Path q = target.resolve(source.relativize(p)); if (Files.isDirectory(p)) Files.createDirectory(q); else Files.copy(p, q); } catch (IOException ex) { throw new UncheckedIOException(ex); } });
FileVisitor
instead:
Files.walkFileTree(root, new SimpleFileVisitor<Path>() { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } public FileVisitResult postVisitDirectory(Path dir, IOException ex) throws IOException { if (ex != null) throw ex; Files.delete(dir); return FileVisitResult.CONTINUE; } });
Paths
class looks up paths in the default file system.FileSystem zipfs = FileSystems.newFileSystem(Paths.get(zipname), null);
Files.copy(zipfs.getPath(sourceName), targetPath);
Files.walk(zipfs.getPath("/")).forEach(p -> { Process p });
Path zipPath = Paths.get("myfile.zip"); URI uri = new URI("jar", zipPath.toUri().toString(), null); // Constructs the URI jar:file://myfile.zip try (FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.singletonMap("create", "true"))) { // To add files, copy them into the ZIP file system Files.copy(sourcePath, zipfs.getPath("/").resolve(targetPath)); }
Path p = Paths.get("/opt/jdk1.8.0/src.zip") FileSystem zipfs = FileSystems.newFileSystem(p, null) Files.walk(zipfs.getPath("/")).limit(100).forEach(System.out::println) Files.copy(zipfs.getPath("/java/lang/String.java"), Paths.get("/tmp/String.java")); Path zipPath = Paths.get("/tmp/myfile.zip"); URI uri = new URI("jar", zipPath.toUri().toString(), null); FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.singletonMap("create", "true")) InputStream in = new ByteArrayInputStream("Hello".getBytes("UTF-8")); Files.copy(in, zipfs.getPath("/hello.txt")) zipfs.close();
URL url = new URL("http://horstmann.com/index.html"); InputStream in = url.openStream();
GET
request).URLConnection
class for more complex cases:
POST
requestURLConnection
object:
URLConnection connection = url.openConnection();
connection.setRequestProperty("Accept-Charset", "UTF-8, ISO-8859-1");
connection.setDoOutput(true); try (OutputStream out = connection.getOutputStream()) { Write to out }
connection.connect(); // If you skipped step 3 Map<String, List<String>> headers = connection.getHeaderFields();
try (InputStream in = connection.getInputStream()) { Read from in }
HttpURLConnection
, the default encoding is application/x-www-form-urlencoded
.URLConnection connection = url.openConnection(); connection.setDoOutput(true); try (Writer out = new OutputStreamWriter( connection.getOutputStream(), StandardCharsets.UTF_8)) { boolean first = true; for (Map.Entry<String, String> entry : postData.entrySet()) { if (first) first = false; else out.write("&"); out.write(URLEncoder.encode(entry.getKey(), "UTF-8")); out.write("="); out.write(URLEncoder.encode(entry.getValue(), "UTF-8")); } }
firefox https://www.usps.com/zip4/ java post.PostTest > /tmp/out.html firefox /tmp/out.html
java
.HTTPie
.URLConnection
/HttpURLConnection
jdk.incubator
package.
--add-modules jdk.incubator.httpclient
HttpClient client = HttpClient.newBuilder() .followRedirects(HttpClient.Redirect.ALWAYS) .build();
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://horstmann.com")) .GET() .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandler.asString());
client.sendAsync(request, HttpResponse.BodyHandler.asString()) .completeOnTimeout(errorResponse, 10, TimeUnit.SECONDS) .thenAccept(response -> Process response.body());
jshell --add-modules jdk.incubator.httpclient
import jdk.incubator.http.*; import java.net.*; HttpClient client = HttpClient.newBuilder().build(); HttpRequest request = HttpRequest.newBuilder(). uri(URI.create("http://www.gutenberg.org/files/11/11-0.txt")). GET(). build(); client.sendAsync(request, HttpResponse.BodyHandler.asString()). thenAccept(response -> System.out.println(response.body()));
[Jj]e?a.+
matches Java
and jealous
but not Jim
or ja
.. * + ? { | ( ) [ \ ^ $
.
matches any character.*
is 0 or more, +
1 or more, ?
0 or 1 repetition.{2,4}
|
denotes alternatives: (Java|Scala)
()
are used for grouping.[...]
delimit character classes, such as [A-Za-z]
\s
(space), \pL
(Unicode letters), complements \S
, \PL
^
and $
match the beginning and end of input.\
to match them literally.\
in Java strings.Pattern pattern = Pattern.compile(regexString); Matcher matcher = pattern.matcher(input); while (matcher.find()) { String match = matcher.group(); ... }
matcher.start()
, matcher.end()
to get the position of the current match in the string.import java.util.regex.* Matcher matcher = Pattern.compile("[0-9]+").matcher(input) String input = "9:45am"; while (matcher.find()) System.out.println(matcher.group());
matches
method to check whether a string matches a regex:
String regex = "[12]?[0-9]:[0-5][0-9][ap]m"; if (Pattern.matches(regex, input)) { ... }
Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(input); if (matcher.matches()) ...
Stream<String> result = streamOfStrings.filter(pattern.asPredicate());
String regex = "[12]?[0-9]:[0-5][0-9][ap]m"; Pattern.matches(regex, "9:45am") Pattern.matches(regex, "9:65") import java.util.stream.* import java.util.regex.* import java.nio.file.* Files.lines(Paths.get("/usr/share/dict/words")). filter(Pattern.compile(".+q.+q.+").asPredicate()). forEach(System.out::println)
Blackwell Toaster USD29.95
(\p{Alnum}+(\s+\p{Alnum}+)*)\s+([A-Z]{3})([0-9.]*)
group
method to get at each group:
Matcher matcher = pattern.matcher(input); if (matcher.matches()) { item = matcher.group(1); currency = matcher.group(3); price = matcher.group(4); }
(?<item>\p{Alnum}+(\s+\p{Alnum}+)*)\s+(?<currency>[A-Z]{3})(?<price>[0-9.]*)
item = matcher.group("item");
Pattern commas = Pattern.compile("\\s*,\\s*"); String[] tokens = commas.split(input); // String"1, 2, 3"
turns into array["1", "2", "3"]
Stream<String> tokens = commas.splitAsStream(input);
String.split
method:
String[] tokens = input.split("\\s*,\\s*");
replaceAll
on the matcher:
Matcher matcher = commas.matcher(input); String result = matcher.replaceAll(", ");
String.replaceAll
method:
String result = input.replaceAll("\s*,\s*", ", ");
$
n or names $
name are replaced with the captured group:
String result = "3:45".replaceAll( "(\\d{1,2}):(?<minutes>\\d{2})", "$1 hours and ${minutes} minutes");
Matcher.stream
and Scanner.findAll
gets a stream of match results:
Pattern pattern = Pattern.compile("[^,]"); Stream<String> matches = pattern.matcher(str).results().map(MatchResult::group); matches = new Scanner(path).findAll(pattern).map(MatchResult::group);
Matcher.replaceFirst/replaceAll
now have a version with a replacement function: String result = Pattern.compile("\\pL{4,}")
.matcher("Mary had a little lamb")
.replaceAll(m -> m.group().toUpperCase());
// Yields "MARY had a LITTLE LAMB"
Serializable
marker interface:
public class Employee implements Serializable { ... }
ObjectOutputStream
object:
ObjectOutputStream out = new ObjectOutputStream( Files.newOutputStream(path));
writeObject
method:
Employee peter = new Employee("Peter", 90000); Employee paul = new Manager("Paul", 180000); out.writeObject(peter); out.writeObject(paul);
ObjectInputStream
object:
ObjectInputStream in = new ObjectInputStream( Files.newInputStream(path));
Employee e1 = (Employee) in.readObject(); Employee e2 = (Employee) in.readObject();
Employee peter = new Employee("Peter", 40000); Manager paul = new Manager("Paul", 105000); Manager mary = new Manager("Mary", 180000); paul.setAdmin(peter); mary.setAdmin(peter); ObjectOutputStream out = new ObjectOutputStream( Files.newOutputStream(path)); out.writeObject(peter); out.writeObject(paul); out.writeObject(mary);
transient
modifer.readObject
/writeObject
methods.
readResolve
/writeReplace
methods.
serialVersionUID
is obtained by hashing field names and types.serialVersionUID
changes, readObject
throws an exception.private static final long serialVersionUID = 2L; // Version 2