#java
#java
Вопрос:
Я создаю установщик, и есть некоторые файлы ресурсов (.xmls, .zip-файлы, файл .jar и т.д.), Которые необходимо прочитать во время установки, Но я хотел бы упаковать их в пользовательский файл (т. Е. файл .dat), чтобы при распространении пользователям не приходилось с ними слишком много возиться. Проблема в том, что установщик должен быть написан на Java, а я никогда раньше не делал ничего подобного ни на одном языке программирования. Возможно ли это вообще? Если да, то как я могу упаковать его таким образом, чтобы впоследствии мое Java-приложение могло его прочитать, и как я могу заставить свое Java-приложение его прочитать?
Ответ №1:
Существует множество вопросов, на которые вам нужно будет ответить для себя относительно требований этого типа файла. Нужно ли его сжимать? Зашифрован? Нужно ли поддерживать чтение с произвольным доступом, или чтение с потоком достаточно хорошее?
Я могу ошибаться, но я не думаю, что это то, что вы задаете в этом вопросе. Если я вас правильно понял, я думаю, вы спрашиваете «как мне читать и записывать данные произвольного файла?»
Итак, на этот вопрос я отвечу. Обновите свой вопрос, если это не совсем то, что вы ищете.
Пользовательские типы файлов могут быть легко реализованы с использованием классов DataInputStream и DataOutputStream. Это позволит вам читать и записывать примитивы (boolean, char, byte, int, long, float, double) в поток. Существует также несколько удобных методов для чтения и записи строк в кодировке UTF-8, байтовых массивов и нескольких других полезных функций.
Давайте начнем.
В качестве аргумента давайте представим, что все мои элементы данных представляют собой массивы байтов. И у каждого из них есть имя. Таким образом, мой тип файла может быть логически смоделирован как Map<String, byte[]>
. Я бы реализовал свой пользовательский класс чтения / записи типов файлов следующим образом:
public class MyFileTypeCodec {
public static void writeToFile(File f, Map<String, byte[]> map)
throws IOException {
// Create an output stream
DataOutputStream stream = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(f))
);
// Delegate writing to the stream to a separate method
writeToStream(stream, map);
// Always be sure to flush amp; close the stream.
stream.flush();
stream.close();
}
public static Map<String, byte[]> readFromFile(File f)
throws IOException {
// Create an input stream
DataInputStream stream = new DataInputStream(
new BufferedInputStream(new FileInputStream(f))
);
// Delegate reading from the stream to a separate method
Map<String, byte[]> map = readFromStream(stream);
// Always be sure to close the stream.
stream.close();
return map;
}
public static void writeToStream(DataOutputStream stream, Map<String, byte[]> map)
throws IOException {
// First, write the number of entries in the map.
stream.writeInt(map.size());
// Next, iterate through all the entries in the map
for (Map.Entry<String, byte[]> entry : map.entrySet()) {
// Write the name of this piece of data.
stream.writeUTF(entry.getKey());
// Write the data represented by this name, making sure to
// prefix the data with an integer representing its length.
byte[] data = entry.getValue();
stream.writeInt(data.length);
stream.write(data);
}
}
public static Map<String, byte[]> readFromStream(DataInputStream stream)
throws IOException {
// Create the data structure to contain the data from my custom file
Map<String, byte[]> map = new HashMap<String, byte[]>();
// Read the number of entries in this file
int entryCount = stream.readInt();
// Iterate through all the entries in the file, and add them to the map
for (int i = 0; i < entryCount; i ) {
// Read the name of this entry
String name = stream.readUTF();
// Read the data associated with this name, remembering that the
// data has an integer prefix representing the array length.
int dataLength = stream.readInt();
byte[] data = new byte[dataLength];
stream.read(data, 0, dataLength);
// Add this entry to the map
map.put(name, data);
}
return map;
}
}
Основная идея заключается в том, что вы можете записать любые данные в выходной поток (и прочитать их снова), если вы можете представить эти данные в виде некоторой комбинации примитивов. Массивы (или другие коллекции) могут иметь префикс с указанием их длины, как я сделал здесь. Или вы можете избежать записи префикса длины, если поставите в конце указатель TERMINUS (что-то вроде строк с нулевым завершением).
Я всегда использую такого рода настройки при реализации пользовательского кодека filetype, при этом методы ввода-вывода файлов делегируются потоковым методам ввода-вывода. Обычно позже я обнаруживаю, что объект, который я считываю и записываю из этого потока, может быть так же легко записан в какой-нибудь более крупный и сложный файл.
Таким образом, у меня может быть SuperFancyCodec
для чтения / записи данных для всей моей системы, и это вызывает мой TinySpecialPurposeCodec
. Пока методы чтения и записи потока являются общедоступными, я могу собирать новые типы файлов, используя методологию, ориентированную на компоненты.
Ответ №2:
Расширение обычно имеет очень мало общего с тем, как интерпретируется файл.
Если вы хотите иметь просто config.dat
вместо config.xml
, просто переименуйте файл. (Обычно вы предоставляете xml-анализатору InputStream
или a Reader
в качестве входных данных, который может считывать любой файл, независимо от расширения)
Если проблема, которую вы описываете, связана с объединением нескольких файлов (.zip, .jar и т.д.) В один файл .dat, вы могли бы, например, сжать их вместе и назвать zip-файл расширением .dat. Java имеет хорошую поддержку zip-файлов и может обрабатывать zip-файл независимо от имени файла / расширения.
- Ссылка по теме: Чтение содержимого ZIP-файла
Комментарии:
1. «Расширение обычно имеет очень мало общего с тем, как интерпретируется файл». Это все, что я знаю. Но хороший указатель о том, как их архивировать, переименовывать и использовать Java API для обработки этого. Я не эксперт по Java, но я изучу это, спасибо.
2. Я последовал вашим первоначальным мыслям, за исключением того, что я извлек содержимое файла .dat в системную временную папку и получил оттуда нужные мне файлы. Сработало чудесно, спасибо!
Ответ №3:
При создании / чтении файлов на Java (или любом другом языке) расширение файла не привязано строго к фактической структуре данных файла. Если бы я хотел, я мог бы создать XML-файлы file.gweebz
. Операционные системы и приложения не будут знать, что с ним делать, но после открытия будет ясно, что это XML.
При этом часто полезно следовать уже установленным соглашениям, и обычно .dat
файлы представляют собой файлы в двоичном формате. Вы можете использовать .dat для того, что вы хотите, но имейте в виду, что у некоторых пользователей могут быть привязки ОС к типу файла, и нажатие на ваш файл может вызвать поведение, отличное от ожидаемого в их системах.
Что касается того, как это сделать в Java. Получить дескриптор файла в Java легко…
File myFile = new File("/dir/file.gweebz");
Это очень просто, и вы можете назвать это как угодно. Вам понадобятся другие классы для записи и чтения из файла или для выполнения сжатия, но я предполагаю, что вы знаете, как это сделать. Если нет, на этом сайте будет ответ.