Рекурсивное чтение файлов в каталогах и добавление имен файлов в ListView приводит к появлению вопросительных знаков.JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Рекурсивное чтение файлов в каталогах и добавление имен файлов в ListView приводит к появлению вопросительных знаков.

Сообщение Anonymous »

После исследования я обнаружил, что наиболее эффективный способ чтения каталога и файлов его подкаталогов — использование метода Files.walk().

Код: Выделить всё

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;
}
К сожалению, в консоли IntelliJ для любых символов кириллицы выводит ????, а в JavaFX ListView я получаю ����� .
Метод 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() возвращает поток (путь), который Я предполагаю, что это делается через однобайтовый поток (признаюсь, я немного потерялся в документации), потому что, согласно комментарию Теда Хоппа в разделе «Поток байтов против потока символов в 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
@Basil Bourque

Что такое «VLC», о котором вы упомянули ?

Я имел в виду VLC Media Player.
@Basil Bourque< /p>

Какая файловая система? Какая операционная система хоста?

Я использую 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());

}
});
Приведенный выше код успешно добавляет /home/user/music/Kingsize - Оставам себе си.mp3 в ListView.
Но если я попытаюсь получить список всех файлов в каталоге с помощью 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");

}
});
@g00se

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);
В моем файле style.css я загрузил его через:

Код: Выделить всё

.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();
}
}
MainController.java

Код: Выделить всё

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"));

} catch (IOException exception) {
exception.printStackTrace();
}
}
}
init-test.fxml Я также наткнулся на этот пост (Как поддерживать кириллицу в Eclipse?).
В нем объясняется, что символ � не работает. не имеет ничего общего с кодировкой, но шрифт не имеет необходимых глифов для поддержки кириллицы, как упоминал Базиль Бурк, что странно, поскольку приведенные выше эксперименты привели к успеху при выборе вручную файлы.
Я буду продолжать обновлять информацию по мере изучения.

Подробнее здесь: https://stackoverflow.com/questions/792 ... a-listview
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»