I have a path in windows as:
C:\Users\Sneha\.netbeans\5.5.1\tomcat55.properties
How can we convert the above path to Linux path. what does .netbeans and tomcat55.properties path means.
Any help would be appreciated.
asked Jul 6, 2016 at 7:02
4
you should read this webpage to understand difference between file system in linux and windows.
to convert that windows path to linux path, you must know that names of directories and files are case sensitive in linux,
then except using C:\Users\Sneha
use this method in java to get current user path in any machine(windows, linux and etc.)
String user_dir = System.getProperty("user.home");
then in linux, path contains only forward slash /
. not backward slash .
so the path you said
C:UsersSneha.netbeans5.5.1tomcat55.properties
will be
/home/Sneha/.netbeans/5.5.1/tomcat55.properties
also
.netbeans
is a folder,tomcat55.properties
is a file.
answered Jul 6, 2016 at 8:53
Rahmat WaisiRahmat Waisi
1,2551 gold badge16 silver badges35 bronze badges
Convert windows path to unix in java
2016-11-22 08:00
File separator is «/» on UNIX and «» on Windows. Using FilenameUtils
convert path between windows and UNIX is easily. FilenameUtils.separatorsToSystem
method can help you to use correct separator.
public static void main(String[] args) { String unixPath = "/test/linux/path"; String windowsPath = "\test\windows\path"; System.out.println(FilenameUtils.separatorsToWindows(unixPath)); System.out.println(FilenameUtils.separatorsToUnix(windowsPath)); System.out.println(FilenameUtils.separatorsToSystem(windowsPath)); }
the pom file like following.
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
So for example say I had it so that all of my files will be transferred from a windows machine to a unix machine as such: C:testmyFile.txt
to {somewhere}/test/myFile.txt
(drive letter is irrelevant at this point).
Currently, our utility library that we wrote ourselves provides a method that does a simple replace of all back slashes with forward slashes:
public String normalizePath(String path) {
return path.replaceAll("\", "/");
}
Slashes are reserved and cannot be part of a file name, so the directory structure should be preserved. However, I’m not sure if there are other complications between windows and unix paths that I may need to worry about (eg: non-ascii names, etc)
asked Jun 16, 2014 at 16:26
MxLDevsMxLDevs
7793 gold badges10 silver badges15 bronze badges
15
Yes, if you only do the replacement on Windows, and turn it off when running on other systems.
Doing the replacement on Unix-like systems is wrong because is a valid character in a file or directory name on Unix-like platforms. On these platforms, only
NUL
and /
are forbidden in file and directory names.
Also, some Windows API functions (mostly the lower level ones) do not allow the use of forward slashes ― backslashes must be used with them.
Edit: It turns out that there are some special file systems on Windows on which /
and NUL are valid characters, such as the Registry (available at \?GLOBALROOTRegistry
from a Windows API perspective, or Registry
from the Native API perspective). In the Named Pipe File System (usually mounted at ??pipe
), all characters (including /
, , and even NUL) are valid. So in general, not only is it not valid to replace
/
with on Windows, it is not valid to assume that every Windows file can be accessed using the Windows API! To reliably access arbitrary files, one must use the Native API (
NtCreateFile
and friends). NtCreateFile
also exposes an equivalent of openat(2)
, which isn’t exposed via the Windows API.
answered Jul 23, 2014 at 0:41
DemiDemi
8167 silver badges18 bronze badges
Yes, but this whole thing is a moot point. Java seamlessly converts forward slashes to back slashes on Windows. You can simply use forward slashes for all paths that are hard-coded or stored in configuration and it will work for both platforms.
Personally, I always use the forward slash even on Windows because it is not the escape character. Whether the raw path is in code or externalized in a properties file, I encode it the same way.
Try it! This will work in Windows. Obviously, change the actual path to something that exists and your user has permission to read.
File f = new File("c:/some/path/file.txt");
if (!f.canRead()) {
System.out.println("Uh oh, Snowman was wrong!");
}
Bonus: you can even mix slashes in the same path!
File f = new File("c:/some\path/file.txt");
if (!f.canRead()) {
System.out.println("Uh oh, Snowman was wrong again!");
}
answered Aug 22, 2014 at 1:26
6
Another complication on Windows is that it also supports UNC notation as well as the traditional drive letters.
A file on a remote file server can be accessed as \serversharenamepathfilename
.
answered Aug 22, 2014 at 10:39
Simon BSimon B
8,9164 gold badges26 silver badges32 bronze badges
1
No. There are far more things to think about than just the path separator (the » vs /» thing). As Rob Y mentions, there is how spaces are handled, and their high frequency in Windows usage. There are different illegal characters in the two environments. There is Unix’s willingness to allow almost anything when escaped by a leading «». There is Windows use of ‘»‘ to deal with embedded spaces. There is Windows’ use of UCS-16 and Unix’s use of ASCII or UTF-8.
etc., etc., etc.
But, for lots of applications that can put constraints on the pathnames they need to manipulate, you actually can do it just the way you suggest. And it will work in at least a large number of the cases, just not all of them.
answered Aug 22, 2014 at 1:02
1
Every Microsoft operating system, starting with MS-DOS, has understood, at the kernel level, both forward slashes and backslashes.
Therefore, on Windows, you can convert between them freely; both have equal status as reserved separators. In any valid path, you can replace backslashes with slashes and vice versa, without changing its meaning, as far as the kernel is concerned.
In early versions of DOS, Microsoft’s command.com
interpreter made it a configurable preference which slash was used to display and parse paths. That was eventually removed.
Some user-space programs in Windows such as, oh, the Windows shell (explorer.exe
) do not like forward slashes. That’s just shoddy programming in those programs.
answered Jul 8, 2016 at 3:16
KazKaz
3,5241 gold badge18 silver badges30 bronze badges
2
Цикл статей «Учебник Java 8».
Следующая статья — «Java 8 многопоточность».
Предыдущая статья — «Java 8 сериализация».
Содержание
java.nio.file.Path
Что такое Glob?
java.nio.file.Files
— Проверка существования файла или каталога
— Проверка прав доступа к файлу или каталогу
— Один и тот же файл
— Удаление файла или каталога
— Копирование файла или каталога
— Перемещение файла или каталога
— Управление метаданными
— Чтение, запись и создание файлов
— — OpenOption
— — Наиболее часто используемые методы для небольших файлов
— — Буферизированный ввод и вывод в текстовые файлы
— — Небуферезированный ввод и вывод
— — Создание файлов
— — Создание временных файлов
— Файлы с произвольным доступом
— Создание и чтение каталогов
— — Перечисление корневых каталогов файловой системы
— — Создание каталога
— — Создание временного каталога
— — Перечисление содержимого каталога
— Символические и другие ссылки
— — Создание символических ссылок
— — Создание жёстких ссылок
— — Определение символической ссылки
— — Нахождение цели ссылки
— Обход дерева файлов
— — Интерфейс java.nio.file.FileVisitor
— — Запуск процесса обхода дерева файлов
— — Размышления о FileVisitor
— — Управление обходом дерева файлов
— — Примеры
— Поиск файлов
Подписываемся на изменения в каталоге
— Обработка событий
java.nio.file.Path
Path представляет из себя путь в файловой системе. Он содержит имя файла и список каталогов, определяющих путь к файлу.
Экземпляры
Path отражают путь в конкретной платформе (например
/home/jho/foo для Linux или
C:homejhofoo для Windows). Экземпляры
Path зависят от платформы. Нельзя сравнивать
Path из Linux с путём из Windows, даже если структура их каталогов одинаковая, и оба этих экземпляра указывают на один и тот же относительный файл.
Path может указывать на файл или каталог, которых не существует. Методы
Path работают только с представлением пути. Они не проверяют существование пути.
Создавать экземпляры
Path можно разными способами.
Можно использовать методы
java.nio.file.Paths.get() :
public static Path get(String first, String... more) |
public static Path get(URI uri) |
Примеры:
Path p1 = Paths.get(«/tmp/foo»); Path p2 = Paths.get(args[0]); Path p3 = Paths.get(URI.create(«file:///Users/joe/FileTest.java»)); |
Эти методы являются сокращённой формой для следующего кода:
Path p4 = java.nio.file.FileSystems.getDefault().getPath(«/users/sally»); |
Можно рассматривать
Path как класс, сохраняющий имена каталогов в пути и имя файла в виде последовательности. Наивысший (ближний к корневому) элемент находится по индексу 0, самый нижний элемент находится по индексу
n—1 , где
n — количество элементов в пути.
Получить конкретный элемент пути можно с помощью метода
getName() :
String element0 = path.getName(0) // Для пути /homme/jho/foo (Linux) вернётся home // Для пути C:homejoefoo (Windows) вернётся home. |
Узнать количество элементов в пути можно с помощью метода
getNameCount():
int nameCount = path.getNameCount(); // Для /home/jho/foo (Linux) вернёт 3 // Для C:homejhofoo (Windows) вернёт 3 |
Можно получить путь родительской директории с помощью метода
getParent() :
Path parentPath = path.getParent(); // Для /home/jho/foo (Linux) вернётся /home/jho // Для C:homejhofoo Windows вернётся C:homejho // Вернёт null, если родительского элемента нет. |
Можно получить корень пути с помощью метода
getRoot() :
Path rootPath = path.getRoot(); // Для /home/jho/foo (Linux) вернёт / // Для C:homejhofoo (Windos) вернёт C: // Вернёт null, если путь относительный и корня нет. |
С помощью метода
toString() можно получить путь в виде строки:
String str1 = path.toString() // Вернёт строку «/home/jho/foo» для пути /home/jho/foo (Linux). // Вернёт строку «C:homejhofoo» для пути C:homejhofoo (Windows). |
Многие файловые системы используют символ точки «.» для обозначения текущего каталога и две точки «..» для обозначения родительского каталога. Например:
/home/./jho/foo /home/sandy/../jho/foo |
Метод
normalize() удаляет все подобные элементы и приводит к нормализованному пути
/home/jho/foo/. Этот метод не проверяет файловую систему. Это чисто синтетическая операция, работающая с элементами
Path. Если
sandy является символической ссылкой, то удаление
sandy/.. может привести к тому, что
Path больше не указывает на предыдущий файл.
Если вам нужно преобразовать
Path к строке, с помощью которой можно открыть файл в браузере, то используйте метод
toUri():
Path p1 = Paths.get(«/home/logfile»); // Result is file:///home/logfile System.out.format(«%s%n», p1.toUri()); |
Метод
toAbsolutePath() преобразует путь к абсолютному. Способ преобразования зависит от системы. Если переданный путь уже является абсолютным, то возвращается тот же самый объект
Path.
Метод
toRealPath() возвращает реальный путь существующего файла. В качестве параметра в метод можно передать константу перечисления
java.nio.file.LinkOption с единственным возможным значением
NOFOLLOW_LINKS . Метод бросает исключение, если файл не существует, либо к нему нет доступа. Этот метод убирает все элементы «.» и «..» и возвращает всегда абсолютный путь.
try { Path fp = path.toRealPath(); } catch (NoSuchFileException x) { System.err.format(«%s: no such» + » file or directory%n», path); // Logic for case when file doesn’t exist. } catch (IOException x) { System.err.format(«%s%n», x); // Logic for other sort of file error. } |
Можно объединять пути с помощью метода
resolve() , в который передаётся часть пути, которую нужно добавить к исходному пути:
// Solaris Path p1 = Paths.get(«/home/joe/foo»); // Result is /home/joe/foo/bar System.out.format(«%s%n», p1.resolve(«bar»)); |
Или для Windows:
// Microsoft Windows Path p1 = Paths.get(«C:\home\joe\foo»); // Result is C:homejoefoobar System.out.format(«%s%n», p1.resolve(«bar»)); |
С помощью метода
relativize() можно создать относительный путь от одного пути к другому:
Path p1 = Paths.get(«jho»); Path p2 = Paths.get(«sandy»); // Так как нет другой информации, то считается, что // jho и sandy находятся в одном каталоге. // Result is ../sandy Path p1_to_p2 = p1.relativize(p2); // Result is ../jho Path p2_to_p1 = p2.relativize(p1); |
Слегка усложнённый пример:
Path p1 = Paths.get(«home»); Path p3 = Paths.get(«home/sandy/bar»); // Result is sandy/bar Path p1_to_p3 = p1.relativize(p3); // Result is ../.. Path p3_to_p1 = p3.relativize(p1); |
Относительный путь не может быть получен только в том случае, когда только один из путей имеет корневой элемент. Если оба пути имеют корневой элемент, но возможность построения относительного пути зависит от системы.
Path поддерживает метод
equals(), что позволяет сравнивать пути. Так же есть методы
startsWith(Path other) ,
startsWith(String other) ,
endsWith(Path other) ,
endsWith(String other) , позволяющие проверять начало и конец пути на совпадение с указанной строкой или частью пути. Path реализует интерфейс Comparable, что позволяет сортировать строки.
Что такое Glob?
Некоторые методы класса
java.nio.file.Files принимают аргумент glob. Шаблон glob использует следующие правила:
Символ «*» обозначает любое количество символов (включая отсутствие символов).
Две снежинки «**» работают так же, как и одна, но переходят за границы каталогов.
Символ вопроса «?» обозначает ровно один символ.
Фигурные скобки указывают коллекцию паттернов. Например
{sun,moon,starts} совпадает с
«sun» ,
«moon» или
«starts».
{temp*, tmp*} совпадает со всеми строками, начинающимися с
«temp» или
«tmp».
Квадратные скобки позволяют указать набор символов либо диапазон символов:
[aeiou] обозначает любую строчную гласную.
[0-9] обозначает любую цифру
[A-Z] обозначает любую прописную букву.
[a-z,A-Z] обозначает любую строчную или прописную букву.
Внутри квадратных скобок «*», «?» и «/» обозначают самих себя.
java.nio.file.Files
Проверка существования файла или каталога
Проверить существование пути
Path можно с помощью методов:
public static boolean exists(Path path, LinkOption... options) |
public static boolean notExists(Path path, LinkOption... options) |
Если передать константу
LinkOption.NOFOLLOW_LINKS , то метод не будет проходить по символическим ссылкам. Если оба метода
exists() и
notExists() возвращают
false , то существование файла не может быть проверено (например нет доступа).
Проверка прав доступа к файлу или каталогу
Проверка доступа к файлу осуществляется с помощью методов:
// Проверяет, что файл доступен для чтения public static boolean isReadable(Path path) |
// Проверяет, что файл доступен для записи public static boolean isWritable(Path path) |
// Проверяет, что файл доступен для выполнения public static boolean isExecutable(Path path) |
Один и тот же файл
Можно проверить, что два пути указывают на один и тот же файл на одной и той же файловой системе:
public static boolean isSameFile(Path path, Path path2) throws IOException |
Удаление файла или каталога
Метод
delete(Path) удаляет файл или бросает исключение, если удалить файл не удалось. Можно удалять каталог, но только если он пустой.
try { Files.delete(path); } catch (NoSuchFileException x) { System.err.format(«%s: no such» + » file or directory%n», path); } catch (DirectoryNotEmptyException x) { System.err.format(«%s not empty%n», path); } catch (IOException x) { // File permission problems are caught here. System.err.println(x); } |
Метод
public static boolean deleteIfExists(Path path) throws IOExceptio |
тоже удаляет файл, но не бросает никаких исключений, если файл не существует. Это может быть полезно, если два потока удаляют файл и вы не хотите получать исключение из-за того, что другой поток уже удалил файл до этого.
Копирование файла или каталога
Можно копировать файл или каталог с помощью метода
copy(Path, Path, CopyOption...) , но имейте в виду, что файлы внутри каталога не копируются этим методом. Метод принимает константы
CopyOption:
StandardCopyOption.REPLACE_EXISTING заменять существующие файлы.
StandardCopyOption.COPY_ATTRIBUTES копирует атрибуты файла.
LinkOption.NOFOLLOW_LINKS не переходить по символическим ссылкам.
Перемещение файла или каталога
Можно переместить файл или каталог с помощью метода
move(Path, Path, CopyOption...) . Можно перемещать пустые каталоги. Возможность перемещения каталогов с содержимым зависит от платформы. Метод принимает
CopyOption:
- StandardCopyOption.REPLACE_EXISTING заменяет существующий файл, если он существует.
- StandardCopyOption.ATOMIC_MOVE попытка осуществить перемещение файла как единую атомарную операцию. Все остальные опции игнорируются.
Управление метаданными
Метаданные файлов это: размер, дата создания, дата последнего изменения, владелец, права доступа и прочее.
Метаданные файлов и каталогов часто называют атрибутами файлов.
Методы для работы с метаданными:
public static long size(Path path) throws IOException |
Возвращает размер файла в байтах.
public static boolean isDirectory(Path path, LinkOption... options) |
Проверяет, что
path указывает на каталог. Можно указать
LinkOption.NOFOLLOW_LINKS , чтобы метод не переходил по символическим ссылкам.
public static boolean isRegularFile(Path path, LinkOption... options) |
Возвращает
true, если
path указывает на обычный файл. Можно передать
LinkOption.NOFOLLOW_LINKS, чтобы метод не переходил по символическим ссылкам.
public static boolean isSymbolicLink(Path path) |
Возвращает
true , если
path указывает на символическую ссылку.
public static boolean isHidden(Path path) throws IOException |
Возвращает
true, если файл является скрытым. Для Linux файл является скрытым, если его имя начинается с точки. Для Windows файл является скрытым, если установлен соответствующий атрибут.
public static FileTime getLastModifiedTime(Path path, LinkOption... options) throws IOException |
Возвращает FileTime с датой последнего изменения файла. Можно передать
LinkOption.NOFOLLOW_LINKS , чтобы метод не переходил по символическим ссылкам.
public static Path setLastModifiedTime(Path path, FileTime time) throws IOException |
Устанавливает дату последнего изменения файла. Смотрите описание класса FileTime в документации Oracle.
public static UserPrincipal getOwner(Path path, LinkOption... options) throws IOException |
Возвращает владельца файла. Можно использовать метод
String getName() у возвращённого объекта, чтобы получить имя пользователя.
public static Path setOwner(Path path, UserPrincipal owner) throws IOException |
Меняет владельца файла.
Различные файловые системы имеют различные атрибуты файлов. Можно считывать группы атрибутов:
- BasicFileAttributeView — базовые атрибуты файлов, которые должны поддерживаться всеми реализациями файловых систем.
- DosFileAttributeView — расширяет стандартные атрибуты 4 битам (скрытый, архивный, только чтение, системный).
- PosixFileAttributeView — расширяет базовые атрибуты атрибутами системы Linux.
- FileOwnerAttributeView — поддерживается всеми файловыми системами, которые поддерживают владельцев файлов.
- AclFileAttributeView — права доступа к файлу, которые реализованы в Windows.
- UserDefinedFileAttributeView — пользовательские метаданные.
Получение конкретной группы атрибутов происходит с помощью метода
public static <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options) |
Пример:
Path path = ... AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class); if (view != null) { List<AclEntry> acl = view.getAcl(); // … } |
Работа с конкретными группами метаданных/атрибутов очень зависит от платформы. Вам вряд ли когда-нибудь придётся столкнуться с этим. Но если интересно, то рекомендую рассмотреть мой проект niofilecommander, который использует все группы атрибутов, описанные здесь.
Чтение, запись и создание файлов
OpenOption
Многие методы, описанные в этом разделе используют
OpenOption в качестве своих параметров. В этом случае в метод можно передавать следующие значения:
- LinkOption.NOFOLLOW_LINKS не переходить по символическим ссылкам.
- StandardOpenOption.APPEND если файл открыт для записи, то байты будут добавляться в конец файла, а не в начало.
- StandardOpenOption.CREATE создавать новый файл, если его нет.
- StandardOpenOption.CREATE_NEW создавать новый файл. Если файл уже существует, то происходит ошибка.
- StandardOpenOption.DELETE_ON_CLOSE удалять файл при закрытии.
- StandardOpenOption.DSYNC каждое обновление содержимого файла синхронного пишется на устройство хранения (жёсткий диск).
- StandardOpenOption.READ открыть для чтения
- StandardOpenOption.SPARCE sparce file
- StandardOpenOption.SYNC каждое обновление содержимого файла или метаданных синхронно пишется на устройство чтения (жёсткий диск).
- StandardOpenOption.TRUNCATE_EXISTING если файл уже существует и открывается для записи, то его длина устанавливается в 0.
- StandardOpenOption.WRITE открывает файл на запись.
Наиболее часто используемые методы для небольших файлов
public static byte[] readAllBytes(Path path) throws IOException |
Читает содержимое файла и возвращает его в массиве байт.
public static List<String> readAllLines(Path path, Charset cs) throws IOException |
Читает содержимое текстового файла и возвращает его в виде списка строк.
public static Path write(Path path, byte[] bytes, OpenOption... options) throws IOException |
Записывает байты в файл.
public static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options) throws IOException |
Записывает строки в файл, преобразуя их в указанную кодировку.
Буферизированный ввод и вывод в текстовые файлы
public static BufferedReader newBufferedReader(Path path, Charset cs) throws IOException |
Возвращает
BufferedReader, который может быть использован для чтения из текстового файла.
public static BufferedWriter newBufferedWriter(Path path, Charset cs, OpenOption... options) throws IOException |
Открывает или создаёт файл для записи. Возвращаемый
BufferedWriter может быть использован для записи в файл. Если
OpenOption не переданы, то используются опции:
CREATE ,
TRUNCATE_EXISTING ,
WRITE.
Небуферезированный ввод и вывод
public static InputStream newInputStream(Path path, OpenOption... options) throws IOException |
Возвращает поток, который можно использовать для чтения байт из файла.
public static OutputStream newOutputStream(Path path, OpenOption... options) throws IOException |
Возвращает поток, который можно использовать для записи байт в файл. Если
OpenOption не переданы, то используются опции:
CREATE,
TRUNCATE_EXISTING,
WRITE.
Создание файлов
public static Path createFile(Path path, FileAttribute<?>... attrs) throws IOException |
Создаёт новый и пустой файл. Бросает исключение, если файл уже существует.
Создание временных файлов
public static Path createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>... attrs) throws IOException |
Создаёт временный файл в указанном каталоге. Является только частью работы с временными файлами. Вы можете использовать метод
File.deleteOnExit(), для того чтобы каталог удалялся автоматически.
public static Path createTempFile(String prefix, String suffix, FileAttribute<?>... attrs) throws IOException |
Создаёт временный файл в специальном каталоге для временных файлов. Является только частью работы с временными файлами. Вы можете использовать метод
File.deleteOnExit(), для того чтобы каталог удалялся автоматически.
Файлы с произвольным доступом
Файл можно открыть одновременно для чтения и записи и с возможностью перемещения текущей позиции в любое место файла. Подобная функциональность реализуется с помощью интерфейса
java.nio.channels.SeekableByteChannel.
Получить экземпляр класса, реализующего интерфейс
SeekableByteChannel, можно с помощью статического метода из класса
Files:
public static SeekableByteChannel newByteChannel(Path path, OpenOption... options) throws IOException |
либо:
public static SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException |
Пример использования:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
String s = «I was here!n»; byte data[] = s.getBytes(); ByteBuffer out = ByteBuffer.wrap(data); ByteBuffer copy = ByteBuffer.allocate(12); try (FileChannel fc = (FileChannel.open(file, READ, WRITE))) { // Читаем первые 12 // байт из файла. int nread; do { nread = fc.read(copy); } while (nread != —1 && copy.hasRemaining()); // Пишем «I was here!» в начало файла. fc.position(0); while (out.hasRemaining()) fc.write(out); out.rewind(); // Перемещаемся в конец файла. Копируем первые 12 байт в // конец файла. Пишем «I was here!» снова. long length = fc.size(); fc.position(length—1); copy.flip(); while (copy.hasRemaining()) fc.write(copy); while (out.hasRemaining()) fc.write(out); } catch (IOException x) { System.out.println(«I/O Exception: « + x); } |
Создание и чтение каталогов
Перечисление корневых каталогов файловой системы
Для этого используется специальный метод класса
FileSystem :
public abstract Iterable<Path> getRootDirectories() |
Пример:
Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories(); for (Path name: dirs) { System.err.println(name); } |
Создание каталога
Метод класса
Files :
public static Path createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException |
Создаёт каталог.
public static Path createDirectories(Path dir, FileAttribute<?>... attrs) throws IOException |
Создаёт каталог вместе со всеми родительскими каталогами, которых ещё нет.
Создание временного каталога
public static Path createTempDirectory(Path dir, String prefix, FileAttribute<?>... attrs) throws IOException |
Создаёт временный каталог. Как и методы
createTempFile является только частью работы с временными файлами. Вы можете использовать метод
File.deleteOnExit(), для того чтобы каталог удалялся автоматически.
public static Path createTempDirectory(String prefix, FileAttribute<?>... attrs) throws IOException |
Создаёт временный каталог в специалном каталоге для временных файлов. Как и методы
createTempFile является только частью работы с временными файлами. Вы можете использовать метод
File.deleteOnExit(), для того чтобы каталог удалялся автоматически.
Перечисление содержимого каталога
public static DirectoryStream<Path> newDirectoryStream(Path dir) throws IOException |
Возвращает поток, который позволяет пройтись по всем элементам каталога.
Пример использования:
Path dir = ...; try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { for (Path file: stream) { System.out.println(file.getFileName()); } } catch (IOException | DirectoryIteratorException x) { // IOException не может броситься во время итерации. // В этом куске кода оно может броситься только // методом newDirectoryStream. System.err.println(x); } |
public static DirectoryStream<Path> newDirectoryStream(Path dir, String glob) throws IOException |
Позволяет посмотреть элементы каталога, названия которых удовлетворяют переданному шаблону Glob.
Например, следующий код возвращает список файлов с расширениями «.class», «.java», «.jar»:
Path dir = ...; try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, «*.{java,class,jar}»)) { for (Path entry: stream) { System.out.println(entry.getFileName()); } } catch (IOException x) { // IOException никогда не бросится во время итерации. // В этом куске кода оно может броситься только // методом newDirectoryStream System.err.println(x); } |
Можно написать свой собственный фильтр для содержимого каталога. Например, этот фильтр будет возвращать только каталоги:
DirectoryStream.Filter<Path> filter = newDirectoryStream.Filter<Path>() { public boolean accept(Path file) throws IOException { try { return (Files.isDirectory(path)); } catch (IOException x) { // Failed to determine if it’s a directory. System.err.println(x); return false; } } }; |
Фильтр применяется методом:
public static DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException |
Пример:
Path dir = ...; try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { for (Path entry: stream) { System.out.println(entry.getFileName()); } } catch (IOException x) { System.err.println(x); } |
Символические и другие ссылки
Каждый метод класса
Path автоматически обрабатывает символические ссылки, либо предоставляет опции, которые позволяют указать, каким образом их обрабатывать.
Ссылки бывают символическими и жёсткими. Жёсткие ссылки имеют больше ограничений, чем символические:
- Цель, на которую указывает жёсткая ссылка, должна существовать.
- Жёсткие ссылки обычно не могут указывать на каталоги.
- Жёсткие ссылки не могут указывать на другой раздел или том и не могут указывать на другую файловую систему.
- Жёсткие ссылки выглядят и ведут себя так, как обычный файл, поэтому их может быть трудно обнаружить.
- Жёсткая ссылка для всех целей и действий является той же сущностью, что и исходный файл. Они имеют те же самые права доступа, временные метки и т. д.
Из-за таких ограничений жёсткие ссылки не так часто используются, как символические ссылки.
Создание символических ссылок
Если ваша файловая система поддерживает символические ссылки, то вы можете создавать их с помощью метода класса
Files:
public static Path createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs) throws IOException |
Этот метод создаёт символическую ссылку по пути
link, указывающую на
target. Параметр
attrs позволяет задать атрибуты ссылки.
Создание жёстких ссылок
public static Path createLink(Path link, Path existing) throws IOException |
Создаёт жёсткую ссылку по пути
link, указывающую на
existing.
Определение символической ссылки
public static boolean isSymbolicLink(Path path) |
Этот метод класса
Files возвращает
true, если файл является символической ссылкой.
Нахождение цели ссылки
public static Path readSymbolicLink(Path link) throws IOException |
Этот метод класса
Files возвращает путь, на который указывает символическая ссылка. Если link не является ссылкой, то бросается исключение
java.nio.file.NotLinkException.
Обход дерева файлов
Интерфейс java.nio.file.FileVisitor
Чтобы обходить дерево файлов нужно сперва написать класс, реализующий интерфейс
FileVisitor. Этот интерфейс позволяет описать действия, которые будут происходить в основные моменты обхода дерева файлов: при посещении файла, перед доступом к каталогу, после доступа к каталогу и при возникновении ошибки.
FileVisitor имеет четыре метода для этих ситуаций:
- preVisitDirectory — вызывается перед посещением элементов каталога.
- postVisitDirectory — вызывается после посещения всех элементов каталога.
- visitFile — вызывается при посещении файла. В метод передаются
BasicFileAttributes. - visitFileFailed — вызывается в случае, когда не удаётся получить доступ к файлу.
Если вам не нужны все эти четыре метода, то вы можете вместо реализации интерфейса
FileVisitor унаследоваться от
java.nio.file.SimpleFileVisitor. Этот класс реализует
FileVisitor и посещает все файлы в дереве, бросая исключение
IOException при возникновении ошибки. Вы можете отнаследоваться от этого класса и реализовать только те методы, которые вам нужны.
Пример реализации
SimpleFileVisitor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import static java.nio.file.FileVisitResult.*; public static class PrintFiles extends SimpleFileVisitor<Path> { // Выводит в консоль информацию о // каждом типе файлов. @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attr) { if (attr.isSymbolicLink()) { System.out.format(«Symbolic link: %s «, file); } else if (attr.isRegularFile()) { System.out.format(«Regular file: %s «, file); } else { System.out.format(«Other: %s «, file); } System.out.println(«(« + attr.size() + «bytes)»); return CONTINUE; } // Пишет в консоль каждый посещаяемый каталог @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { System.out.format(«Directory: %s%n», dir); return CONTINUE; } // Если возникла какая-нибудь ошибка при доступе к файлу, // то выводим эту ошибку. // Если вы не переопределите этот метод, и возникнет // ошибка, то бросится исключение IOException @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { System.err.println(exc); return CONTINUE; } } |
Запуск процесса обхода дерева файлов
public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor) throws IOException |
или
public static Path walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor) throws IOException |
Второй метод позволяет задать максимальную глубину обхода и
FileVisitOpion.FOLLOW_LINKS, что позволит заходить в символические ссылки.
Пример для нашего
PrintFiles :
Path startingDir = ...; PrintFiles pf = new PrintFiles(); Files.walkFileTree(startingDir, pf); |
Размышления о FileVisitor
Дерево файлов обходится в глубину, но вы не можете предугадать порядок посещения подкаталогов.
Если ваша программа делает изменения в файловой системе, то вам нужно внимательно реализовывать ваш
FileVisitor.
Например, если вы пишете рекурсивное удаление, то сначала вам нужно удалить файлы в каталоге, а затем удалят сам каталог. В этом случае удалять каталог нужно в методе
postVisitDirectory.
Если вы пишете рекурсивное копирование, то вам сначала нужно создавать каталог в
preVisitDirectory, а лишь потом копировать файлы в
visitFiles. Если вам нужно скопировать атрибуты с исходного каталога, то это нужно делать после копирования каталога, то есть в
postVisitDirectory.
Если вы пишете поиск файла, то осуществляйте сравнение в
visitFile, если вам нужно находить не только файлы, но и каталоги, то используйте в добавок метод
preVisitDirectory или
postVisitDirectory.
Вам также нужно решить, как обрабатывать символические ссылки. Если вы удаляете файлы, то переходить по символическим ссылкам, скорее всего, не нужно. Если вы копируете дерево файлов, то вам потребуется переходить по ссылкам, скорее всего. По умолчанию метод
walkFileTree не переходит по символическим ссылкам.
Метод
visitFile вызывается для файлов. Если вы указали
FOLLOW_LINKS, и ваше дерево файлов имеет циклическую ссылку на родительский каталог, то во время повторение каталога будет сообщено в
visitFileFailed с помощью исключения
FileSystemLoopException.
Управление обходом дерева файлов
Во время обхода может потребоваться не заходить внутрь какого-либо каталога либо даже прервать обход дерева. Методы
FileVisitor возвращают
java.nio.file.FileVisitResult, которое является перечислением со следующими константами:
-
FileVisitResult.CONTINUE — указывает, что обход дерева файлов должен продолжаться. Если метод
preVisitDirectory возвращает
CONTINUE , то каталог посещаяется. - FileVisitResult.TERMINATE — прерывает обход всего дерева файлов.
-
FileVisitResult.SKIP_SUBTREE — Если
preVisitDirectory возвращает это значение, то указанный каталог и его подкаталоги пропускаются. -
FileVisitResult.SKIP_SIBLINGS — Если
preVisitDirectory возвращает это значение, то указанный каталог не посещается, и
postVisitDirectory не вызывается. Если возвращается из
postVisitDirectory, то остальные каталоги с тем же родительским каталогом пропускаются.
Примеры
Смотрите примеры в niofilecommander.
Поиск файлов
Каждая реализация файловой системы поставляет свою реализацию интерфейса
java.nio.file.PathMatcher.
Вы можете получить экземпляр класса, реализующий этот интерфейс для файловой системы вот так:
String pattern = ...; PathMatcher matcher = FileSystems.getDefault().getPathMatcher(«glob:» + pattern); |
Строка, которая передаётся в этот метод, указывает какие файлы искать. В этом примере используется синтаксис glob. Можно использовать регулярные выражения, тогда вместо
«glob:» нужно писать
«regex:».
В дальнейшем этот
matcher можно использовать при обходе дерева файлов вот так:
if (matcher.matches(filename)) { System.out.println(filename); } |
Подписываемся на изменения в каталоге
Последовательность шагов, которую нужно проделать, для того чтобы следить за изменениями в каком-нибудь каталоге:
- Создаём экземпляр
WatchService для файловой системы. - Для каждого каталога, за которым нужно наблюдать, регистрируем наблюдателя (watcher). При регистрации каталога вы указываете события, о которых вам бы хотелось знать. Для каждого каталога вы получаете экземпляр класса
WatchKey. - Делаем бесконечный цикл на входящих событиях. При возникновении события
WatchKey этого каталога получает сигнал и кладётся в очередь наблюдателя. - Получаем
WatchKey из очереди. Вы можете получить имя файла из этого ключа. - Получаем каждое событие для ключа (их может быть несколько) и обрабатываем.
- Сбрасываем
WatchKey и возвращаемся в ожиданию событий. - Закрываем
WatchServce. Он закрывается при выходе из потоки либо при вызове метода.
Экземпляры
WatchKey потокобезопасны.
Пример:
import static java.nio.file.StandardWatchEventKinds.*; ... WatchService watcher = FileSystems.getDefault().newWatchService(); Path dir = ...; try { WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); } catch (IOException x) { System.err.println(x); } |
Обработка событий
Сначала мы получаем
WatchKey с помощью одного из методов
WatchService :
Удаляет из очереди и возвращает следующий
WatchKey либо
null , если очередь пуста.
WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException |
Удаляет из очереди и возвращает следующий
WatchKey. Ждёт, если нужно, указанное количество времени.
WatchKey take() throws InterruptedException |
Удаляет из очереди и возвращает следующий
WatchKey. Если очередь пуста, то ждёт до тех пор, пока не появится хоть что-нибудь.
Затем обрабатываются все события из
WatchKey, которые получаются при вызове его метода:
List<WatchEvent<?>> pollEvents() |
Тип события получается с помощью следующего метода
WatchEvent :
WatchEvent.Kind<T> kind() |
Не зависимо от событий, на которые мы подписаны, мы может получить событие
OVERFLOW.
Получаем имя файла из события с помощью метода
context() , который возвращает относительный путь к файлу от каталога, на изменения в котором мы подписаны.
Вызываем
reset() на
WatchKey . Если он вернул
false, то он больше не работает и из цикла можно выходить.
Пример обработки событий изменения содержимого каталога можно увидеть в niofilecommander, который обновляет свои панели при добавлении, переименовании и удалении файлов в них.
Цикл статей «Учебник Java 8».
Следующая статья — «Java 8 многопоточность».
Предыдущая статья — «Java 8 сериализация».
Improve Article
Save Article
Improve Article
Save Article
PATH is an environment variable that is used by Operating System to locate the exe files (.exe) or java binaries ( java or javac command). The path once it is set, cannot be overridden. The PATH variable prevents us from having to write out the entire path to a program on the Command Line Interface every time we run it. Moreover, the path is just a variable that stores a bunch of shortcuts.
To execute java console-based programs in windows or Linux environments we have to use java and javac commands. The commands java and javac are not known to the operating system as we don’t specify where the executables reside. Hence, we need to specify the path where the executables are located. This is the reason we set the path and specify the path of the bin folder because the bin contains all binary executable files. After setting the path it can load all necessary items in the program including the compiler or interpreter itself.
Below is the procedure for setting the path for both Windows and Linux:
Setting Java Path in Windows
1. Go to the Search box and type advanced system settings in it. Now click on the View advanced system settings.
2. Select the Advanced tab and then click environment variables.
3. In the system, variables click the New button. Now in the edit system variable, type variable name as JAVA_HOME and variable path as the path where the JDK folder is saved and click on OK button Usually the path of the JDK file will be C:Program FilesJavajdk1.8.0_60.
4. Now in the system variables go to the path and click the edit button.
5. Click the New button.
6. Now add the following path: %JAVA_HOME%bin
Setting Java Path in Linux
- Open the terminal and enter the following command:
sudo nano /etc/environment.
- A file will be opened and add the following command to that file:
JAVA_HOME = "YOUR_PATH".
- Replace YOUR_PATH with the JDK bin file path.
- Now restart your computer or virtual machine that you are using (or) reload the file: source /etc/environment
- You can test the path by executing
echo $JAVA_HOME
- If you get the output without any error, then you’ve set the path correctly.
- If you get any errors, try repeating the procedure again.
After covering file reading and writing operations in Java, this third part of the series of articles shows how to use the classes File
, Path
, and Paths
to construct file and directory paths – regardless of the operating system.
If you have already dealt with file operations in Java, you have probably used these classes to pass a filename to one of the read or write operations with new File()
, Paths.get()
or Path.of()
.
Most programmers do not study these classes in much more detail. This is partly because these classes can be confusing even for experienced Java programmers: What is the difference between File.getName()
and File.getPath()
? What is the difference between File.getAbsolutePath()
, File.getCanonicalPath()
and Path.normalize()
? What is the difference between Paths.get()
and Path.of()
?
This article answers the following questions:
- What is the difference between a filename, a directory name, and a path?
- How to construct a relative directory or file path independent of the operating system?
- How to construct an absolute directory or file path independent of the operating system?
- What changed with the introduction of the NIO.2 File API?
- What exactly is returned by the
File
methodsgetName()
,getPath()
,getParent()
,getParentFile()
,getAbsolutePath()
,getAbsoluteFile()
,getCanonicalPath()
,getCanonicalFile()
? - What is returned by the
Path
methodsgetFileName()
,getName(int index)
,getParent()
,getRoot()
,toAbsolutePath()
undnormalize()
? - How to join
Path
objects withPath.resolve()
andPath.resolveSibling()
? - When to use
File
and when to usePath
? And can I convert the two into each other?
Basics: Definitions of terms, operating system independence, NIO.2
What is the difference between filename, directory name, relative path, and absolute path?
Before we start, we need to agree on terminology. For example, the terms «path» and «directory» are often confused.
- Filename: the name of a file without a directory and separators, e.g.,
readme.txt
- Directory name: the name of a particular directory without parent directory(s), for example,
apache-maven-3.6.3
orlog
- Path: the «route» to an object of the file system, i.e., to files and directories. A path can be absolute or relative:
- An absolute path is always unique and independent of the current position in the file system.
- A relative path is related to the current position within the file system. It describes how to get from this position to the target. If the target is located in the current directory, the relative path usually equals the file or directory name.
The following table shows some examples of absolute and relative paths to directories and files – for both Windows and Linux/Mac:
Linux / Mac | Windows | |
---|---|---|
Absolute path to a directory: | /var/log |
C:Windows |
Absolute path to a file: | /var/log/syslog |
C:Windowsexplorer.exe |
Relative path to a directory: | ../../var/log
(from |
..Windows
(from |
Relative path to a file: | ../../var/log/syslog
(from |
..Windowsexplorer.exe
(from |
Operating system independent path and directory names
As seen in the table, absolute paths on Windows start with a drive letter and a colon; directories are separated by a backslash (»). On Linux and Mac, absolute paths start with a forward slash (‘/’), which also separates directories.
You can access the separator of the currently used operating system with the constant File.separator
or the method FileSystems.getDefault().getSeparator()
and thus generate pathnames «manually» (i.e. by concatenating strings). For example like this:
Code language: Java (java)
String homePath = System.getProperty("user.home"); String fileName = "test" + System.currentTimeMillis(); String filePath = homePath + File.separator + fileName; System.out.println("filePath = " + filePath);
Depending on the operating system we get a different output:
- Windows:
filePath = C:Userssvenwtest1578950760671
- Linux:
filePath = /home/sven/test1578950836130
With the home directory, this works quite well, but with the temp directory (we get this from the system property «java.io.tmpdir») we get the following output:
- Windows:
filePath = C:UserssvenwAppDataLocalTemp\test1578950862590
- Linux:
filePath = /tmp/test1578950884314
Did you spot the problem?
On Windows, the path for the temporary directory already ends with a backslash. By adding a separator, our code creates a double backslash in the file path.
We could now check if the directory name already ends with a separator and add it only if it is not present. But that is not necessary at all. You can construct file and directory names much more elegantly – completely without string operations, using the classes java.io.File
and (from Java 7) java.nio.file.Path
.
«Old» Java File API vs. NIO.2 File API
In Java 7, the «NIO.2 File API» was introduced with JSR 203 (NIO stands for «New I/O»). This provides a whole new set of classes for handling files (introduced in the previous article about writing and reading files).
Files and directories were previously represented by the class java.io.File
. This leads to confusion, especially for beginners, because the class name suggests that the class only represents files, not directories.
In NIO.2, this task is taken over by the – now appropriately named – class java.nio.file.Path
. Its interface has been completely rewritten compared to java.io.File
.
Constructing file and directory paths with java.io.File
Let’s start with the «old» class, java.io.File
. A file object can represent a filename, a directory name, a relative file or directory path, or an absolute file or directory path (where a file/directory name is actually also a relative file/directory path, relative to the directory in which the file/directory is located).
java.io.file: File and directory names
Representing file names with java.io.File
You can define a filename (without specifying a directory) as follows (we stick to the pattern «test<timestamp>» used above):
Code language: Java (java)
File file = new File("test" + System.currentTimeMillis());
You can now read the following information from the File
object:
Method | Return value |
---|---|
file.getName() |
test1578953190701 |
file.getPath() |
test1578953190701 |
file.getParent() / file.getParentFile() |
null |
file.getAbsolutePath() / file.getAbsoluteFile() |
/happycoders/git/filedemo/test1578953190701 |
The method getName()
returns the filename we passed to the constructor. getPath()
returns the path, which in this case corresponds to the filename since we have not specified a directory. For the same reason, getParent()
and getParentFile()
both return null
, the first method returns a String, the second a corresponding File
object.
Using the methods getAbsolutPath()
and getAbsolutFile()
, you map this file into the current working directory and get the complete path of the file including its directory and filename. These two methods also differ only in that the first returns a String, and the second returns a corresponding File
object.
There are also the methods getCanonicalPath()
and getCanonicalFile()
, which would return the same values as getAbsolutePath()
and getAbsoluteFile()
in this and the following examples. We will see in a later example, in which cases they can contain other values.
Representing directory names with java.io.File
The File
object constructed in the previous section could just as well represent a directory with the same name instead of a file. The methods listed in the table above would return the same results.
A distinction would only be possible if a file or directory with this name already exists. If a corresponding file exists, the method file.isFile()
returns true
. If, on the other hand, a directory with this name exists, the method file.isDirectory()
returns true
. If neither file nor directory exists, both methods return false
. Depending on the further use, the File
object can then be used either to create a directory or to create a file.
java.io.File: Relative file and directory paths
Relative file path with java.io.File
To specify a directory, we can pass it to the File
constructor as a parameter – in the simplest form as a String. With the following code, you put the test file into a tests
directory:
Code language: Java (java)
File file = new File("tests", "test" + System.currentTimeMillis());
The getters now provide the following information about the File
object (with the differences to the previous example highlighted in bold):
Method | Return value |
---|---|
file.getName() |
test1578953190701 |
file.getPath() |
tests/test1578953190701 |
file.getParent() / file.getParentFile() |
tests |
file.getAbsolutePath() / file.getAbsoluteFile() |
/happycoders/git/filedemo/tests/test1578953190701 |
We can now see a difference between getName()
and getPath()
: the first method returns only the file name without the directory information, the second method returns the complete relative path. getParent()
and getParentFile()
(remember: the first method returns a String, the second a corresponding File
object) now return the specified directory tests
. In the absolute path information returned by getAbsolutePath()
and getAbsoluteFile()
(again: String vs. File
), the subdirectory tests
gets inserted accordingly.
The directory can also be passed as a File
object instead of a String:
Code language: Java (java)
File directory = new File("tests"); File file = new File(directory, "test" + System.currentTimeMillis());
Relative file path with nested directories
Several directory levels can also be nested:
Code language: Java (java)
File testsDirectory = new File("tests"); File yearDirectory = new File(testsDirectory, "2020"); File dayDirectory = new File(yearDirectory, "2020-01-13"); File file = new File(dayDirectory, "test" + System.currentTimeMillis());
This allows us to construct directory paths of any depth without having to use the separator character even once. The example constructs a file object with the path tests/2020/2020-01-13/test1578953190701
.
What will the getParent()
method return now? tests/2020/2020-01-13
or just 2020-01-13
? Let’s try it…
Method | Return value |
---|---|
file.getName() |
test1578953190701 |
file.getPath() |
tests/2020/2020-01-13/test1578953190701 |
file.getParent() / file.getParentFile() |
tests/2020/2020-01-13 |
file.getAbsolutePath() / file.getAbsoluteFile() |
/happycoders/git/filedemo/tests/2020/2020-01-13/test1578953190701 |
The parent, therefore, represents the path to the parent directory, not just its name. To access the name of the parent directory we can use file.getParentFile().getName()
.
Relative directory path with java.io.File
Also, in the examples from the previous section, test1578953190701
could be a directory instead of a file. The path does not allow any conclusions to be drawn.
java.io.File: Absolute file and directory paths
Absolute directory path with java.io.File
Attention: We look at absolute paths in reverse order: We first construct the directory path and then the file path, since we cannot generate an absolute file path without an absolute directory path as a parent.
(There is one exception, which we have already seen in the previous examples: We can obtain the absolute file path for a file in the current directory by invoking the File
constructor with only the file name and then calling the method getAbsoluteFile()
/ getAbsolutePath()
on the created File
object.)
We have the following options for constructing an absolute directory path:
- from an absolute directory path represented as a String (therefore dependent on the operating system)
- from the system properties mentioned at the beginning, like «user.home» and «java.io.tmpdir»
- from the current directory
Constructing an absolute directory path from a String
Once we have the absolute directory path in a String (for example, from a configuration file), we can pass it directly to the File
constructor. The following example uses a String constant for simplicity:
Code language: Java (java)
File directory = new File("/var/log/myapp");
For this absolute directory, the File
object’s getters return the following values:
Method | Return value |
---|---|
file.getName() |
myapp |
file.getPath() |
/var/log/myapp |
file.getParent() / file.getParentFile() |
/var/log |
file.getAbsolutePath() / file.getAbsoluteFile() |
/var/log/myapp |
The Methods getPath()
, getAbsolutePath()
and getAbsoluteFile()
now all return the absolute path of the directory. getParent()
and getParentFile()
return the absolute path of the parent directory.
Constructing an absolute directory path from system properties
Through the system properties user.home
and java.io.tmpdir
, you get – independent of the operating system – the user’s home directory and the temporary directory.
The System.getProperty()
method finally returns the path as a String, which we can then pass to the File
constructor. Above, we saw that on Windows, the temporary directory has a trailing backslash, the home directory does not. Does that cause us problems at this point?
We can use the following code to test it on Windows:
Code language: Java (java)
String homeDir = System.getProperty("user.home"); System.out.println("homeDir = " + homeDir); System.out.println("homeDir as File object = " + new File(homeDir)); String tempDir = System.getProperty("java.io.tmpdir"); System.out.println("tempDir = " + tempDir); System.out.println("tempDir as File object = " + new File(tempDir));
The program delivers the following output:
Code language: plaintext (plaintext)
homeDir = C:Userssvenw homeDir as File object = C:Userssvenw tempDir = C:UserssvenwAppDataLocalTemp tempDir as File object = C:UserssvenwAppDataLocalTemp
The unnecessary trailing backslash has been removed, so we don’t have to worry about anything.
Creating an absolute directory path from the current directory
Using what we know so far, we could construct the absolute directory path of the current directory as follows:
Code language: Java (java)
File file = new File("dummy"); File absoluteFile = file.getAbsoluteFile(); File absoluteDirectory = absoluteFile.getParentFile();
Here we have generated a dummy file path, constructed the absolute path for it (which maps the file into the current directory), and then extracted the parent – the absolute path of the directory in which the file is located.
Admittedly, this is rather cumbersome. Fortunately, there is a more elegant way: The current directory can also be read from a system property, user.dir
, and then passed to the File
constructor:
Code language: Java (java)
File currentDir = new File(System.getProperty("user.dir"));
Absolute file path with java.io.File
After having looked at different ways of creating an absolute directory path, we can now construct an absolute file path. All we have to do is pass the directory and filename to the File
constructor.
Code language: Java (java)
File tempDir = new File(System.getProperty("java.io.tmpdir")); File subDir = new File(tempDir, "myapp"); String fileName = "foo"; File file = new File(subDir, fileName);
For this example, the getters of the File
object return the following values:
Method | Return value |
---|---|
file.getName() |
foo |
file.getPath() |
/tmp/myapp/foo |
file.getParent() / file.getParentFile() |
/tmp/myapp |
file.getAbsolutePath() / file.getAbsoluteFile() |
/tmp/myapp/foo |
We see a similar pattern as in the example with the absolute directory path /var/log/myapp
: The methods getPath()
, getAbsolutePath()
and getAbsoluteFile()
return the absolute path of the file. And getParent()
and getParentFile()
return the absolute path of the parent directory.
Attention:
If you create a file object for a file in the current directory, it makes a difference whether you create the object with the current directory and filename or just the filename. The methods getAbsoluteFile()
/ getAbsolutePath()
return the absolute file path in both cases. However, getPath()
returns the absolute path only in the first case; whereas in the second case it returns only the filename. And getParent()
and getParentFile()
only return the parent directory in the first case, but null
in the second case.
java.io.file: Overview of File’s getter methods
The following table summarizes what File
‘s getters return depending on the file system object represented:
Method | File/directory name | Relative file/directory path | Absolute file/directory path | ||
---|---|---|---|---|---|
getName() |
File/directory name | File/directory name | File/directory name | ||
getPath() |
File/directory name | Relative file/directory path | Absolute file/directory path | ||
getParent() / getParentFile() |
null |
Relative path to parent directory | Absolute path to parent directory | ||
getAbsolutePath() / getAbsoluteFile() |
Absolute path from combination of current directory and file/directory name | Absolute path from combination of current directory and relative file/directory path | Absolute file/directory path |
Once again as a reminder: getParent()
and getAbsolutePath()
return a String; getParentFile()
and getAbsoluteFile()
return a corresponding File
object.
java.io.file: What is the difference between getCanonicalPath() / getCanonicalFile() and getAbsolutePath() / getAbsolutePath()?
In all previous examples, the methods getCanonicalPath()
and getCanonicalFile()
would have returned the same result as getAbsolutePath()
and getAbsoluteFile()
– namely the respective absolute path (as String or File
object).
So what is the difference?
A «canonical path» is unique; i.e., there is only one such path to a file. In contrast, there can be more than one absolute path to the same file. An example:
For the file /var/log/syslog
, this String is also the «canonical path». The same String is also an absolute path. However, there are other absolute paths, such as
/var/log/./syslog
,/var/log/../log/syslog
,/home/user/../../var/log/syslog
,- as well as all paths that eventually point to
/var/log/syslog
via symbolic links.
Constructing file and directory paths with java.nio.file.Path and Paths
Although the interface of java.nio.file.Path
has been completely changed from java.io.File
, the underlying concepts have remained unchanged. Filenames, directory names, relative file and directory paths, and absolute file and directory paths are still the file system objects being represented.
What was changed? In the following sections, you see how to construct Path
objects, using the same structure and the same examples as with the File
objects before.
In the following sections, I will not make a distinction between file and directory names. We have already seen above that, as long as the corresponding file system object does not exist, its path does not indicate whether it is a file or a directory.
java.nio.file.Path: File and directory names
Instead of a constructor, we use a factory method for java.nio.file.Path
to create instances. The factory method was originally located in the class java.nio.file.Paths
(with «s» at the end), but in Java 11, it was also directly included in the Path
class. We create a Path
object for the file name «test<timestamp>» as follows:
Code language: Java (java)
Path path = Paths.get("test" + System.currentTimeMillis());
Starting with Java 11, you can use Path.of()
instead of Paths.get()
. There is practically no difference. Internally, Paths.get()
calls the newer method Path.of()
and this in turn calls FileSystems.getDefault().getPath()
.
Code language: Java (java)
Path path = Path.of("test" + System.currentTimeMillis());
The following methods provide information analogous to methods of the File
class shown above:
Method | Return value |
---|---|
path.getFileName() |
test1579037366379 |
path.getNameCount() |
1 |
path.getName(0) |
test1579037366379 |
path.getParent() |
null |
path.getRoot() |
null |
path.toAbsolutePath() |
/happycoders/git/filedemo/test1579037366379 |
path.normalize() |
test1579037366379 |
First of all: All methods shown – except for getNameCount()
– return a Path
object. There are no variants of these methods that return a String. The only way to convert a Path
object into a String is to call its toString()
method.
The getFileName()
method returns the name of the file or directory. getNameCount()
is always 1 for a filename without directory information, or for directories without a parent directory. And the first name, retrievable by getName(0)
, is also the file/directory name. getParent()
returns – like File
‘s method with the same name – null
. The method getRoot()
also returns null
, since a single filename is always relative. With toAbsolutePath()
we map – analogous to File.getAbsolutePath()
– the file/directory into the current directory and get the corresponding absolute path.
Path.normalize()
is similar to File.getCanonicalPath()
with the difference that when normalizing a path, relative paths remain relative, while getCanonicalPath()
always generates an absolute path for both absolute and relative File
objects.
java.nio.file.Path: Relative file and directory paths
To include directories, Path
offers two different approaches:
- You can list all directories in the factory method
Paths.get()
orPath.of()
. - You can use its
resolve()
method to convert an existingPath
object into a newPath
object, where theresolve()
method is equivalent to changing the directory with the Windows or Linuxcd
command.
Constructing relative file and directory paths with Paths.get() / Path.of()
You can pass any number of directory names to the factory methods. For example, you would construct the relative path tests/test1578953190701
as follows (the timestamp is hard-coded for simplicity):
Code language: Java (java)
Path path = Paths.get("tests", "test1578953190701");
This Path
object’s getters return the following results (I highlighted the differences to the individual file names in bold again):
Method | Return value |
---|---|
path.getFileName() |
test1578953190701 |
path.getNameCount() |
2 |
path.getName(0) |
tests |
path.getName(1) |
test1578953190701 |
path.getParent() |
tests |
path.getRoot() |
null |
path.toAbsolutePath() |
/happycoders/git/filedemo/tests/test1578953190701 |
path.normalize() |
tests/test1578953190701 |
Due to the directory, nameCount
has increased from 1 to 2. In the name
array, the directory name was inserted at position 0; the file name has moved to position 1. getParent()
also returns the directory name. The absolute path and the normalized version also contain the directory name.
Constructing nested file and directory paths with Paths.get() / Path.of()
If the file is to be located in the directory tests/2020/2020-01-13
, call the factory method as follows:
Code language: Java (java)
Path path = Paths.get("tests", "2020", "2020-01-13", "test1578953190701");
Here once again, the getters’ results:
Method | Return value |
---|---|
path.getFileName() |
test1578953190701 |
path.getNameCount() |
4 |
path.getName(0) |
tests |
path.getName(1) |
2020 |
path.getName(2) |
2020-01-13 |
path.getName(3) |
test1578953190701 |
path.getParent() |
tests/2020/2020-01-13 |
path.getRoot() |
null |
path.toAbsolutePath() |
/happycoders/git/filedemo/tests/2020/2020-01-13/test1578953190701 |
path.normalize() |
tests/2020/2020-01-13/test1578953190701 |
nameCount
has been increased accordingly, and the name
array contains all directories of the path as well as the filename. Again, getParent()
returns the complete known path to the directory, not just its name.
Constructing relative file and directory paths with Path.resolve()
An alternative way to construct the Path
object for the path tests/2020/2020-01-13/test1578953190701
is to use the resolve()
method. It combines the path on which the method is called with the path passed to it:
Code language: GLSL (glsl)
Path testsDir = Paths.get("tests"); Path yearDir = testsDir.resolve("2020"); Path dayDir = yearDir.resolve("2020-01-13"); Path path = dayDir.resolve("test1578953190701");
The resolve()
operation is associative, i.e., the individual parts can also be joined in a different order, for example like this:
Code language: Java (java)
Path testsDir = Paths.get("tests"); // tests Path yearDir = testsDir.resolve("2020"); // tests/2020 Path dayDir = Paths.get("2020-01-13"); // 2020-01-13 // 2020-01-13/test1578953190701 Path fileInDayDir = dayDir.resolve("test1578953190701"); // tests/2020/2020-01-13/test1578953190701 Path path = yearDir.resolve(fileInDayDir);
Shortcut: Path.resolveSibling()
Let’s assume we have the Path
object we constructed in the previous section, and we want to create another file in the same directory. If we still have access to the Path
object representing the directory, we can call resolve()
on it with the new filename. Otherwise, we could access the directory with getParent()
and then call resolve()
:
Code language: Java (java)
Path sibling = path.getParent().resolve("test" + System.currentTimeMillis());
Exactly for this purpose, there is the shortcut resolveSibling()
, which saves you five keystrokes and bytes:
Code language: Java (java)
Path sibling = path.resolveSibling("test" + System.currentTimeMillis());
java.nio.file.Path: Absolute file and directory paths
Similar to java.io.File
, we can also create an absolute path with java.nio.file.Path
from a String that we read from a configuration file or a system property. We can pass this path, as it is, to the factory method. We do not need to split it up first. Using the directory /var/log/myapp
as an example again:
Code language: Java (java)
Path path = Paths.get("/var/log/myapp");
Of course, we can also modify an absolute path using the resolve()
method. The following example corresponds to the example of the absolute file path with java.io.File
:
Code language: Java (java)
Path tempDir = Path.of(System.getProperty("java.io.tmpdir")); Path subDir = tempDir.resolve("myapp"); String fileName = "foo"; Path file = subDir.resolve(fileName);
For this absolute path, the getter methods return:
Method | Return value |
---|---|
path.getFileName() |
foo |
path.getNameCount() |
3 |
path.getName(0) |
tmp |
path.getName(1) |
myapp |
path.getName(2) |
foo |
path.getParent() |
/tmp/myapp |
path.getRoot() |
/ |
path.toAbsolutePath() |
/tmp/myapp/foo |
path.normalize() |
/tmp/myapp/foo |
Here we experience for the first time that path.getRoot()
does not return null, but "/", the Linux root directory. On Windows,
we would get «C:» here (unless the temporary directory is in a different file system). The root directory is not part of the name
array.
java.nio.file.Path: Overview of its getter methods
Here you can see a summary of what Path
‘s getters return:
Method | File/directory name | Relative file/directory path | Absolute file/directory path |
---|---|---|---|
path.getFileName() |
File/directory name | File/directory name | File/directory name |
path.getNameCount() |
1 |
Number of directories + file | Number of directories + file |
path.getName(index) |
File/directory name | File/directory names at the given position (0-based) | File/directory names at the given position (0-based, root does not count) |
path.getParent() |
null |
Relative path to parent directory | Absolute path to parent directory |
path.getRoot() |
null |
null |
The file system’s root, such as «/» or «C:» |
path.toAbsolutePath() |
Absolute path from combination of current directory and file/directory name | Absolute path from combination of current directory and file/directory name | Absolute file/directory path |
path.normalize() |
Normalized file/directory name | Normalized relative file/directory name | Normalized absolute file/directory name |
Summary and outlook
This article gave a detailed overview of how to construct file and directory paths independent of the operating system using the classes File
, Path
, and Paths
.
My recommendation is to use only the NIO.2 classes Path
and Paths
from Java 7 on, and from Java 11 on, use only Path
. If you need a File
object for a particular file operation, you can always create one with Path.toFile()
.
The following parts of the series will deal with the following topics:
- Directory operations, such as reading the file list of a directory
- Copying, moving, and deleting files
- Creating temporary files
- Read and write structured data with
DataOutputStream
andDataInputStream
In the later course we come to advanced topics:
- NIO channels and buffers introduced in Java 1.4, to speed up working with large files
- Memory-mapped I/O for blazing-fast file access without streams
- File locking, to access the same files in parallel – i.e., from several threads or processes – without conflicts
Do you have any questions, suggestions, ideas for improvement? Then I would be pleased with a comment. Do you know others who find the topic interesting? Then I would be happy if you share the article by using one of the buttons below. Would you like to be informed when the next part appears? Then click here to sign up for the HappyCoders newsletter.