Код: Выделить всё
private void selectPrimaryFolder(ResourceBundle resourceBundle, ListView lvFileList) {
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle(resourceBundle.getString("selectPrimaryFolder"));
File selectedDirectory = chooser.showDialog((Stage) btnSelectPrimaryFolder.getScene().getWindow());
System.out.println("SELECTED DIRECTORY: " + selectedDirectory.toPath());
// TODO
try (Stream
stream = Files.walk(selectedDirectory.toPath()).sorted()) {
stream.forEach(path -> addFileToList(path.toFile(), lvFileList));
} catch (IOException ioException) {
ioException.getMessage();
}
/*System.out.println(listFileTree(selectedDirectory));
for (File f: listFileTree(selectedDirectory)){
lvFileList.getItems().add(f.getName());
}*/
}
private static void addFileToList(File file, ListView lvFileList) {
if (file.isDirectory()) {
System.out.println("Directory: " + file.getAbsolutePath());
} else {
System.out.println("File: " + file.getAbsolutePath());
lvFileList.getItems().add(file.getName());
}
}
public static Collection listFileTree(File dir) {
Set fileTree = new HashSet();
if(dir==null||dir.listFiles()==null){
return fileTree;
}
for (File entry : dir.listFiles()) {
if (entry.isFile()) fileTree.add(entry);
else fileTree.addAll(listFileTree(entry));
}
return fileTree;
}
Метод listFileTree(), который я нашел здесь (рекурсивный список файлов в Java), — это еще один способ, которым я пытался получить список файлов, но как ни странно, он игнорирует файлы которые содержат любые символы кириллицы.
Согласно сообщению здесь (оба File.isFile() и File.isDirectory() возвращают false), isFile() может иметь проблема с кодировкой.
Кодировка
Судя по тому, что я нашел, это может быть проблема с кодировкой.
Я проверил свой Настройки кодировки файлов IntelliJ, и все они настроены на UTF-8 (он также настроен на создание файлов UTF-8 без спецификации), включая кодировку консоли по умолчанию.
Я установил оба из них в VMOptions:
Код: Выделить всё
-Dconsole.encoding=UTF-8
-Dfile.encoding=UTF-8
Я столкнулся с чем-то интересным: если я использую FileChooser и выбираю один файл, символы правильно отображаются в ListView (хотя в консоли они по-прежнему отображаются в виде вопросительных знаков).
Согласно документации, File.walk() возвращает поток (путь), который Я предполагаю, что это сделано через однобайтовый поток [См. EDIT 4] (признаюсь, я немного заблудился в документацию), потому что, согласно комментарию Теда Хоппа в статье «Поток байтов против потока символов в Java», он должен иметь возможность читать кириллицу, если это был «поток символов» (при условии, что исходный файл закодирован в UTF-8, или конечно).
...Чтобы проверить это, попробуйте файл, содержащий что-то, для представления которого требуется
более одного байта (например, греческий , кириллицы или арабских
символов). С байт-ориентированным потоком это не сработает. В
потоке, ориентированном на символы, символы будут сохраняться до тех пор, пока
оба потока используют кодировки, поддерживающие эти символы
(например, UTF-8), и входной файл был сохранен. в кодировке, используемой для
входящего потока...
Выяснение исходной кодировки файла
Я подумал, что просто поищу способ обнаружить кодировку и установил условие, но после прочтения многих, многих, многих ответов выяснилось, что это невозможно сделать. Лучший вариант — попытаться «угадать». Что я и сделал.
Используя новую строку (bytes, charset)/String.getBytes(), упомянутую в разделе «Преобразование кодировки в Java», я протестировал наиболее распространенные из них, как показано ниже. вопрос (Какова наиболее распространенная кодировка каждого языка?), через File.walk().
НИ ОДИН ИЗ НИХ НЕ РАБОТАЕТ! Каждый один из них привел к появлению вопросительных знаков в консоли и в ListView.
Я думал, что в моих файлах могут быть ошибки, но у VLC, похоже, нет проблем с кодированием. Весь текст представлен так, как должен.
Вопрос
Как мне это сделать? Существует ли рекурсивный поток символов, альтернативный File.walk()? Я что-то еще пропустил?
P.S. Я не пробовал никаких нерекурсивных решений, поскольку рекурсия является обязательным требованием.
P.S. 2. Я также пробовал те, которые упомянуты в io-recurse-tests, но, увы, ничего.
EDIT 1 – Дополнительная информация@Basil Bourque
Опубликуйте пример имени файла с проблемными кириллическими символами.
Примеры названий файлов на кириллице:
Код: Выделить всё
Ъпсурт - Колега.mp3Код: Выделить всё
Kingsize - Оставам себе си.mp3Что такое «VLC», о котором вы упомянули ?
Я имел в виду VLC Media Player.
@Basil Bourque < strong>@g00se
Какая файловая система? Какая операционная система хоста?
Я использую Fedora, которая использует Btrfs: файловую систему b-дерева с UTF-8 в качестве системной кодировки по умолчанию.
@g00se
Не совсем понимаю, почему а) вы смешиваете Path с File (возможно, из-за ваших положительных результатов с FileChooser или что-то?)...
Код: Выделить всё
ListView lvPrimaryList = new ListView();
Button btn = new Button("Select file");
btn.setOnMouseClicked(new EventHandler() {
@Override
public void handle(MouseEvent mouseEvent) {
FileChooser chooser = new FileChooser();
chooser.setTitle(resourceBundle.getString("selectPrimaryFolder"));
File selectedFile = chooser.showOpenDialog((Stage) btn.getScene().getWindow());
System.out.println("SELECTED FILE: " + selectedFile.getAbsolutePath());
lvPrimaryList.getItems().add(selectedFile.getAbsolutePath());
}
});
Но если я попытаюсь получить список всех файлов в каталоге с помощью File.walk(), упомянутого выше, в итоге получится /home/user/music/Kingsize - ����� �� ���� ��.mp3.
@g00se
... б) почему вы думаете, что рекурсия/нерекурсия имеет какое-то отношение к этому...
Я упомянул рекурсию на случай, если есть решения, которые работают, но получают только список файлов в текущем каталоге, и мне нужно иметь возможность получить любые возможные файлы в любом подкаталоги.
@jewelsea
Создайте приложение с меткой, которая отображает жестко запрограммированный текст одного из > имен проблемных файлов: новая сцена(новая метка("текст проблемы")). Это > все, что нужно сделать. Ничего больше. Текст отображается правильно?
Использование метки работает.
Код: Выделить всё
ListView lvPrimaryList = new ListView();
Button btn = new Button("Select file");
btn.setOnMouseClicked(new EventHandler() {
@Override
public void handle(MouseEvent mouseEvent) {
lvPrimaryList.getItems().add(new Label("Ъпсурт - Колега.mp3"));
}
});
Код: Выделить всё
ListView lvPrimaryList = new ListView();
Button btn = new Button("Select file");
btn.setOnMouseClicked(new EventHandler() {
@Override
public void handle(MouseEvent mouseEvent) {
lvPrimaryList.getItems().add("Ъпсурт - Колега.mp3");
}
});
new Scene(new Label("\u041E\u0434\ u0438\u043D"));
Код: Выделить всё
ListView lvPrimaryList = new ListView();
Button btn = new Button("Select file");
btn.setOnMouseClicked(new EventHandler() {
@Override
public void handle(MouseEvent mouseEvent) {
lvPrimaryList.getItems().add(new Label("\u041E\u0434\u0438\u043D"));
}
});
@Basil Bourque
Вы можете необходимо указать шрифт, в котором есть глифы для
нужных символов. Другие вопросы указывают на то, что JavaFX не может
правильно просмотреть шрифты и найти шрифт с необходимыми глифами.
Я использую шрифт IBM Plex Sans .
В моем файле Main.java я добавил это следующим образом:
Код: Выделить всё
Font.loadFont(Objects.requireNonNull(getClass().getResource("fonts/IBMPlexSans-Light.ttf")).toExternalForm(), 14);
Font.loadFont(Objects.requireNonNull(getClass().getResource("fonts/IBMPlexSans-Medium.ttf")).toExternalForm(), 14);
Font.loadFont(Objects.requireNonNull(getClass().getResource("fonts/IBMPlexSans-Regular.ttf")).toExternalForm(), 14);
Font.loadFont(Objects.requireNonNull(getClass().getResource("fonts/IBMPlexSans-SemiBold.ttf")).toExternalForm(), 14);
Код: Выделить всё
.root {
-fx-font-family: "IBM Plex Sans";
}
Я удалил ее. , на всякий случай, но я все равно получаю ����� в ListView при использовании File.walk().
РЕДАКТИРОВАТЬ 2 – Дальнейшее тестирование
Использование FileChooser и выбор нескольких файлов дают желаемые результаты в ListView, но в коде отсутствует рекурсия.
Код: Выделить всё
ListView lvPrimaryList = new ListView();
Button btn = new Button("Select file");
btn.setOnMouseClicked(new EventHandler() {
@Override
public void handle(MouseEvent mouseEvent) {
FileChooser chooser = new FileChooser();
chooser.setTitle("Select files");
List selectedFiles = chooser.showOpenMultipleDialog((Stage) btn.getScene().getWindow());
for (File file : selectedFiles) {
System.out.println("SELECTED FILE: " + file.getAbsolutePath());
lvPrimaryList.getItems().add(file.getAbsolutePath());
}
}
});
РЕДАКТИРОВАТЬ 3 – Минимальный воспроизводимый пример >
В процессе создания полноценного MRE я столкнулся с проблемой, из-за которой после самостоятельного создания файлов все их имена были: ?????? - ??????.mp3

Main.java
Код: Выделить всё
public class Main extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("main.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 800, 600);
scene.getStylesheets().add(getClass().getResource("style/style.css").toExternalForm());
stage.setTitle("My Program");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Код: Выделить всё
public class MainController implements Initializable {
@FXML
private ListView lvPrimaryList;
@FXML
private Button btnSelectFile;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// Select primary list
btnSelectFile.setOnMouseClicked(new EventHandler() {
@Override
public void handle(MouseEvent mouseEvent) {
initTest();
}
});
}
private void initTest() {
System.out.println(java.nio.charset.Charset.defaultCharset());
// Edit these to match your operating system
String osDelimiter = "/";
String rootString = "/home/user/Documents/init-test" + osDelimiter;
Path rootPath = Paths.get(rootString);
try {
Files.createDirectory(rootPath);
File songOne = new File(rootString + "Ъпсурт - Колега.mp3");
songOne.createNewFile();
File songTwo = new File(rootString + "Kingsize - Оставам себе си.mp3");
songTwo.createNewFile();
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Ъпсурт - Колега.mp3"), true, StandardCharsets.UTF_8));
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Kingsize - Оставам себе си.mp3"), true, StandardCharsets.UTF_8));
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Ъпсурт - Колега.mp3"), true, "Cp1252"));
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Kingsize - Оставам себе си.mp3"), true, "Cp1252"));
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Ъпсурт - Колега.mp3"), true, "windows-1251"));
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Kingsize - Оставам себе си.mp3"), true, "windows-1251"));
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Ъпсурт - Колега.mp3"), true, "UTF-16"));
//System.setOut(new PrintStream(new FileOutputStream(rootString + "Kingsize - Оставам себе си.mp3"), true, "UTF-16"));
//Writer writerOne = new OutputStreamWriter(new FileOutputStream(rootString + "Ъпсурт - Колега.mp3"));
//writerOne.close();
//Writer writerTwo = new OutputStreamWriter(new FileOutputStream(rootString + "Kingsize - Оставам себе си.mp3"));
//writerTwo.close();
//Writer writerOne = new OutputStreamWriter(new FileOutputStream(rootString + "Ъпсурт - Колега.mp3"), StandardCharsets.UTF_8);
//writerOne.close();
//Writer writerTwo = new OutputStreamWriter(new FileOutputStream(rootString + "Kingsize - Оставам себе си.mp3"), StandardCharsets.UTF_8);
//writerTwo.close();
//Writer writerOne = new OutputStreamWriter(new FileOutputStream(rootString + "Ъпсурт - Колега.mp3"), StandardCharsets.UTF_16);
//writerOne.close();
//Writer writerTwo = new OutputStreamWriter(new FileOutputStream(rootString + "Kingsize - Оставам себе си.mp3"), StandardCharsets.UTF_16);
//writerTwo.close();
try (Stream
stream = Files.walk(rootPath.toFile().toPath()).sorted()) {
stream.forEach(path -> addFileToList(path.toFile(), lvPrimaryList));
} catch (IOException ioException) {
ioException.getMessage();
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
Код: Выделить всё
[*]
В нем объясняется, что символ � не работает. не имеет ничего общего с кодировкой, но шрифт не имеет необходимых глифов для поддержки кириллицы, как упоминал Базиль Бурк, что странно, поскольку приведенные выше эксперименты привели к успеху при выборе вручную файлы.
Я буду продолжать обновлять информацию по мере продолжения расследования.
РЕДАКТИРОВАНИЕ 4 — Исходный код
Копать через исходный код Java/JavaFX на Github я нашел следующее:
- FileChooser — использует список
- Файл — использует нормализованный путь. String.
- Files — использует входной поток Path
- Path — использует URI
- URI — это строка
Однако одна и та же строка интерпретируется по-разному.
Подробнее здесь: https://stackoverflow.com/questions/792 ... a-listview
Мобильная версия