3175 writer.newLine(); |
3179 writer.newLine(); |
3176 } |
3180 } |
3177 } |
3181 } |
3178 return path; |
3182 return path; |
3179 } |
3183 } |
|
3184 |
|
3185 // -- Stream APIs -- |
|
3186 |
|
3187 /** |
|
3188 * Implementation of CloseableStream |
|
3189 */ |
|
3190 private static class DelegatingCloseableStream<T> extends DelegatingStream<T> |
|
3191 implements CloseableStream<T> |
|
3192 { |
|
3193 private final Closeable closeable; |
|
3194 |
|
3195 DelegatingCloseableStream(Closeable c, Stream<T> delegate) { |
|
3196 super(delegate); |
|
3197 this.closeable = c; |
|
3198 } |
|
3199 |
|
3200 public void close() { |
|
3201 try { |
|
3202 closeable.close(); |
|
3203 } catch (IOException ex) { |
|
3204 throw new UncheckedIOException(ex); |
|
3205 } |
|
3206 } |
|
3207 } |
|
3208 |
|
3209 /** |
|
3210 * Return a lazily populated {@code CloseableStream}, the elements of |
|
3211 * which are the entries in the directory. The listing is not recursive. |
|
3212 * |
|
3213 * <p> The elements of the stream are {@link Path} objects that are |
|
3214 * obtained as if by {@link Path#resolve(Path) resolving} the name of the |
|
3215 * directory entry against {@code dir}. Some file systems maintain special |
|
3216 * links to the directory itself and the directory's parent directory. |
|
3217 * Entries representing these links are not included. |
|
3218 * |
|
3219 * <p> The stream is <i>weakly consistent</i>. It is thread safe but does |
|
3220 * not freeze the directory while iterating, so it may (or may not) |
|
3221 * reflect updates to the directory that occur after returning from this |
|
3222 * method. |
|
3223 * |
|
3224 * <p> When not using the try-with-resources construct, then the stream's |
|
3225 * {@link CloseableStream#close close} method should be invoked after the |
|
3226 * operation is completed so as to free any resources held for the open |
|
3227 * directory. Operating on a closed stream behaves as if the end of stream |
|
3228 * has been reached. Due to read-ahead, one or more elements may be |
|
3229 * returned after the stream has been closed. |
|
3230 * |
|
3231 * <p> If an {@link IOException} is thrown when accessing the directory |
|
3232 * after this method has returned, it is wrapped in an {@link |
|
3233 * UncheckedIOException} which will be thrown from the method that caused |
|
3234 * the access to take place. |
|
3235 * |
|
3236 * @param dir The path to the directory |
|
3237 * |
|
3238 * @return The {@code CloseableStream} describing the content of the |
|
3239 * directory |
|
3240 * |
|
3241 * @throws NotDirectoryException |
|
3242 * if the file could not otherwise be opened because it is not |
|
3243 * a directory <i>(optional specific exception)</i> |
|
3244 * @throws IOException |
|
3245 * if an I/O error occurs when opening the directory |
|
3246 * @throws SecurityException |
|
3247 * In the case of the default provider, and a security manager is |
|
3248 * installed, the {@link SecurityManager#checkRead(String) checkRead} |
|
3249 * method is invoked to check read access to the directory. |
|
3250 * |
|
3251 * @see #newDirectoryStream(Path) |
|
3252 * @since 1.8 |
|
3253 */ |
|
3254 public static CloseableStream<Path> list(Path dir) throws IOException { |
|
3255 DirectoryStream<Path> ds = Files.newDirectoryStream(dir); |
|
3256 final Iterator<Path> delegate = ds.iterator(); |
|
3257 |
|
3258 // Re-wrap DirectoryIteratorException to UncheckedIOException |
|
3259 Iterator<Path> it = new Iterator<Path>() { |
|
3260 public boolean hasNext() { |
|
3261 try { |
|
3262 return delegate.hasNext(); |
|
3263 } catch (DirectoryIteratorException e) { |
|
3264 throw new UncheckedIOException(e.getCause()); |
|
3265 } |
|
3266 } |
|
3267 public Path next() { |
|
3268 try { |
|
3269 return delegate.next(); |
|
3270 } catch (DirectoryIteratorException e) { |
|
3271 throw new UncheckedIOException(e.getCause()); |
|
3272 } |
|
3273 } |
|
3274 }; |
|
3275 |
|
3276 return new DelegatingCloseableStream<>(ds, |
|
3277 StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, |
|
3278 Spliterator.DISTINCT))); |
|
3279 } |
|
3280 |
|
3281 /** |
|
3282 * Return a {@code CloseableStream} that is lazily populated with {@code |
|
3283 * Path} by walking the file tree rooted at a given starting file. The |
|
3284 * file tree is traversed <em>depth-first</em>, the elements in the stream |
|
3285 * are {@link Path} objects that are obtained as if by {@link |
|
3286 * Path#resolve(Path) resolving} the relative path against {@code start}. |
|
3287 * |
|
3288 * <p> The {@code stream} walks the file tree as elements are consumed. |
|
3289 * The {@code CloseableStream} returned is guaranteed to have at least one |
|
3290 * element, the starting file itself. For each file visited, the stream |
|
3291 * attempts to read its {@link BasicFileAttributes}. If the file is a |
|
3292 * directory and can be opened successfully, entries in the directory, and |
|
3293 * their <em>descendants</em> will follow the directory in the stream as |
|
3294 * they are encountered. When all entries have been visited, then the |
|
3295 * directory is closed. The file tree walk then continues at the next |
|
3296 * <em>sibling</em> of the directory. |
|
3297 * |
|
3298 * <p> The stream is <i>weakly consistent</i>. It does not freeze the |
|
3299 * file tree while iterating, so it may (or may not) reflect updates to |
|
3300 * the file tree that occur after returned from this method. |
|
3301 * |
|
3302 * <p> By default, symbolic links are not automatically followed by this |
|
3303 * method. If the {@code options} parameter contains the {@link |
|
3304 * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are |
|
3305 * followed. When following links, and the attributes of the target cannot |
|
3306 * be read, then this method attempts to get the {@code BasicFileAttributes} |
|
3307 * of the link. |
|
3308 * |
|
3309 * <p> If the {@code options} parameter contains the {@link |
|
3310 * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then the stream keeps |
|
3311 * track of directories visited so that cycles can be detected. A cycle |
|
3312 * arises when there is an entry in a directory that is an ancestor of the |
|
3313 * directory. Cycle detection is done by recording the {@link |
|
3314 * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories, |
|
3315 * or if file keys are not available, by invoking the {@link #isSameFile |
|
3316 * isSameFile} method to test if a directory is the same file as an |
|
3317 * ancestor. When a cycle is detected it is treated as an I/O error with |
|
3318 * an instance of {@link FileSystemLoopException}. |
|
3319 * |
|
3320 * <p> The {@code maxDepth} parameter is the maximum number of levels of |
|
3321 * directories to visit. A value of {@code 0} means that only the starting |
|
3322 * file is visited, unless denied by the security manager. A value of |
|
3323 * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all |
|
3324 * levels should be visited. |
|
3325 * |
|
3326 * <p> When a security manager is installed and it denies access to a file |
|
3327 * (or directory), then it is ignored and not included in the stream. |
|
3328 * |
|
3329 * <p> When not using the try-with-resources construct, then the stream's |
|
3330 * {@link CloseableStream#close close} method should be invoked after the |
|
3331 * operation is completed so as to free any resources held for the open |
|
3332 * directory. Operate the stream after it is closed will throw an |
|
3333 * {@link java.lang.IllegalStateException}. |
|
3334 * |
|
3335 * <p> If an {@link IOException} is thrown when accessing the directory |
|
3336 * after this method has returned, it is wrapped in an {@link |
|
3337 * UncheckedIOException} which will be thrown from the method that caused |
|
3338 * the access to take place. |
|
3339 * |
|
3340 * @param start |
|
3341 * the starting file |
|
3342 * @param maxDepth |
|
3343 * the maximum number of directory levels to visit |
|
3344 * @param options |
|
3345 * options to configure the traversal |
|
3346 * |
|
3347 * @return the {@link CloseableStream} of {@link Path} |
|
3348 * |
|
3349 * @throws IllegalArgumentException |
|
3350 * if the {@code maxDepth} parameter is negative |
|
3351 * @throws SecurityException |
|
3352 * If the security manager denies access to the starting file. |
|
3353 * In the case of the default provider, the {@link |
|
3354 * SecurityManager#checkRead(String) checkRead} method is invoked |
|
3355 * to check read access to the directory. |
|
3356 * @throws IOException |
|
3357 * if an I/O error is thrown when accessing the starting file. |
|
3358 * @since 1.8 |
|
3359 */ |
|
3360 public static CloseableStream<Path> walk(Path start, int maxDepth, |
|
3361 FileVisitOption... options) |
|
3362 throws IOException |
|
3363 { |
|
3364 FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); |
|
3365 return new DelegatingCloseableStream<>(iterator, |
|
3366 StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT)) |
|
3367 .map(entry -> entry.file())); |
|
3368 } |
|
3369 |
|
3370 /** |
|
3371 * Return a {@code CloseableStream} that is lazily populated with {@code |
|
3372 * Path} by walking the file tree rooted at a given starting file. The |
|
3373 * file tree is traversed <em>depth-first</em>, the elements in the stream |
|
3374 * are {@link Path} objects that are obtained as if by {@link |
|
3375 * Path#resolve(Path) resolving} the relative path against {@code start}. |
|
3376 * |
|
3377 * <p> This method works as if invoking it were equivalent to evaluating the |
|
3378 * expression: |
|
3379 * <blockquote><pre> |
|
3380 * walk(start, Integer.MAX_VALUE, options) |
|
3381 * </pre></blockquote> |
|
3382 * In other words, it visits all levels of the file tree. |
|
3383 * |
|
3384 * @param start |
|
3385 * the starting file |
|
3386 * @param options |
|
3387 * options to configure the traversal |
|
3388 * |
|
3389 * @return the {@link CloseableStream} of {@link Path} |
|
3390 * |
|
3391 * @throws SecurityException |
|
3392 * If the security manager denies access to the starting file. |
|
3393 * In the case of the default provider, the {@link |
|
3394 * SecurityManager#checkRead(String) checkRead} method is invoked |
|
3395 * to check read access to the directory. |
|
3396 * @throws IOException |
|
3397 * if an I/O error is thrown when accessing the starting file. |
|
3398 * |
|
3399 * @see #walk(Path, int, FileVisitOption...) |
|
3400 * @since 1.8 |
|
3401 */ |
|
3402 public static CloseableStream<Path> walk(Path start, |
|
3403 FileVisitOption... options) |
|
3404 throws IOException |
|
3405 { |
|
3406 return walk(start, Integer.MAX_VALUE, options); |
|
3407 } |
|
3408 |
|
3409 /** |
|
3410 * Return a {@code CloseableStream} that is lazily populated with {@code |
|
3411 * Path} by searching for files in a file tree rooted at a given starting |
|
3412 * file. |
|
3413 * |
|
3414 * <p> This method walks the file tree in exactly the manner specified by |
|
3415 * the {@link #walk walk} method. For each file encountered, the given |
|
3416 * {@link BiPredicate} is invoked with its {@link Path} and {@link |
|
3417 * BasicFileAttributes}. The {@code Path} object is obtained as if by |
|
3418 * {@link Path#resolve(Path) resolving} the relative path against {@code |
|
3419 * start} and is only included in the returned {@link CloseableStream} if |
|
3420 * the {@code BiPredicate} returns true. Compare to calling {@link |
|
3421 * java.util.stream.Stream#filter filter} on the {@code Stream} |
|
3422 * returned by {@code walk} method, this method may be more efficient by |
|
3423 * avoiding redundant retrieval of the {@code BasicFileAttributes}. |
|
3424 * |
|
3425 * <p> If an {@link IOException} is thrown when accessing the directory |
|
3426 * after returned from this method, it is wrapped in an {@link |
|
3427 * UncheckedIOException} which will be thrown from the method that caused |
|
3428 * the access to take place. |
|
3429 * |
|
3430 * @param start |
|
3431 * the starting file |
|
3432 * @param maxDepth |
|
3433 * the maximum number of directory levels to search |
|
3434 * @param matcher |
|
3435 * the function used to decide whether a file should be included |
|
3436 * in the returned stream |
|
3437 * @param options |
|
3438 * options to configure the traversal |
|
3439 * |
|
3440 * @return the {@link CloseableStream} of {@link Path} |
|
3441 * |
|
3442 * @throws IllegalArgumentException |
|
3443 * if the {@code maxDepth} parameter is negative |
|
3444 * @throws SecurityException |
|
3445 * If the security manager denies access to the starting file. |
|
3446 * In the case of the default provider, the {@link |
|
3447 * SecurityManager#checkRead(String) checkRead} method is invoked |
|
3448 * to check read access to the directory. |
|
3449 * @throws IOException |
|
3450 * if an I/O error is thrown when accessing the starting file. |
|
3451 * |
|
3452 * @see #walk(Path, int, FileVisitOption...) |
|
3453 * @since 1.8 |
|
3454 */ |
|
3455 public static CloseableStream<Path> find(Path start, |
|
3456 int maxDepth, |
|
3457 BiPredicate<Path, BasicFileAttributes> matcher, |
|
3458 FileVisitOption... options) |
|
3459 throws IOException |
|
3460 { |
|
3461 FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); |
|
3462 return new DelegatingCloseableStream<>(iterator, |
|
3463 StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT)) |
|
3464 .filter(entry -> matcher.test(entry.file(), entry.attributes())) |
|
3465 .map(entry -> entry.file())); |
|
3466 } |
|
3467 |
|
3468 /** |
|
3469 * Read all lines from a file as a {@code CloseableStream}. Unlike {@link |
|
3470 * #readAllLines(Path, Charset) readAllLines}, this method does not read |
|
3471 * all lines into a {@code List}, but instead populates lazily as the stream |
|
3472 * is consumed. |
|
3473 * |
|
3474 * <p> Bytes from the file are decoded into characters using the specified |
|
3475 * charset and the same line terminators as specified by {@code |
|
3476 * readAllLines} are supported. |
|
3477 * |
|
3478 * <p> After this method returns, then any subsequent I/O exception that |
|
3479 * occurs while reading from the file or when a malformed or unmappable byte |
|
3480 * sequence is read, is wrapped in an {@link UncheckedIOException} that will |
|
3481 * be thrown form the |
|
3482 * {@link java.util.stream.Stream} method that caused the read to take |
|
3483 * place. In case an {@code IOException} is thrown when closing the file, |
|
3484 * it is also wrapped as an {@code UncheckedIOException}. |
|
3485 * |
|
3486 * <p> When not using the try-with-resources construct, then stream's |
|
3487 * {@link CloseableStream#close close} method should be invoked after |
|
3488 * operation is completed so as to free any resources held for the open |
|
3489 * file. |
|
3490 * |
|
3491 * @param path |
|
3492 * the path to the file |
|
3493 * @param cs |
|
3494 * the charset to use for decoding |
|
3495 * |
|
3496 * @return the lines from the file as a {@code CloseableStream} |
|
3497 * |
|
3498 * @throws IOException |
|
3499 * if an I/O error occurs opening the file |
|
3500 * @throws SecurityException |
|
3501 * In the case of the default provider, and a security manager is |
|
3502 * installed, the {@link SecurityManager#checkRead(String) checkRead} |
|
3503 * method is invoked to check read access to the file. |
|
3504 * |
|
3505 * @see #readAllLines(Path, Charset) |
|
3506 * @see #newBufferedReader(Path, Charset) |
|
3507 * @see java.io.BufferedReader#lines() |
|
3508 * @since 1.8 |
|
3509 */ |
|
3510 public static CloseableStream<String> lines(Path path, Charset cs) |
|
3511 throws IOException |
|
3512 { |
|
3513 BufferedReader br = Files.newBufferedReader(path, cs); |
|
3514 return new DelegatingCloseableStream<>(br, br.lines()); |
|
3515 } |
3180 } |
3516 } |