Чтение определенного индекса из двоичного файла, содержащего массив объектов
У меня есть двоичный файл, созданный в программе Java. Двоичный файл содержит массив объектов User.
Он был создан так:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Main {
public static void main(String[] args) {
User[] arrayOfUsers = new User[50];
for (int i = 0; i < 50; i++){
arrayOfUsers[i] = new User("Mr. ", i + "owitz");
}
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users.dat"));
oos.writeObject(arrayOfUsers);
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Это User
учебный класс:
import java.io.Serializable;
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String firstname;
private String lastname;
public User(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}
На данный момент я знаю, как читать только весь массив одновременно. Тем не менее, мне обычно нужно получить только один или два User
объекты из массива, и я знаю их позиции.
Есть ли способ прочитать только индекс, который я хочу прочитать, не читая во всем?
1 ответ
Вы создаете не прямой файл, а просто последовательный файл, который содержит сериализуемую версию Java ArrayList. Таким образом, вы можете только прочитать весь ArrayList в памяти, чтобы снова обработать его и получить доступ к отдельному элементу.
Если вы хотите иметь доступ непосредственно к элементу, просто зная его индекс, вам нужно будет создать настоящий прямой файл или индексированный файл. Прямой файл имеет записи постоянного размера, скажем s
Итак, смещение для записи n
является n * s
, Вы можете использовать его через класс Java RandomAccessFile
, Но вы не должны напрямую использовать readUTF
или же writeUTF
для прямых файлов, потому что длина строки в байтах зависит от количества и типа символов:
- Все символы в диапазоне от \u0001 до \u007F представлены одним байтом
- Нулевой символ "\u0000" и символы в диапазоне от "\u0080" до "\u07FF" представлены парой байтов
- Значения символов в диапазоне от \u0800 до \uFFFF представлены тремя байтами
(ссылка: Javadoc для DataInput)
Так что вам лучше явно конвертировать их в byte[]
с String.getBytes()
по крайней мере, теперь легче контролировать размер и вручную записывать размер, а не байты. В качестве альтернативы, вы можете написать пропустить преобразование в байтах, записать размер в Char
а затем напишите отдельные символы.
Если вы почти никогда не изменяете значения или не добавляете значения, вы можете использовать индексированный файл. Основа состоит в том, чтобы сначала иметь массив, содержащий смещения записей. Это позволяет записям не иметь одинаковый размер. Возможный дизайн будет:
- количество записей в массиве смещений (
int n
) - n int для смещений
- данные
Чтобы записать файл, вы вычисляете начало области данных: (1 + n) * 4, создайте массив int для хранения смещений. Тогда ты пишешь n+1 0
чтобы файл был правильно позиционирован, и запишите свою строку, последовательно сохраняя позицию записи для первой записи. Наконец вы возвращаетесь к 0, записываете количество записей и смещений.
Чтобы прочитать, просто прочитайте количество записей и смещений. Затем вы можете перемещаться по файлу. Это в основном используется для больших записей неизвестных и переменных размеров
И если вы обнаружите, что вышеупомянутое слишком сложно, просто используйте базы данных. Derby или H2 могут использоваться как встроенные базы данных, и это будет намного проще.