# HG changeset patch # User alanb # Date 1381520835 -3600 # Node ID 483371f41926b9a67a52a9134fc8a228faaf007a # Parent 26af21e74a8db09a6c67ba49f372aa682367ce08 8019526: (fs) Files.lines, etc without Charset parameter Reviewed-by: psandoz, henryjen diff -r 26af21e74a8d -r 483371f41926 jdk/src/share/classes/java/nio/file/Files.java --- a/jdk/src/share/classes/java/nio/file/Files.java Fri Oct 11 20:47:16 2013 +0100 +++ b/jdk/src/share/classes/java/nio/file/Files.java Fri Oct 11 20:47:15 2013 +0100 @@ -43,9 +43,10 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.DosFileAttributes; +import java.nio.file.attribute.DosFileAttributes; // javadoc import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileAttributeView; import java.nio.file.attribute.FileOwnerAttributeView; @@ -104,8 +105,7 @@ return () -> { try { c.close(); - } - catch (IOException e) { + } catch (IOException e) { throw new UncheckedIOException(e); } }; @@ -2550,7 +2550,7 @@ * checkExec} is invoked to check execute access to the file. */ public static boolean isExecutable(Path path) { - return isAccessible(path, AccessMode.EXECUTE); + return isAccessible(path, AccessMode.EXECUTE); } // -- Recursive operations -- @@ -2783,6 +2783,37 @@ } /** + * Opens a file for reading, returning a {@code BufferedReader} to read text + * from the file in an efficient manner. Bytes from the file are decoded into + * characters using the {@link StandardCharsets#UTF_8 UTF-8} {@link Charset + * charset}. + * + *

This method works as if invoking it were equivalent to evaluating the + * expression: + *

{@code
+     * Files.newBufferedReader(path, StandardCharsets.UTF_8)
+     * }
+ * + * @param path + * the path to the file + * + * @return a new buffered reader, with default buffer size, to read text + * from the file + * + * @throws IOException + * if an I/O error occurs opening the file + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + * + * @since 1.8 + */ + public static BufferedReader newBufferedReader(Path path) throws IOException { + return newBufferedReader(path, StandardCharsets.UTF_8); + } + + /** * Opens or creates a file for writing, returning a {@code BufferedWriter} * that may be used to write text to the file in an efficient manner. * The {@code options} parameter specifies how the the file is created or @@ -2828,6 +2859,41 @@ } /** + * Opens or creates a file for writing, returning a {@code BufferedWriter} + * to write text to the file in an efficient manner. The text is encoded + * into bytes for writing using the {@link StandardCharsets#UTF_8 UTF-8} + * {@link Charset charset}. + * + *

This method works as if invoking it were equivalent to evaluating the + * expression: + *

{@code
+     * Files.newBufferedWriter(path, StandardCharsets.UTF_8, options)
+     * }
+ * + * @param path + * the path to the file + * @param options + * options specifying how the file is opened + * + * @return a new buffered writer, with default buffer size, to write text + * to the file + * + * @throws IOException + * if an I/O error occurs opening or creating the file + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + * + * @since 1.8 + */ + public static BufferedWriter newBufferedWriter(Path path, OpenOption... options) throws IOException { + return newBufferedWriter(path, StandardCharsets.UTF_8, options); + } + + /** * Reads all bytes from an input stream and writes them to an output stream. */ private static long copy(InputStream source, OutputStream sink) @@ -3025,9 +3091,7 @@ * @throws OutOfMemoryError * if an array of the required size cannot be allocated */ - private static byte[] read(InputStream source, int initialSize) - throws IOException - { + private static byte[] read(InputStream source, int initialSize) throws IOException { int capacity = initialSize; byte[] buf = new byte[capacity]; int nread = 0; @@ -3131,9 +3195,7 @@ * * @see #newBufferedReader */ - public static List readAllLines(Path path, Charset cs) - throws IOException - { + public static List readAllLines(Path path, Charset cs) throws IOException { try (BufferedReader reader = newBufferedReader(path, cs)) { List result = new ArrayList<>(); for (;;) { @@ -3147,6 +3209,37 @@ } /** + * Read all lines from a file. Bytes from the file are decoded into characters + * using the {@link StandardCharsets#UTF_8 UTF-8} {@link Charset charset}. + * + *

This method works as if invoking it were equivalent to evaluating the + * expression: + *

{@code
+     * Files.readAllLines(path, StandardCharsets.UTF_8)
+     * }
+ * + * @param path + * the path to the file + * + * @return the lines from the file as a {@code List}; whether the {@code + * List} is modifiable or not is implementation dependent and + * therefore not specified + * + * @throws IOException + * if an I/O error occurs reading from the file or a malformed or + * unmappable byte sequence is read + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + * + * @since 1.8 + */ + public static List readAllLines(Path path) throws IOException { + return readAllLines(path, StandardCharsets.UTF_8); + } + + /** * Writes bytes to a file. The {@code options} parameter specifies how the * the file is created or opened. If no options are present then this method * works as if the {@link StandardOpenOption#CREATE CREATE}, {@link @@ -3262,6 +3355,45 @@ return path; } + /** + * Write lines of text to a file. Characters are encoded into bytes using + * the {@link StandardCharsets#UTF_8 UTF-8} {@link Charset charset}. + * + *

This method works as if invoking it were equivalent to evaluating the + * expression: + *

{@code
+     * Files.write(path, lines, StandardCharsets.UTF_8, options);
+     * }
+ * + * @param path + * the path to the file + * @param lines + * an object to iterate over the char sequences + * @param options + * options specifying how the file is opened + * + * @return the path + * + * @throws IOException + * if an I/O error occurs writing to or creating the file, or the + * text cannot be encoded as {@code UTF-8} + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + * + * @since 1.8 + */ + public static Path write(Path path, + Iterable lines, + OpenOption... options) + throws IOException + { + return write(path, lines, StandardCharsets.UTF_8, options); + } + // -- Stream APIs -- /** @@ -3431,9 +3563,11 @@ * if an I/O error is thrown when accessing the starting file. * @since 1.8 */ - public static Stream walk(Path start, int maxDepth, + public static Stream walk(Path start, + int maxDepth, FileVisitOption... options) - throws IOException { + throws IOException + { FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); try { return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false) @@ -3484,9 +3618,7 @@ * @see #walk(Path, int, FileVisitOption...) * @since 1.8 */ - public static Stream walk(Path start, - FileVisitOption... options) - throws IOException { + public static Stream walk(Path start, FileVisitOption... options) throws IOException { return walk(start, Integer.MAX_VALUE, options); } @@ -3547,7 +3679,8 @@ int maxDepth, BiPredicate matcher, FileVisitOption... options) - throws IOException { + throws IOException + { FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); try { return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false) @@ -3561,7 +3694,7 @@ } /** - * Read all lines from a file as a {@code Stream}. Unlike {@link + * Read all lines from a file as a {@code Stream}. Unlike {@link * #readAllLines(Path, Charset) readAllLines}, this method does not read * all lines into a {@code List}, but instead populates lazily as the stream * is consumed. @@ -3619,4 +3752,33 @@ throw e; } } + + /** + * Read all lines from a file as a {@code Stream}. Bytes from the file are + * decoded into characters using the {@link StandardCharsets#UTF_8 UTF-8} + * {@link Charset charset}. + * + *

This method works as if invoking it were equivalent to evaluating the + * expression: + *

{@code
+     * Files.lines(path, StandardCharsets.UTF_8)
+     * }
+ * + * @param path + * the path to the file + * + * @return the lines from the file as a {@code Stream} + * + * @throws IOException + * if an I/O error occurs opening the file + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + * + * @since 1.8 + */ + public static Stream lines(Path path) throws IOException { + return lines(path, StandardCharsets.UTF_8); + } } diff -r 26af21e74a8d -r 483371f41926 jdk/test/java/nio/file/Files/BytesAndLines.java --- a/jdk/test/java/nio/file/Files/BytesAndLines.java Fri Oct 11 20:47:16 2013 +0100 +++ b/jdk/test/java/nio/file/Files/BytesAndLines.java Fri Oct 11 20:47:15 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,262 +22,318 @@ */ /* @test - * @bug 7006126 8020669 8024788 + * @bug 7006126 8020669 8024788 8019526 * @build BytesAndLines PassThroughFileSystem - * @run main BytesAndLines + * @run testng BytesAndLines * @summary Unit test for methods for Files readAllBytes, readAllLines and * and write methods. */ -import java.nio.file.*; -import static java.nio.file.Files.*; -import java.io.*; -import java.util.*; -import java.nio.charset.*; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.OpenOption; +import static java.nio.file.StandardOpenOption.*; +import java.nio.charset.Charset; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.MalformedInputException; +import java.nio.charset.UnmappableCharacterException; +import static java.nio.charset.StandardCharsets.*; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.Callable; +import java.io.IOException; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test(groups = "unit") public class BytesAndLines { - static final Random rand = new Random(); + + // data for text files + private static final String EN_STRING = "The quick brown fox jumps over the lazy dog"; + private static final String JA_STRING = "\u65e5\u672c\u8a9e\u6587\u5b57\u5217"; - static final Charset US_ASCII = Charset.forName("US-ASCII"); + // used for random byte content + private static Random RAND = new Random(); + + // file used by most tests + private Path tmpfile; - public static void main(String[] args) throws IOException { - testReadAndWriteBytes(); - testReadLines(); - testWriteLines(); + @BeforeClass + void setup() throws IOException { + tmpfile = Files.createTempFile("blah", null); + } + + @AfterClass + void cleanup() throws IOException { + Files.deleteIfExists(tmpfile); + } + + /** + * Returns a byte[] of the given size with random content + */ + private byte[] genBytes(int size) { + byte[] arr = new byte[size]; + RAND.nextBytes(arr); + return arr; } /** - * Test readAllBytes(Path) and write(Path, byte[], OpenOption...) + * Exercise NullPointerException */ - static void testReadAndWriteBytes() throws IOException { - // exercise methods with various sizes - testReadAndWriteBytes(0); - for (int i=0; i<100; i++) { - testReadAndWriteBytes(rand.nextInt(32000)); - } - - // NullPointerException + public void testNulls() { Path file = Paths.get("foo"); + byte[] bytes = new byte[100]; List lines = Collections.emptyList(); - try { - readAllBytes(null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - write(null, lines, Charset.defaultCharset()); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - write(file, null, Charset.defaultCharset()); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } + + checkNullPointerException(() -> Files.readAllBytes(null)); + + checkNullPointerException(() -> Files.write(null, bytes)); + checkNullPointerException(() -> Files.write(file, (byte[])null)); + checkNullPointerException(() -> Files.write(file, bytes, (OpenOption[])null)); + checkNullPointerException(() -> Files.write(file, bytes, new OpenOption[] { null } )); + + checkNullPointerException(() -> Files.readAllLines(null)); + checkNullPointerException(() -> Files.readAllLines(file, (Charset)null)); + checkNullPointerException(() -> Files.readAllLines(null, Charset.defaultCharset())); + + checkNullPointerException(() -> Files.write(null, lines)); + checkNullPointerException(() -> Files.write(file, (List)null)); + checkNullPointerException(() -> Files.write(file, lines, (OpenOption[])null)); + checkNullPointerException(() -> Files.write(file, lines, new OpenOption[] { null } )); + checkNullPointerException(() -> Files.write(null, lines, Charset.defaultCharset())); + checkNullPointerException(() -> Files.write(file, null, Charset.defaultCharset())); + checkNullPointerException(() -> Files.write(file, lines, (Charset)null)); + checkNullPointerException(() -> Files.write(file, lines, Charset.defaultCharset(), (OpenOption[])null)); + checkNullPointerException(() -> Files.write(file, lines, Charset.defaultCharset(), new OpenOption[] { null } )); + } + + private void checkNullPointerException(Callable c) { try { - write(file, lines, null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - write(file, lines, Charset.defaultCharset(), (OpenOption[])null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - OpenOption[] opts = { null }; - write(file, lines, Charset.defaultCharset(), opts); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - - // read from procfs - if (System.getProperty("os.name").equals("Linux")) { - // Refer to the Linux proc(5) man page for details about /proc/self/stat file - // procfs reports it to be zero sized, even though data can be read from it - String statFile = "/proc/self/stat"; - Path pathStat = Paths.get(statFile); - byte[] data = Files.readAllBytes(pathStat); - assertTrue(data.length > 0, "Files.readAllBytes('" + statFile + "') failed to read"); - } - - // test readAllBytes on custom file system - Path myfile = PassThroughFileSystem.create().getPath(file.toString()); - for (int size=0; size<=1024; size+=512) { - byte[] b1 = new byte[size]; - rand.nextBytes(b1); - Files.write(myfile, b1); - byte[] b2 = Files.readAllBytes(myfile); - assertTrue(Arrays.equals(b1, b2), "bytes not equal"); + c.call(); + fail("NullPointerException expected"); + } catch (NullPointerException ignore) { + } catch (Exception e) { + fail(e + " not expected"); } } - - static void testReadAndWriteBytes(int size) throws IOException { - Path path = createTempFile("blah", null); - try { - boolean append = rand.nextBoolean(); - - byte[] b1 = new byte[size]; - rand.nextBytes(b1); + /** + * Exercise Files.readAllBytes(Path) on varied file sizes + */ + public void testReadAllBytes() throws IOException { + int size = 0; + while (size <= 16*1024) { + testReadAllBytes(size); + size += 512; + } + } - byte[] b2 = (append) ? new byte[size] : new byte[0]; - rand.nextBytes(b2); - - // write method should create file if it doesn't exist - if (rand.nextBoolean()) - delete(path); - - // write bytes to file - Path target = write(path, b1); - assertTrue(target==path, "Unexpected path"); - assertTrue(size(path) == b1.length, "Unexpected file size"); + private void testReadAllBytes(int size) throws IOException { + // write bytes to file (random content) + byte[] expected = genBytes(size); + Files.write(tmpfile, expected); - // append bytes to file (might be 0 bytes) - write(path, b2, StandardOpenOption.APPEND); - assertTrue(size(path) == b1.length + b2.length, "Unexpected file size"); - - // read entire file - byte[] read = readAllBytes(path); + // check expected bytes are read + byte[] read = Files.readAllBytes(tmpfile); + assertTrue(Arrays.equals(read, expected), "Bytes read not the same as written"); + } - // check bytes are correct - byte[] expected; - if (append) { - expected = new byte[b1.length + b2.length]; - System.arraycopy(b1, 0, expected, 0, b1.length); - System.arraycopy(b2, 0, expected, b1.length, b2.length); - } else { - expected = b1; - } - assertTrue(Arrays.equals(read, expected), - "Bytes read not the same as bytes written"); - } finally { - deleteIfExists(path); + /** + * Linux specific test to exercise Files.readAllBytes on /proc. This is + * special because file sizes are reported as 0 even though the file + * has content. + */ + public void testReadAllBytesOnProcFS() throws IOException { + // read from procfs + if (System.getProperty("os.name").equals("Linux")) { + Path statFile = Paths.get("/proc/self/stat"); + byte[] data = Files.readAllBytes(statFile); + assertTrue(data.length > 0, "Files.readAllBytes('" + statFile + "') failed to read"); } } /** - * Test readAllLines(Path,Charset) + * Exercise Files.readAllBytes(Path) on custom file system. This is special + * because readAllBytes was originally implemented to use FileChannel + * and so may not be supported by custom file system providers. */ - static void testReadLines() throws IOException { - Path tmpfile = createTempFile("blah", "txt"); + public void testReadAllBytesOnCustomFS() throws IOException { + Path myfile = PassThroughFileSystem.create().getPath("myfile"); try { - List lines; - - // zero lines - assertTrue(size(tmpfile) == 0, "File should be empty"); - lines = readAllLines(tmpfile, US_ASCII); - assertTrue(lines.isEmpty(), "No line expected"); - - // one line - byte[] hi = { (byte)'h', (byte)'i' }; - write(tmpfile, hi); - lines = readAllLines(tmpfile, US_ASCII); - assertTrue(lines.size() == 1, "One line expected"); - assertTrue(lines.get(0).equals("hi"), "'Hi' expected"); - - // two lines using platform's line separator - List expected = Arrays.asList("hi", "there"); - write(tmpfile, expected, US_ASCII); - assertTrue(size(tmpfile) > 0, "File is empty"); - lines = readAllLines(tmpfile, US_ASCII); - assertTrue(lines.equals(expected), "Unexpected lines"); - - // MalformedInputException - byte[] bad = { (byte)0xff, (byte)0xff }; - write(tmpfile, bad); - try { - readAllLines(tmpfile, US_ASCII); - throw new RuntimeException("MalformedInputException expected"); - } catch (MalformedInputException ignore) { } - - - // NullPointerException - try { - readAllLines(null, US_ASCII); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - readAllLines(tmpfile, null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - - // read from procfs - if (System.getProperty("os.name").equals("Linux")) { - // Refer to the Linux proc(5) man page for details about /proc/self/status file - // procfs reports this file to be zero sized, even though data can be read from it - String statusFile = "/proc/self/status"; - Path pathStatus = Paths.get(statusFile); - lines = Files.readAllLines(pathStatus, US_ASCII); - assertTrue(lines.size() > 0, "Files.readAllLines('" + pathStatus + "') failed to read"); + int size = 0; + while (size <= 1024) { + byte[] b1 = genBytes(size); + Files.write(myfile, b1); + byte[] b2 = Files.readAllBytes(myfile); + assertTrue(Arrays.equals(b1, b2), "bytes not equal"); + size += 512; } - } finally { - delete(tmpfile); + Files.deleteIfExists(myfile); } } /** - * Test write(Path,Iterable,Charset,OpenOption...) + * Exercise Files.write(Path, byte[], OpenOption...) on various sizes */ - static void testWriteLines() throws IOException { - Path tmpfile = createTempFile("blah", "txt"); - try { - // write method should create file if it doesn't exist - if (rand.nextBoolean()) - delete(tmpfile); - - // zero lines - Path result = write(tmpfile, Collections.emptyList(), US_ASCII); - assert(size(tmpfile) == 0); - assert(result == tmpfile); - - // two lines - List lines = Arrays.asList("hi", "there"); - write(tmpfile, lines, US_ASCII); - List actual = readAllLines(tmpfile, US_ASCII); - assertTrue(actual.equals(lines), "Unexpected lines"); - - // append two lines - write(tmpfile, lines, US_ASCII, StandardOpenOption.APPEND); - List expected = new ArrayList(); - expected.addAll(lines); - expected.addAll(lines); - assertTrue(expected.size() == 4, "List should have 4 elements"); - actual = readAllLines(tmpfile, US_ASCII); - assertTrue(actual.equals(expected), "Unexpected lines"); - - // UnmappableCharacterException - try { - String s = "\u00A0\u00A1"; - write(tmpfile, Arrays.asList(s), US_ASCII); - throw new RuntimeException("UnmappableCharacterException expected"); - } catch (UnmappableCharacterException ignore) { } - - // NullPointerException - try { - write(null, lines, US_ASCII); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - write(tmpfile, null, US_ASCII); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - write(tmpfile, lines, null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - write(tmpfile, lines, US_ASCII, (OpenOption[])null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - OpenOption[] opts = { (OpenOption)null }; - write(tmpfile, lines, US_ASCII, opts); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - - } finally { - delete(tmpfile); + public void testWriteBytes() throws IOException { + int size = 0; + while (size < 16*1024) { + testWriteBytes(size, false); + testWriteBytes(size, true); + size += 512; } } - static void assertTrue(boolean expr, String errmsg) { - if (!expr) - throw new RuntimeException(errmsg); + private void testWriteBytes(int size, boolean append) throws IOException { + byte[] bytes = genBytes(size); + Path result = Files.write(tmpfile, bytes); + assertTrue(result == tmpfile); + if (append) { + Files.write(tmpfile, bytes, APPEND); + assertTrue(Files.size(tmpfile) == size*2); + } + + byte[] expected; + if (append) { + expected = new byte[size << 1]; + System.arraycopy(bytes, 0, expected, 0, bytes.length); + System.arraycopy(bytes, 0, expected, bytes.length, bytes.length); + } else { + expected = bytes; + } + + byte[] read = Files.readAllBytes(tmpfile); + assertTrue(Arrays.equals(read, expected), "Bytes read not the same as written"); + } + + /** + * Exercise Files.readAllLines(Path, Charset) + */ + public void testReadAllLines() throws IOException { + // zero lines + Files.write(tmpfile, new byte[0]); + List lines = Files.readAllLines(tmpfile, US_ASCII); + assertTrue(lines.isEmpty(), "No line expected"); + + // one line + byte[] hi = { (byte)'h', (byte)'i' }; + Files.write(tmpfile, hi); + lines = Files.readAllLines(tmpfile, US_ASCII); + assertTrue(lines.size() == 1, "One line expected"); + assertTrue(lines.get(0).equals("hi"), "'Hi' expected"); + + // two lines using platform's line separator + List expected = Arrays.asList("hi", "there"); + Files.write(tmpfile, expected, US_ASCII); + assertTrue(Files.size(tmpfile) > 0, "File is empty"); + lines = Files.readAllLines(tmpfile, US_ASCII); + assertTrue(lines.equals(expected), "Unexpected lines"); + + // MalformedInputException + byte[] bad = { (byte)0xff, (byte)0xff }; + Files.write(tmpfile, bad); + try { + Files.readAllLines(tmpfile, US_ASCII); + fail("MalformedInputException expected"); + } catch (MalformedInputException ignore) { } + } + + /** + * Linux specific test to exercise Files.readAllLines(Path) on /proc. This + * is special because file sizes are reported as 0 even though the file + * has content. + */ + public void testReadAllLinesOnProcFS() throws IOException { + if (System.getProperty("os.name").equals("Linux")) { + Path statFile = Paths.get("/proc/self/stat"); + List lines = Files.readAllLines(statFile); + assertTrue(lines.size() > 0, "Files.readAllLines('" + statFile + "') failed to read"); + } + } + + /** + * Exercise Files.readAllLines(Path) + */ + public void testReadAllLinesUTF8() throws IOException { + Files.write(tmpfile, encodeAsUTF8(EN_STRING + "\n" + JA_STRING)); + + List lines = Files.readAllLines(tmpfile); + assertTrue(lines.size() == 2, "Read " + lines.size() + " lines instead of 2"); + assertTrue(lines.get(0).equals(EN_STRING)); + assertTrue(lines.get(1).equals(JA_STRING)); + + // a sample of malformed sequences + testReadAllLinesMalformedUTF8((byte)0xFF); // one-byte sequence + testReadAllLinesMalformedUTF8((byte)0xC0, (byte)0x80); // invalid first byte + testReadAllLinesMalformedUTF8((byte)0xC2, (byte)0x00); // invalid second byte + } + + private byte[] encodeAsUTF8(String s) throws CharacterCodingException { + // not using s.getBytes here so as to catch unmappable characters + ByteBuffer bb = UTF_8.newEncoder().encode(CharBuffer.wrap(s)); + byte[] result = new byte[bb.limit()]; + bb.get(result); + assertTrue(bb.remaining() == 0); + return result; + } + + private void testReadAllLinesMalformedUTF8(byte... bytes) throws IOException { + Files.write(tmpfile, bytes); + try { + Files.readAllLines(tmpfile); + fail("MalformedInputException expected"); + } catch (MalformedInputException ignore) { } + } + + /** + * Exercise Files.write(Path, Iterable, Charset, OpenOption...) + */ + public void testWriteLines() throws IOException { + // zero lines + Path result = Files.write(tmpfile, Collections.emptyList(), US_ASCII); + assert(Files.size(tmpfile) == 0); + assert(result == tmpfile); + + // two lines + List lines = Arrays.asList("hi", "there"); + Files.write(tmpfile, lines, US_ASCII); + List actual = Files.readAllLines(tmpfile, US_ASCII); + assertTrue(actual.equals(lines), "Unexpected lines"); + + // append two lines + Files.write(tmpfile, lines, US_ASCII, APPEND); + List expected = new ArrayList<>(); + expected.addAll(lines); + expected.addAll(lines); + assertTrue(expected.size() == 4, "List should have 4 elements"); + actual = Files.readAllLines(tmpfile, US_ASCII); + assertTrue(actual.equals(expected), "Unexpected lines"); + + // UnmappableCharacterException + try { + String s = "\u00A0\u00A1"; + Files.write(tmpfile, Arrays.asList(s), US_ASCII); + fail("UnmappableCharacterException expected"); + } catch (UnmappableCharacterException ignore) { } + } + + /** + * Exercise Files.write(Path, Iterable, OpenOption...) + */ + public void testWriteLinesUTF8() throws IOException { + List lines = Arrays.asList(EN_STRING, JA_STRING); + Files.write(tmpfile, lines); + List actual = Files.readAllLines(tmpfile, UTF_8); + assertTrue(actual.equals(lines), "Unexpected lines"); } } diff -r 26af21e74a8d -r 483371f41926 jdk/test/java/nio/file/Files/StreamTest.java --- a/jdk/test/java/nio/file/Files/StreamTest.java Fri Oct 11 20:47:16 2013 +0100 +++ b/jdk/test/java/nio/file/Files/StreamTest.java Fri Oct 11 20:47:15 2013 +0100 @@ -22,11 +22,10 @@ */ /* @test - * @bug 8006884 - * @summary Unit test for java.nio.file.Files - * @library .. + * @bug 8006884 8019526 * @build PassThroughFileSystem FaultyFileSystem * @run testng StreamTest + * @summary Unit test for java.nio.file.Files methods that return a Stream */ import java.io.IOException; @@ -43,11 +42,13 @@ import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.Callable; import java.util.function.BiPredicate; import java.util.stream.Stream; import java.util.stream.Collectors; @@ -316,56 +317,80 @@ try { // zero lines assertTrue(Files.size(tmpfile) == 0, "File should be empty"); + try (Stream s = Files.lines(tmpfile)) { + checkLines(s, Collections.emptyList()); + } try (Stream s = Files.lines(tmpfile, US_ASCII)) { - assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected"); + checkLines(s, Collections.emptyList()); } // one line - byte[] hi = { (byte)'h', (byte)'i' }; - Files.write(tmpfile, hi); + List oneLine = Arrays.asList("hi"); + Files.write(tmpfile, oneLine, US_ASCII); + try (Stream s = Files.lines(tmpfile)) { + checkLines(s, oneLine); + } try (Stream s = Files.lines(tmpfile, US_ASCII)) { - List lines = s.collect(Collectors.toList()); - assertTrue(lines.size() == 1, "One line expected"); - assertTrue(lines.get(0).equals("hi"), "'Hi' expected"); + checkLines(s, oneLine); } // two lines using platform's line separator - List expected = Arrays.asList("hi", "there"); - Files.write(tmpfile, expected, US_ASCII); - assertTrue(Files.size(tmpfile) > 0, "File is empty"); + List twoLines = Arrays.asList("hi", "there"); + Files.write(tmpfile, twoLines, US_ASCII); + try (Stream s = Files.lines(tmpfile)) { + checkLines(s, twoLines); + } try (Stream s = Files.lines(tmpfile, US_ASCII)) { - List lines = s.collect(Collectors.toList()); - assertTrue(lines.equals(expected), "Unexpected lines"); + checkLines(s, twoLines); } // MalformedInputException byte[] bad = { (byte)0xff, (byte)0xff }; Files.write(tmpfile, bad); + try (Stream s = Files.lines(tmpfile)) { + checkMalformedInputException(s); + } try (Stream s = Files.lines(tmpfile, US_ASCII)) { - try { - List lines = s.collect(Collectors.toList()); - throw new RuntimeException("UncheckedIOException expected"); - } catch (UncheckedIOException ex) { - assertTrue(ex.getCause() instanceof MalformedInputException, - "MalformedInputException expected"); - } + checkMalformedInputException(s); } // NullPointerException - try { - Files.lines(null, US_ASCII); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - Files.lines(tmpfile, null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } + checkNullPointerException(() -> Files.lines(null)); + checkNullPointerException(() -> Files.lines(null, US_ASCII)); + checkNullPointerException(() -> Files.lines(tmpfile, null)); } finally { Files.delete(tmpfile); } } + private void checkLines(Stream s, List expected) { + List lines = s.collect(Collectors.toList()); + assertTrue(lines.size() == expected.size(), "Unexpected number of lines"); + assertTrue(lines.equals(expected), "Unexpected content"); + } + + private void checkMalformedInputException(Stream s) { + try { + List lines = s.collect(Collectors.toList()); + fail("UncheckedIOException expected"); + } catch (UncheckedIOException ex) { + IOException cause = ex.getCause(); + assertTrue(cause instanceof MalformedInputException, + "MalformedInputException expected"); + } + } + + private void checkNullPointerException(Callable c) { + try { + c.call(); + fail("NullPointerException expected"); + } catch (NullPointerException ignore) { + } catch (Exception e) { + fail(e + " not expected"); + } + } + public void testDirectoryIteratorException() throws IOException { Path dir = testFolder.resolve("dir2"); Path trigger = dir.resolve("DirectoryIteratorException");