#java #deserialization
#java #десериализация
Вопрос:
У меня есть моя программа в файле JAR, а некоторые файлы в папке в том же каталоге. После нескольких часов поиска я нашел некоторый код, который позволил мне перечислить файлы внутри этой папки (поскольку File.listFiles()
не работал), но теперь readObject()
выдает мне IOException
. Он отлично работает, когда я запускаю его из IDE или с помощью cmd. Он выдает исключение только при запуске JAR с помощью двойного щелчка.
Вот что я делаю:
public static Template[] loadTemplates() throws IOException, ClassNotFoundException {
Path dirtemp = Paths.get(path.toString(), TEMPLATE_PATH);
DirectoryStream<Path> dirStream = Files.newDirectoryStream(dirtemp);
ArrayList<File> files = new ArrayList<>();
for (Path entry: dirStream) {
files.add(entry.toFile());
}
if (files.size() != 0) {
ArrayList<Template> templates = new ArrayList<>();
for (File file: files) {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject();
if (object instanceof Template) {
templates.add((Template) object);
}
ois.close();
fis.close();
}
Collections.sort(templates);
return templates.toArray(new Template[0]);
} else return null;
}
TEMPLATE_PATH
это просто строка, содержащая имя папки с файлами.
path
это статическая переменная внутри моего класса, которая содержит текущий путь к JAR. Я инициализирую его из метода main, поскольку местоположение не предназначено для изменения. Вот код, который я использовал для его получения, если это уместно:
public static void findJARPath() {
final Class<?> referenceClass = Main.class;
final URL url =
referenceClass.getProtectionDomain().getCodeSource().getLocation();
try {
final File jarPath = new File(url.toURI()).getParentFile();
path = Paths.get(jarPath.toURI());
} catch(final URISyntaxException ignored){}
}
Кто-нибудь знает, почему это происходит?
Я работаю в Windows, но я хочу, чтобы это работало и на других ОС. Я был бы признателен, если бы вы указали, не является ли какой-либо из этого кода переносимым.
Редактировать: трассировка стека исключения:
javax.swing.ImageIcon local class incompatible: stream class desc serialVersionUID = -962022720109015502, local class serialVersionUID = 532615968316031794
java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2355)
java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2249)
java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2087)
java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
Data.FileManager.loadTemplates(FileManager.java:108)
Код, который записывает файлы:
public static void saveTemplate(Template template) {
new File(TEMPLATE_PATH).mkdir();
String filename = StringUtils.toFilename(template.getName(), "templ");
try {
FileOutputStream fos = new FileOutputStream(TEMPLATE_PATH filename);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(template);
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Редактировать: понял это. По-видимому, по какой-либо причине UID ImageIcon из изображения в моем классе шаблонов не будет совпадать при запуске jar с помощью двойного щелчка. Перенос изображения в другой класс с фиксированным идентификатором UID решил проблему.
Комментарии:
1. Почему что происходит? Что
IOException
?2. @MarquisofLorne javax.swing. ImageIcon; локальный класс несовместим.
3. Неадекватно. Опубликуйте все исключение и его трассировку стека в вашем вопросе. Также код, который записал файл. Но вы, похоже, полностью проигнорировали предупреждение в Javadoc для этого класса о его сериализации.
4. @MarquisofLorne Я только что опубликовал трассировку стека и код записи файла.
5. Это именно то, что я сказал. Вы проигнорировали предупреждение и делаете то, что в нем сказано не делать: сериализуете класс Swing с одной версией Java и десериализуете его с другой. Решение: не делайте этого.
Ответ №1:
Конечно, ваш план терпит неудачу: «Тот же каталог, что и мой jar-файл», очевидно, будет содержать ….. ваш jar-файл.
Который приведет к сбою, если вы попытаетесь прочитать его с помощью OIS. Примените некоторую фильтрацию при перемещении по этому каталогу. Имеет ли оно правильное расширение? Это фактический файл (или каталог)?
Кроме того, в вашем коде есть утечка памяти; dirstreams — это ресурсы, как и a FileInputStream
. Вы должны закрыть их. Единственный безопасный способ сделать это — попробовать / finally или попробовать с помощью ресурсов. Найдите в Интернете «Java try with resources», если вы не знакомы с этими методами.
Комментарии:
1. Все верно, но попытка десериализации файла JAR приведет к
new ObjectInputStream
, а неreadObject()
. Я подозреваю, что это то, что происходит на самом деле.2. Я не знаю, правильно ли я это понимаю, но я не десериализирую jar, у меня есть родительская папка, содержащая как jar, так и файловую папку. То, что я пытаюсь десериализовать, — это содержимое файловой папки, и оно срабатывает при cmd, если я перехожу в родительскую папку и запускаю jar оттуда.
Ответ №2:
Вы сохранили JDK11 ImageIcon и пытаетесь десериализовать его обратно на виртуальной машине, у которой этого нет, потому что у нее есть JDK14 ImageIcon или что-то еще.
В более общем плане, вы не можете ничего сериализовать, если цель состоит в том, чтобы разрешить его десериализацию в другой системе, если им не очень тщательно управляют. ImageIcon по намерению не управляется таким образом, поэтому вы не можете сохранять ImageIcons с OIS и OOS. Похоже, что вы можете, но есть нюанс: разрывы на разных виртуальных машинах.
Вы должны выбросить весь этот код и подумать о другом способе сериализации объектов ImageIcon. Возможно, сохраните необработанные пиксели, сохраните их в формате PNG и т. Д.