FileRef.java
package space.sunqian.common.io.file;
import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.Nullable;
import space.sunqian.common.Fs;
import space.sunqian.common.base.chars.CharsKit;
import space.sunqian.common.io.IORuntimeException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
/**
* This interface represents a file reference used to retrieve information and manipulate the file.
*
* @author sunqian
*/
public interface FileRef {
/**
* Returns a new {@link FileRef} from the given path.
*
* @param path the given path
* @return a new {@link FileRef} from the given path
*/
static @Nonnull FileRef of(@Nonnull Path path) {
return new FileRef() {
private File file;
@Override
public @Nonnull File getFile() {
if (file == null) {
file = path.toFile();
}
return file;
}
@Override
public @Nonnull Path getPath() {
return path;
}
};
}
/**
* Returns a new {@link FileRef} from the given file.
*
* @param file the given file
* @return a new {@link FileRef} from the given file
*/
static @Nonnull FileRef of(@Nonnull File file) {
return new FileRef() {
private Path path;
@Override
public @Nonnull File getFile() {
return file;
}
@Override
public @Nonnull Path getPath() {
if (path == null) {
path = file.toPath();
}
return path;
}
};
}
/**
* Returns a new {@link FileRef} from the given path.
*
* @param path the given path
* @return a new {@link FileRef} from the given path
*/
static @Nonnull FileRef of(@Nonnull String path) {
return of(Paths.get(path));
}
/**
* Returns a new {@link FileRef} from the given path string, or a sequence of strings.
*
* @param first the path string or initial part of the path string
* @param more additional path string or initial parts of the path string
* @return a new {@link FileRef} from the given path string, or a sequence of strings
*/
static @Nonnull FileRef of(@Nonnull String first, @Nonnull String @Nonnull ... more) {
return of(Paths.get(first, more));
}
/**
* Returns a new {@link FileRef} from the given uri.
*
* @param uri the given uri
* @return a new {@link FileRef} from the given uri
*/
static @Nonnull FileRef of(@Nonnull URI uri) {
return of(Paths.get(uri));
}
/**
* Returns a new {@link FileRef} from the given url.
*
* @param url the given url
* @return a new {@link FileRef} from the given url
* @throws IORuntimeException if the url is unsupported
*/
static @Nonnull FileRef of(@Nonnull URL url) throws IORuntimeException {
try {
return of(Paths.get(url.toURI()));
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
/**
* Returns the {@link File} object related to this file reference.
*
* @return the {@link File} object related to this file reference
*/
@Nonnull
File getFile();
/**
* Returns the {@link Path} object related to this file reference.
*
* @return the {@link Path} object related to this file reference
*/
@Nonnull
Path getPath();
/**
* Returns the basic file attributes of the referenced file.
*
* @param linkOptions options indicating how symbolic links are handled, can be empty
* @return the basic file attributes of the referenced file
* @throws IORuntimeException if any error occurs
*/
default @Nonnull BasicFileAttributes getBasicFileAttributes(
@Nonnull LinkOption @Nonnull ... linkOptions
) throws IORuntimeException {
try {
return Files.readAttributes(getPath(), BasicFileAttributes.class, linkOptions);
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
/**
* Returns the content type of the referenced file. The return value is in form of {@code MIME}.
*
* @return the content type of the referenced file, or {@code null} if the content type cannot be determined
* @throws IORuntimeException if any error occurs
*/
default @Nullable String getContentType() throws IORuntimeException {
return Fs.uncheck(
() -> Files.probeContentType(getPath()),
IORuntimeException::new
);
}
/**
* Returns all bytes of the referenced file.
*
* @return a new array contains all bytes of the referenced file
* @throws IORuntimeException if any error occurs
*/
default byte @Nonnull [] readBytes() throws IORuntimeException {
try {
return Files.readAllBytes(getPath());
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
/**
* Returns string from the referenced file with the {@link CharsKit#defaultCharset()}.
*
* @return a string from the referenced file with the {@link CharsKit#defaultCharset()}
* @throws IORuntimeException if any error occurs
*/
default @Nonnull String readString() throws IORuntimeException {
return readString(CharsKit.defaultCharset());
}
/**
* Returns string from the referenced file with the specified charset.
*
* @param charset the specified charset
* @return a string from the referenced file with the specified charset
* @throws IORuntimeException if any error occurs
*/
default @Nonnull String readString(@Nonnull Charset charset) throws IORuntimeException {
return new String(readBytes(), charset);
}
/**
* Returns all lines from the referenced file with the {@link CharsKit#defaultCharset()}. This method recognizes the
* following as line separators:
* <ul>
* <li>'\r\n'</li>
* <li>'\n'</li>
* <li>'\r'</li>
* </ul>
*
* @return all lines from the referenced file with the {@link CharsKit#defaultCharset()}
* @throws IORuntimeException if any error occurs
*/
default @Nonnull List<String> readLines() throws IORuntimeException {
return readLines(CharsKit.defaultCharset());
}
/**
* Returns all lines from the referenced file with the specified charset. This method recognizes the following as
* line separators:
* <ul>
* <li>'\r\n'</li>
* <li>'\n'</li>
* <li>'\r'</li>
* </ul>
*
* @param charset the specified charset
* @return all lines from the referenced file with the specified charset
* @throws IORuntimeException if any error occurs
*/
default @Nonnull List<String> readLines(@Nonnull Charset charset) throws IORuntimeException {
try {
return Files.readAllLines(getPath(), charset);
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
/**
* Write bytes to the referenced file with the open options. If no option is specified, this method creates a new
* file or overwrites an existing file.
*
* @param bytes the bytes to write
* @param options the open options
* @throws IORuntimeException if any error occurs
*/
default void writeBytes(byte @Nonnull [] bytes, OpenOption @Nonnull ... options) throws IORuntimeException {
try {
Files.write(getPath(), bytes, options);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
/**
* Write string to the referenced file with the {@link CharsKit#defaultCharset()} and open options. If no option is
* specified, this method creates a new file or overwrites an existing file.
*
* @param string the string to write
* @param options the open options
* @throws IORuntimeException if any error occurs
*/
default void writeString(@Nonnull String string, OpenOption @Nonnull ... options) throws IORuntimeException {
writeString(string, CharsKit.defaultCharset(), options);
}
/**
* Write string to the referenced file with the specified charset and open options. If no option is specified, this
* method creates a new file or overwrites an existing file.
*
* @param string the string to write
* @param charset the specified charset
* @param options the open options
* @throws IORuntimeException if any error occurs
*/
default void writeString(@Nonnull String string, Charset charset, OpenOption @Nonnull ... options) throws IORuntimeException {
writeBytes(string.getBytes(charset), options);
}
/**
* Returns a new {@link FileInputStream} for reading the referenced file.
*
* @return a new {@link FileInputStream} for reading the referenced file
* @throws IORuntimeException if any error occurs
*/
default @Nonnull FileInputStream fileInputStream() throws IORuntimeException {
try {
return new FileInputStream(getFile());
} catch (FileNotFoundException e) {
throw new IORuntimeException(e);
}
}
/**
* Returns a new {@link FileOutputStream} for writing the referenced file in overwrite mode. In overwrite mode, the
* file's content will be overwritten starting from the beginning, and the file's length will be truncated or
* extended to the number of bytes actually written.
*
* @return a new {@link FileOutputStream} for writing the referenced file in overwrite mode
* @throws IORuntimeException if any error occurs
*/
default @Nonnull FileOutputStream fileOutputStream() throws IORuntimeException {
return fileOutputStream(false);
}
/**
* Returns a new {@link FileOutputStream} for writing the referenced file in the specified mode.
* <p>
* In overwrite mode, the file's content will be overwritten starting from the beginning, and the file's length will
* be truncated or extended to the number of bytes actually written. Otherwise in append mode, new bytes will be
* written starting at the end of the file, and the file's length will be extended by the number of bytes actually
* written.
*
* @param append {@code true} for append mode, {@code false} for overwrite mode
* @return a new {@link FileOutputStream} for writing the referenced file in the specified mode
* @throws IORuntimeException if any error occurs
*/
default @Nonnull FileOutputStream fileOutputStream(boolean append) throws IORuntimeException {
try {
return new FileOutputStream(getFile(), append);
} catch (FileNotFoundException e) {
throw new IORuntimeException(e);
}
}
/**
* Opens and returns a new {@link InputStream} for reading the referenced file. If no option is specified, this
* method opens the file for reading.
* <p>
* This method is equivalent to {@link Files#newInputStream(Path, OpenOption...)}.
*
* @param options options specifying how the file is opened
* @return a new {@link InputStream} for reading the referenced file
* @throws IORuntimeException if any error occurs
*/
default @Nonnull InputStream newInputStream(
@Nonnull OpenOption @Nonnull ... options
) throws IORuntimeException {
try {
return Files.newInputStream(getPath(), options);
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
/**
* Opens and returns a new {@link OutputStream} for writing the referenced file. If no option is specified, this
* method opens the file for writing, creating the file if it doesn't exist, or truncating file to {@code 0} size if
* it exists.
* <p>
* This method is equivalent to {@link Files#newOutputStream(Path, OpenOption...)}.
*
* @param options options specifying how the file is opened
* @return a new {@link OutputStream} for writing the referenced file
* @throws IORuntimeException if any error occurs
*/
default @Nonnull OutputStream newOutputStream(
@Nonnull OpenOption @Nonnull ... options
) throws IORuntimeException {
try {
return Files.newOutputStream(getPath(), options);
} catch (Exception e) {
throw new IORuntimeException(e);
}
}
/**
* Opens and returns a new {@link FileChannel} for operating the referenced file.
* <p>
* This method is equivalent to {@link FileChannel#open(Path, OpenOption...)}.
*
* @param options options specifying how the file is opened
* @return a new {@link FileChannel} for operating the referenced file
* @throws IORuntimeException if any error occurs
*/
default @Nonnull FileChannel newFileChannel(
@Nonnull OpenOption @Nonnull ... options
) throws IORuntimeException {
try {
return FileChannel.open(getPath(), options);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
}