From 12edf83082d30df9b25d88eb256ad4725b39ceaa Mon Sep 17 00:00:00 2001 From: Shivam Malhotra Date: Wed, 13 Mar 2024 14:33:11 -0500 Subject: [PATCH] Moved File->URI methods to FileUtils --- .../java/io/deephaven/base/FileUtils.java | 71 +++++++++++++++++++ .../channel/SeekableChannelsProvider.java | 71 +------------------ .../parquet/base/ColumnChunkReaderImpl.java | 2 +- .../parquet/base/ParquetFileReader.java | 2 +- .../parquet/table/ParquetTableWriter.java | 2 +- .../deephaven/parquet/table/ParquetTools.java | 2 +- .../location/ParquetTableLocationKey.java | 2 +- .../table/ParquetTableReadWriteTest.java | 2 +- 8 files changed, 79 insertions(+), 75 deletions(-) diff --git a/Base/src/main/java/io/deephaven/base/FileUtils.java b/Base/src/main/java/io/deephaven/base/FileUtils.java index 983c7d3a5b7..367c6896a05 100644 --- a/Base/src/main/java/io/deephaven/base/FileUtils.java +++ b/Base/src/main/java/io/deephaven/base/FileUtils.java @@ -8,6 +8,9 @@ import org.jetbrains.annotations.Nullable; import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Path; import java.util.ArrayList; public class FileUtils { @@ -249,4 +252,72 @@ public boolean accept(File pathname) { || (pathname.isFile() && (normalFileFilter == null || normalFileFilter.accept(pathname))); } } + + /** + * Take the file source path or URI string and convert it to a URI object. + * + * @param source The file source path or URI + * @param isDirectory Whether the source is a directory + * @return The URI object + */ + public static URI convertToURI(final String source, final boolean isDirectory) { + if (source.isEmpty()) { + throw new IllegalArgumentException("Cannot convert empty source to URI"); + } + final URI uri; + try { + uri = new URI(source); + } catch (final URISyntaxException e) { + // If the URI is invalid, assume it's a file path + return convertToURI(new File(source), isDirectory); + } + if (uri.getScheme() == null) { + // Convert to a "file" URI + return convertToURI(new File(source), isDirectory); + } + return uri; + } + + /** + * Takes a file and convert it to a URI object with {@code "file"} scheme. This method is preferred instead of + * {@link File#toURI()} because {@link File#toURI()} internally calls {@link File#isDirectory()}, which typically + * invokes the {@code stat} system call, resulting in filesystem metadata access. + * + * @param file The file + * @param isDirectory Whether the source file is a directory + * @return The URI object + */ + public static URI convertToURI(final File file, final boolean isDirectory) { + String absPath = file.getAbsolutePath(); + if (File.separatorChar != '/') { + absPath = absPath.replace(File.separatorChar, '/'); + } + if (absPath.charAt(0) != '/') { + absPath = "/" + absPath; + } + if (isDirectory && absPath.charAt(absPath.length() - 1) != '/') { + absPath = absPath + "/"; + } + if (absPath.startsWith("//")) { + absPath = "//" + absPath; + } + try { + return new URI("file", null, absPath, null); + } catch (final URISyntaxException e) { + throw new IllegalStateException("Failed to convert file to URI: " + file, e); + } + } + + /** + * Takes a path and convert it to a URI object with {@code "file"} scheme. This method is preferred instead of + * {@link Path#toUri()} because {@link Path#toUri()} internally invokes the {@code stat} system call, resulting in + * filesystem metadata access. + * + * @param path The path + * @param isDirectory Whether the file is a directory + * @return The URI object + */ + public static URI convertToURI(final Path path, final boolean isDirectory) { + return convertToURI(path.toFile(), isDirectory); + } } diff --git a/Util/channel/src/main/java/io/deephaven/util/channel/SeekableChannelsProvider.java b/Util/channel/src/main/java/io/deephaven/util/channel/SeekableChannelsProvider.java index af8c53b66e9..ba7bcf49c74 100644 --- a/Util/channel/src/main/java/io/deephaven/util/channel/SeekableChannelsProvider.java +++ b/Util/channel/src/main/java/io/deephaven/util/channel/SeekableChannelsProvider.java @@ -6,83 +6,16 @@ import io.deephaven.util.SafeCloseable; import org.jetbrains.annotations.NotNull; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; -import java.net.URISyntaxException; import java.nio.channels.SeekableByteChannel; import java.nio.file.Path; import java.nio.file.Paths; -public interface SeekableChannelsProvider extends SafeCloseable { - - /** - * Take the file source path or URI string and convert it to a URI object. - * - * @param source The file source path or URI - * @param isDirectory Whether the source is a directory - * @return The URI object - */ - static URI convertToURI(final String source, final boolean isDirectory) { - if (source.isEmpty()) { - throw new IllegalArgumentException("Cannot convert empty source to URI"); - } - final URI uri; - try { - uri = new URI(source); - } catch (final URISyntaxException e) { - // If the URI is invalid, assume it's a file path - return convertToURI(new File(source), isDirectory); - } - if (uri.getScheme() == null) { - // Convert to a "file" URI - return convertToURI(new File(source), isDirectory); - } - return uri; - } - - /** - * Takes a file and convert it to a URI object. This method is preferred instead of {@link File#toURI()} because - * {@link File#toURI()} internally calls {@link File#isDirectory()}, which typically invokes the {@code stat} system - * call, resulting in filesystem metadata access. - * - * @param file The file - * @param isDirectory Whether the source file is a directory - * @return The URI object - */ - static URI convertToURI(final File file, final boolean isDirectory) { - String absPath = file.getAbsolutePath(); - if (File.separatorChar != '/') { - absPath = absPath.replace(File.separatorChar, '/'); - } - if (absPath.charAt(0) != '/') { - absPath = "/" + absPath; - } - if (isDirectory && absPath.charAt(absPath.length() - 1) != '/') { - absPath = absPath + "/"; - } - if (absPath.startsWith("//")) { - absPath = "//" + absPath; - } - try { - return new URI("file", null, absPath, null); - } catch (final URISyntaxException e) { - throw new IllegalStateException("Failed to convert file to URI: " + file, e); - } - } +import static io.deephaven.base.FileUtils.convertToURI; - /** - * Takes a path and convert it to a URI object. This method is preferred instead of {@link Path#toUri()} because - * {@link Path#toUri()} internally invokes the {@code stat} system call, resulting in filesystem metadata access. - * - * @param path The path - * @param isDirectory Whether the file is a directory - * @return The URI object - */ - static URI convertToURI(final Path path, final boolean isDirectory) { - return convertToURI(path.toFile(), isDirectory); - } +public interface SeekableChannelsProvider extends SafeCloseable { /** * Wraps {@link SeekableChannelsProvider#getInputStream(SeekableByteChannel)} to ensure the channel's position is diff --git a/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ColumnChunkReaderImpl.java b/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ColumnChunkReaderImpl.java index 9f01b6de543..1166b3956b4 100644 --- a/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ColumnChunkReaderImpl.java +++ b/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ColumnChunkReaderImpl.java @@ -32,8 +32,8 @@ import java.util.NoSuchElementException; import java.util.function.Function; +import static io.deephaven.base.FileUtils.convertToURI; import static io.deephaven.parquet.base.ParquetFileReader.FILE_URI_SCHEME; -import static io.deephaven.util.channel.SeekableChannelsProvider.convertToURI; import static org.apache.parquet.format.Encoding.PLAIN_DICTIONARY; import static org.apache.parquet.format.Encoding.RLE_DICTIONARY; diff --git a/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ParquetFileReader.java b/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ParquetFileReader.java index 4cd2e83a49a..e97576f95a7 100644 --- a/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ParquetFileReader.java +++ b/extensions/parquet/base/src/main/java/io/deephaven/parquet/base/ParquetFileReader.java @@ -18,7 +18,7 @@ import java.nio.charset.StandardCharsets; import java.util.*; -import static io.deephaven.util.channel.SeekableChannelsProvider.convertToURI; +import static io.deephaven.base.FileUtils.convertToURI; /** * Top level accessor for a parquet file which can read both from a file path string or a CLI style file URI, diff --git a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTableWriter.java b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTableWriter.java index 70ed5a095f8..66f93a7073b 100644 --- a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTableWriter.java +++ b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTableWriter.java @@ -45,7 +45,7 @@ import java.nio.file.Paths; import java.util.*; -import static io.deephaven.util.channel.SeekableChannelsProvider.convertToURI; +import static io.deephaven.base.FileUtils.convertToURI; /** * API for writing DH tables in parquet format diff --git a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTools.java b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTools.java index 5f4e5907018..dbbdfd88ad7 100644 --- a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTools.java +++ b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/ParquetTools.java @@ -54,8 +54,8 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.*; +import static io.deephaven.base.FileUtils.convertToURI; import static io.deephaven.parquet.base.ParquetFileReader.FILE_URI_SCHEME; -import static io.deephaven.util.channel.SeekableChannelsProvider.convertToURI; import static io.deephaven.parquet.table.ParquetTableWriter.PARQUET_FILE_EXTENSION; import static io.deephaven.util.type.TypeUtils.getUnboxedTypeIfBoxed; diff --git a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/location/ParquetTableLocationKey.java b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/location/ParquetTableLocationKey.java index 09a5cdd8d32..b8fdcb1c5be 100644 --- a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/location/ParquetTableLocationKey.java +++ b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/location/ParquetTableLocationKey.java @@ -23,7 +23,7 @@ import java.util.Map; import java.util.stream.IntStream; -import static io.deephaven.util.channel.SeekableChannelsProvider.convertToURI; +import static io.deephaven.base.FileUtils.convertToURI; /** * {@link TableLocationKey} implementation for use with data stored in the parquet format. diff --git a/extensions/parquet/table/src/test/java/io/deephaven/parquet/table/ParquetTableReadWriteTest.java b/extensions/parquet/table/src/test/java/io/deephaven/parquet/table/ParquetTableReadWriteTest.java index 1c5071daf41..0dfeec49305 100644 --- a/extensions/parquet/table/src/test/java/io/deephaven/parquet/table/ParquetTableReadWriteTest.java +++ b/extensions/parquet/table/src/test/java/io/deephaven/parquet/table/ParquetTableReadWriteTest.java @@ -88,6 +88,7 @@ import javax.annotation.Nullable; +import static io.deephaven.base.FileUtils.convertToURI; import static io.deephaven.engine.testutil.TstUtils.assertTableEquals; import static io.deephaven.engine.util.TableTools.booleanCol; import static io.deephaven.engine.util.TableTools.byteCol; @@ -108,7 +109,6 @@ import static io.deephaven.parquet.table.ParquetTools.readTable; import static io.deephaven.parquet.table.ParquetTools.writeTable; import static io.deephaven.util.QueryConstants.*; -import static io.deephaven.util.channel.SeekableChannelsProvider.convertToURI; import static org.junit.Assert.*; @Category(OutOfBandTest.class)