Форум программистов, компьютерный форум, киберфорум
Java
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.92/13: Рейтинг темы: голосов - 13, средняя оценка - 4.92
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
1

Сохранение бинарного json

07.11.2019, 13:46. Показов 2400. Ответов 18

Author24 — интернет-сервис помощи студентам
В гугле по поиску binary json или simple json java ничего не смог найти. Поэтому прошу помощи здесь.
Копаюсь в игре с редактором уровней, игра сохраняет файлы из редактора в сжатые бинарные джейсоны. Прочитать из бинарного файла в джейсон объект труда не возникло. Но теперь необходимо обратно записать объект в файл. Приложу мой класс чтения из файла для критики.
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
 
public class Test {
 
    public static void main(String[] args) {
        new Test();
    }
    Test() {
        try {
            System.out.println(loadFromCompressedFile("0.metadata").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public JsonElement loadFromCompressedFile(String fname) throws Exception {
        File file = new File(fname);
        return loadFromCompressedStream(new FileInputStream(file));
    }
    public JsonElement loadFromCompressedStream(InputStream is) throws Exception {
        BZip2CompressorInputStream cis = new BZip2CompressorInputStream(is);
        return loadFromStream(cis);
    }
    public JsonElement loadFromFile(String fname) throws Exception {
        File file = new File(fname);
        return loadFromStream(new FileInputStream(file));
    }
    public JsonElement loadFromStream(InputStream is) throws Exception {
        BufferedInputStream bis = new BufferedInputStream(is);
        return deserialize(bis);
    }
 
    private JsonElement deserialize(InputStream in) throws Exception {
        int z = readByte(in);
        switch (z) {
        case 1: {
            int num = readInt32(in);
            JsonArray jarr = new JsonArray();
            for (int i = 0; i < num; i++) {
                jarr.add(deserialize(in));
            }
            return jarr;
        }
        case 2: {
            int num = readInt32(in);
            JsonObject jobj = new JsonObject();
            for (int i = 0; i < num; i++) {
                String name = readString(in);
                jobj.add(name, deserialize(in));
            }
            return jobj;
        }
        case 3: {
            return new JsonPrimitive(readString(in));
        }
        case 4: {
            return new JsonPrimitive(readInt32(in));
        }
        case 5: {
            return new JsonPrimitive(readDouble(in));
        }
        case 6: {
            return new JsonPrimitive(readBoolean(in));
        }
        case 7: {
            return new JsonPrimitive(readFloat(in));
        }
        default: {
            throw new Exception("Error deserializing JSON. Unknown tag: " + z);
        }
        }
    }
    private int readInt32(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }
    private double readDouble(InputStream in) throws IOException {
        byte out[] = new byte[8];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getDouble();
    }
    private float readFloat(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    }
    private boolean readBoolean(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return (new Byte(out[0]).byteValue()) == 0 ? false : true;
    }
    private byte readByte(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return new Byte(out[0]).byteValue();
    }
    private String readString(InputStream in) throws IOException {
        char c;
        String str = "";
        do {
            int tmp = Byte.toUnsignedInt(readByte(in));
            String s = String.format("%8s", Integer.toBinaryString(tmp)).replace(' ', '0');
            c = s.charAt(0);
            str = s.substring(1) + str;
        } while (c == '1');
        int len = Integer.parseInt(str, 2);
        String out = new String(read(in, len));
        return out;
    }
    private byte[] read(InputStream in, int len) throws IOException {
        byte out[] = new byte[len];
        in.read(out);
        return out;
    }
}
Класс по сути переписанный с c# от юнити на java используя google gson. А обратно в коде используется virtual метод с переопределением в каждом классе json формата. Мне не хочется самому создавать свою реализацию json поэтому повторить код с шарпа считаю невозможным. Файл примера приложил к сообщению (необходимо распаковать до расширения metadata).
По сути надо обойти все json объекты углубляясь внутрь попутно записывая их последовательно в файл. Вот как это сделать не могу придумать. Ведь надо получить не только имена но и количество объектов на каждом уровне.
На примере простого json
JSON
1
{"environment":1,"size":1}
Бинарный файл будет таким
тэг 1 байт - 2 - объект json
количество объектов 4 байта - 2
имя объекта 12 байт - (1байт размер имени + строка environment)
тэг 1 байт - 4 - число инт
число инт 4 байта - 1
имя объекта 5 байт - (1байт размер имени + строка size)
тэг 1 байт - 4 - число инт
число инт 4 байта - 1
На примере более сложного json
JSON
1
{"environment":{"environment":1,"size":1},"size":1}
тэг 1 байт - 2 - объект json
количество объектов 4 байта - 2
имя объекта 12 байт - (1байт размер имени + строка environment)
тэг 1 байт - 2 - объект json
количество объектов 4 байта - 2
имя объекта 12 байт - (1байт размер имени + строка environment)
тэг 1 байт - 4 - число инт
число инт 4 байта - 1
имя объекта 5 байт - (1байт размер имени + строка size)
тэг 1 байт - 4 - число инт
число инт 4 байта - 1
имя объекта 5 байт - (1байт размер имени + строка size)
тэг 1 байт - 4 - число инт
число инт 4 байта - 1
Вложения
Тип файла: 7z 0.7z (764 байт, 0 просмотров)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.11.2019, 13:46
Ответы с готовыми решениями:

Сохранение map в json
Здравствуйте. Не могу решить одну проблему. Скорее всего я просто чего-то не знаю чтобы в ней...

Редактирование и сохранение изменений в файл JSON
с записью и чтением все понятно, примеров полно. Подскажите, пожалуйста, как можно редактировать...

[JSON] Правильное сохранение настроек в Json файл
Добрый день уважаемые участники. Есть вопрос. Решил я сохранять настройки проги в json файл....

(Сохранение и чтение с бинарного файла)
Задание: Расписание. (Учебное заведение имеет список преподавателей : фамилия, имя и отчество,...

18
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
07.11.2019, 13:55  [ТС] 2
ПЫСЫ ВСе это надо для того чтобы иметь возможность открывать в редакторе чужие карты, без правки файла карта грузится в режиме только для игры для не владельца файла. Если прописать себя в json то редактор спокойно открывает
0
Эксперт Java
3639 / 2971 / 918
Регистрация: 05.07.2013
Сообщений: 14,220
07.11.2019, 14:15 3
в чем проблема то, я так и не понял?
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
07.11.2019, 14:22  [ТС] 4
У меня нет идей как сохранить файл в бинарном формате
0
Эксперт Java
3639 / 2971 / 918
Регистрация: 05.07.2013
Сообщений: 14,220
07.11.2019, 14:33 5
Раз ты знаешь, как читать, ты, видимо, знаешь формат файла. А раз так - берешь и пишешь.
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
07.11.2019, 22:19  [ТС] 6
Почти написал сохранение, но возникла пара непоняток.
Первое. Как узнать тип числа из JsonElement? Я проверяю его сначала на JsonPrimitive а потом примитив на isNumber а что дальше хз. Мне нужно определить что за тип числа из трех нужных: int, double и float. То есть после проверок я точно знаю что имею дело с числом но неизвестного типа. Тип (один из трех) необходим обязательно.
И второе. Как нормально перевести число в тип int кодированный группами по 7 бит?
Пару слов про это кодирование. Изначально берется число типа int и его надо перевести в группу из n беззнаковых 7 битных byte, после этого записать в файл начиная с младших групп и первый бит в каждой группе установить в 1 если есть еще группа и 0 если группа последняя.
У меня вышел вот такой кривой способ.
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void writeName(OutputStream out, String str) throws IOException {
   int len = str.length();
   String binlen = Integer.toBinaryString(len);
   int b = 7*(int) Math.ceil(binlen.length() / 7.0) - binlen.length();
   if (b>0) {
      StringBuilder sb = new StringBuilder("");
      for (int i=0; i<b; i++) sb.append("0");
      binlen = sb.toString() + binlen;
   }
   String nums[] = binlen.split("(?<=\\G.{7})");
   String flg = "";
   for (int i=nums.length-1; i>=0; i--) {
      flg = i==0 ? "0" : "1";
      writeTag(out, Integer.parseInt(flg + nums[i], 2));
   }
   write(out, str.getBytes());
}
private void writeTag(OutputStream out, int num) throws IOException {
   out.write(new byte[]{(byte)num});
}
private void write(OutputStream out, byte byt[]) throws IOException {
   out.write(byt);
}
Иначе говоря я беру длинну строки в int и перевожу его в строку из бинарного представления этого числа.
После определяю сколько надо добавить нулей для того чтобы длинна строки стала кратна 7.
Далее создаю добавку из нулей нужной длинны и добавляю ее к строке.
Потом делю строку на группы по 7 знаков в массив строк.
И в конце прохожу массив строк с конца добавляя по 1 или 0 (0 к первому элементу) перевожу их обратно в int, потом в byte и пишу это дело в OutputStream.
Только мне мое решение не нравится. Более коротко и красиво придумать не могу.
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
08.11.2019, 14:03  [ТС] 7
Дописал, выкладываю весь код (чтение и запись) на критику и что стоит подправить (помимо предыдущего моего сообщения)
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
package ru.JsonBinary;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
 
public class SimpleJson {
 
    public JsonElement loadFromCompressedFile(String fname) throws Exception {
        File file = new File(fname);
        return loadFromCompressedStream(new FileInputStream(file));
    }
 
    public JsonElement loadFromCompressedStream(InputStream is) throws Exception {
        BZip2CompressorInputStream cis = new BZip2CompressorInputStream(is);
        return loadFromStream(cis);
    }
 
    public JsonElement loadFromFile(String fname) throws Exception {
        File file = new File(fname);
        return loadFromStream(new FileInputStream(file));
    }
 
    public JsonElement loadFromStream(InputStream is) throws Exception {
        BufferedInputStream bis = new BufferedInputStream(is);
        return deserialize(bis);
    }
 
    public void saveToStream(JsonElement in, OutputStream os) throws IOException {
        serealize(os, in);
    }
 
    public void saveToCompressedStream(JsonElement in, OutputStream os) throws IOException {
        BZip2CompressorOutputStream bic = new BZip2CompressorOutputStream(os);
        saveToStream(in, bic);
        bic.finish();
    }
 
    public void saveToFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists())
            file.createNewFile();
        FileOutputStream fos = new FileOutputStream(file);
        saveToStream(in, fos);
        fos.close();
    }
 
    public void saveToCompressedFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists())
            file.createNewFile();
        FileOutputStream fos = new FileOutputStream(file);
        saveToCompressedStream(in, fos);
        fos.close();
    }
 
    private void serealize(OutputStream out, JsonElement in) throws IOException {
        if (in.isJsonObject()) {
            writeTag(out, 2);
            int size = in.getAsJsonObject().size();
            writeLen(out, size);
            Set<Entry<String, JsonElement>> set = in.getAsJsonObject().entrySet();
            for (Entry<String, JsonElement> ent : set) {
                String name = ent.getKey().toString();
                writeName(out, name);
                serealize(out, ent.getValue());
            }
            return;
        }
        if (in.isJsonPrimitive()) {
            JsonPrimitive prim = in.getAsJsonPrimitive();
            if (prim.isBoolean()) {
                writeBoolean(out, prim.getAsBoolean());
                return;
            }
            if (prim.isNumber()) {
                String num = prim.getAsString();
                if (num.contains(".") || num.contains(",")) {
                    try {
                        Float.parseFloat(num);
                        writeFloat(out, prim.getAsFloat());
                    } catch (NumberFormatException e) {
                        writeDouble(out, prim.getAsDouble());
                    }
                } else {
                    writeInt32(out, prim.getAsInt());
                }
            }
            if (prim.isString()) {
                writeString(out, prim.getAsString());
                return;
            }
            return;
        }
        if (in.isJsonArray()) {
            writeTag(out, 1);
            int size = in.getAsJsonArray().size();
            writeLen(out, size);
            for (int i = 0; i < size; i++) {
                serealize(out, in.getAsJsonArray().get(i));
            }
            return;
        }
    }
 
    private void writeInt32(OutputStream out, int num) throws IOException {
        writeTag(out, 4);
        writeLen(out, num);
    }
 
    private void writeLen(OutputStream out, int num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putInt(num);
        byte[] bytes = dbuf.array();
        out.write(bytes);
    }
 
    private void writeDouble(OutputStream out, double num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(8);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putDouble(num);
        byte[] bytes = dbuf.array();
        writeTag(out, 5);
        out.write(bytes);
    }
 
    private void writeFloat(OutputStream out, float num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putFloat(num);
        byte[] bytes = dbuf.array();
        writeTag(out, 7);
        out.write(bytes);
    }
 
    private void writeString(OutputStream out, String str) throws IOException {
        writeTag(out, 3);
        writeName(out, str);
    }
 
    private void writeName(OutputStream out, String str) throws IOException {
        int len = str.length();
        String binlen = Integer.toBinaryString(len);
        int b = 7 * (int) Math.ceil(binlen.length() / 7.0) - binlen.length();
        if (b > 0) {
            StringBuilder sb = new StringBuilder("");
            for (int i = 0; i < b; i++)
                sb.append("0");
            binlen = sb.toString() + binlen;
        }
        String nums[] = binlen.split("(?<=\\G.{7})");
        String flg = "";
        for (int i = nums.length - 1; i >= 0; i--) {
            flg = i == 0 ? "0" : "1";
            writeTag(out, Integer.parseInt(flg + nums[i], 2));
        }
        out.write(str.getBytes());
    }
 
    private void writeTag(OutputStream out, int num) throws IOException {
        out.write(new byte[] { (byte) num });
    }
 
    private void writeBoolean(OutputStream out, boolean bool) throws IOException {
        writeTag(out, 6);
        if (bool) {
            writeTag(out, 1);
        } else {
            writeTag(out, 0);
        }
    }
 
    private JsonElement deserialize(InputStream in) throws Exception {
        int z = readByte(in);
        switch (z) {
        case 1: {
            int num = readInt32(in);
            JsonArray jarr = new JsonArray();
            for (int i = 0; i < num; i++) {
                jarr.add(deserialize(in));
            }
            return jarr;
        }
        case 2: {
            int num = readInt32(in);
            JsonObject jobj = new JsonObject();
            for (int i = 0; i < num; i++) {
                String name = readString(in);
                jobj.add(name, deserialize(in));
            }
            return jobj;
        }
        case 3: {
            return new JsonPrimitive(readString(in));
        }
        case 4: {
            return new JsonPrimitive(readInt32(in));
        }
        case 5: {
            return new JsonPrimitive(readDouble(in));
        }
        case 6: {
            return new JsonPrimitive(readBoolean(in));
        }
        case 7: {
            return new JsonPrimitive(readFloat(in));
        }
        default: {
            throw new Exception("Error deserializing JSON. Unknown tag: " + z);
        }
        }
    }
 
    private int readInt32(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }
 
    private double readDouble(InputStream in) throws IOException {
        byte out[] = new byte[8];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getDouble();
    }
 
    private float readFloat(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    }
 
    private boolean readBoolean(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return (new Byte(out[0]).byteValue()) == 0 ? false : true;
    }
 
    private byte readByte(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return new Byte(out[0]).byteValue();
    }
 
    private String readString(InputStream in) throws IOException {
        char c;
        String str = "";
        do {
            int tmp = Byte.toUnsignedInt(readByte(in));
            String s = String.format("%8s", Integer.toBinaryString(tmp)).replace(' ', '0');
            c = s.charAt(0);
            str = s.substring(1) + str;
        } while (c == '1');
        int len = Integer.parseInt(str, 2);
        String out = new String(read(in, len));
        return out;
    }
 
    private byte[] read(InputStream in, int len) throws IOException {
        byte out[] = new byte[len];
        in.read(out);
        return out;
    }
}
0
Эксперт функциональных языков программированияЭксперт Java
4486 / 2721 / 485
Регистрация: 28.04.2012
Сообщений: 8,590
08.11.2019, 21:43 8
Цитата Сообщение от alecss131 Посмотреть сообщение
выкладываю весь код (чтение и запись) на критику и что стоит подправить
Зачем мешать в одном классе чтение и запись? Лучше разнести по двум разным.

Магические числа нужно заменить числовыми константами с понятными именами.

Java
1
return new Byte(out[0]).byteValue();
— вот это зачем?
Java
1
return out[0];
Java
1
2
3
4
5
6
7
if (...) {
    ...
    return;
}
if (...) {
    ...
}
=>
Java
1
2
3
4
5
if (...) {
    ...
} else if (...) {
    ...
}
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
09.11.2019, 12:07  [ТС] 9
Вот новый вариант. Заменил функцию по кодированию длинны строки, надеюсь она получше. Возник вопрос, в стрингбилдере можно прибавлять строку не справа а слева?

reader
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package ru.SimpleJson;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
 
public class JsonBinaryReader {
 
    private final byte TAG_ARRAY = 1;
    private final byte TAG_OBJECT = 2;
    private final byte TAG_STRING_VALUE = 3;
    private final byte TAG_INT_VALUE = 4;
    private final byte TAG_DOUBLE_VALUE = 5;
    private final byte TAG_BOOLEAN_VALUE = 6;
    private final byte TAG_FLOAT_VALUE = 7;
 
    public JsonElement loadFromCompressedFile(String fname) throws Exception {
        File file = new File(fname);
        return loadFromCompressedStream(new FileInputStream(file));
    }
 
    public JsonElement loadFromCompressedStream(InputStream is) throws Exception {
        BZip2CompressorInputStream cis = new BZip2CompressorInputStream(is);
        return loadFromStream(cis);
    }
 
    public JsonElement loadFromFile(String fname) throws Exception {
        File file = new File(fname);
        return loadFromStream(new FileInputStream(file));
    }
 
    public JsonElement loadFromStream(InputStream is) throws Exception {
        BufferedInputStream bis = new BufferedInputStream(is);
        return deserialize(bis);
    }
 
    private JsonElement deserialize(InputStream in) throws Exception {
        byte z = readByte(in);
        switch (z) {
        case TAG_ARRAY: {
            int num = readInt(in);
            JsonArray jarr = new JsonArray();
            for (int i = 0; i < num; i++) {
                jarr.add(deserialize(in));
            }
            return jarr;
        }
        case TAG_OBJECT: {
            int num = readInt(in);
            JsonObject jobj = new JsonObject();
            for (int i = 0; i < num; i++) {
                String name = readString(in);
                jobj.add(name, deserialize(in));
            }
            return jobj;
        }
        case TAG_STRING_VALUE: {
            return new JsonPrimitive(readString(in));
        }
        case TAG_INT_VALUE: {
            return new JsonPrimitive(readInt(in));
        }
        case TAG_DOUBLE_VALUE: {
            return new JsonPrimitive(readDouble(in));
        }
        case TAG_BOOLEAN_VALUE: {
            return new JsonPrimitive(readBoolean(in));
        }
        case TAG_FLOAT_VALUE: {
            return new JsonPrimitive(readFloat(in));
        }
        default: {
            throw new Exception("Error deserializing JSON. Unknown tag: " + z);
        }
        }
    }
 
    private int readInt(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }
 
    private double readDouble(InputStream in) throws IOException {
        byte out[] = new byte[8];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getDouble();
    }
 
    private float readFloat(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    }
 
    private boolean readBoolean(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return (new Byte(out[0]).byteValue()) == 0 ? false : true;
    }
 
    private byte readByte(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return out[0];
    }
 
    private String readString(InputStream in) throws IOException {
        char c;
        String str = "";
        do {
            int tmp = Byte.toUnsignedInt(readByte(in));
            String s = String.format("%8s", Integer.toBinaryString(tmp)).replace(' ', '0');
            c = s.charAt(0);
            str = s.substring(1) + str;
        } while (c == '1');
        return new String(read(in, Integer.parseInt(str, 2)));
    }
 
    private byte[] read(InputStream in, int len) throws IOException {
        byte out[] = new byte[len];
        in.read(out);
        return out;
    }
}
writer
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package ru.SimpleJson;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
 
public class JsonBinaryWriter {
 
    private final byte TAG_ARRAY = 1;
    private final byte TAG_OBJECT = 2;
    private final byte TAG_STRING_VALUE = 3;
    private final byte TAG_INT_VALUE = 4;
    private final byte TAG_DOUBLE_VALUE = 5;
    private final byte TAG_BOOLEAN_VALUE = 6;
    private final byte TAG_FLOAT_VALUE = 7;
 
    public void saveToCompressedStream(JsonElement in, OutputStream os) throws IOException {
        BZip2CompressorOutputStream bic = new BZip2CompressorOutputStream(os);
        saveToStream(in, bic);
        bic.finish();
    }
 
    public void saveToFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists()) {
            file.createNewFile();
        }
        FileOutputStream fos = new FileOutputStream(file);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        saveToStream(in, bos);
        bos.close();
        fos.close();
    }
 
    public void saveToCompressedFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists()) {
            file.createNewFile();
        }
        FileOutputStream fos = new FileOutputStream(file);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        saveToCompressedStream(in, bos);
        bos.close();
        fos.close();
    }
 
    public void saveToStream(JsonElement in, OutputStream os) throws IOException {
        serealize(os, in);
    }
 
    private void serealize(OutputStream out, JsonElement in) throws IOException {
        if (in.isJsonObject()) {
            writeByte(out, TAG_OBJECT);
            int size = in.getAsJsonObject().size();
            writeLen(out, size);
            Set<Entry<String, JsonElement>> set = in.getAsJsonObject().entrySet();
            for (Entry<String, JsonElement> ent : set) {
                String name = ent.getKey().toString();
                writeName(out, name);
                serealize(out, ent.getValue());
            }
        } else if (in.isJsonPrimitive()) {
            JsonPrimitive prim = in.getAsJsonPrimitive();
            if (prim.isBoolean()) {
                writeBoolean(out, prim.getAsBoolean());
            } else if (prim.isNumber()) {
                String num = prim.getAsString();
                if (num.contains(".") || num.contains(",")) {
                    try {
                        Float.parseFloat(num);
                        writeFloat(out, prim.getAsFloat());
                    } catch (NumberFormatException e) {
                        writeDouble(out, prim.getAsDouble());
                    }
                } else {
                    writeInt(out, prim.getAsInt());
                }
            } else if (prim.isString()) {
                writeString(out, prim.getAsString());
            }
        } else if (in.isJsonArray()) {
            writeByte(out, TAG_ARRAY);
            int size = in.getAsJsonArray().size();
            writeLen(out, size);
            for (int i = 0; i < size; i++) {
                serealize(out, in.getAsJsonArray().get(i));
            }
        }
    }
 
    private void writeInt(OutputStream out, int num) throws IOException {
        writeByte(out, TAG_INT_VALUE);
        writeLen(out, num);
    }
 
    private void writeLen(OutputStream out, int num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putInt(num);
        byte[] bytes = dbuf.array();
        out.write(bytes);
    }
 
    private void writeDouble(OutputStream out, double num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(8);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putDouble(num);
        byte[] bytes = dbuf.array();
        writeByte(out, TAG_DOUBLE_VALUE);
        out.write(bytes);
    }
 
    private void writeFloat(OutputStream out, float num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putFloat(num);
        byte[] bytes = dbuf.array();
        writeByte(out, TAG_FLOAT_VALUE);
        out.write(bytes);
    }
 
    private void writeString(OutputStream out, String str) throws IOException {
        writeByte(out, TAG_STRING_VALUE);
        writeName(out, str);
    }
 
    private void writeName(OutputStream out, String str) throws IOException {
        int len = str.length();
        while (true) {
            String bin = "";
            for (int i = 0; i < 7; i++) {
                bin = len % 2 + bin;
                len = len / 2;
            }
            if (len == 0) {
                bin = "0" + bin;
                writeByte(out, (byte) Integer.parseInt(bin, 2));
                break;
            } else {
                bin = "1" + bin;
                writeByte(out, (byte) Integer.parseInt(bin, 2));
            }
        }
        out.write(str.getBytes());
    }
 
    private void writeByte(OutputStream out, byte num) throws IOException {
        out.write(new byte[] { num });
    }
 
    private void writeBoolean(OutputStream out, boolean bool) throws IOException {
        writeByte(out, TAG_BOOLEAN_VALUE);
        if (bool) {
            writeByte(out, (byte) 1);
        } else {
            writeByte(out, (byte) 0);
        }
    }
}
Еще остались магические числа? Вроде все остальные числа это размеры стандартных типов в байтах
0
Эксперт Java
3639 / 2971 / 918
Регистрация: 05.07.2013
Сообщений: 14,220
09.11.2019, 12:36 10
Про enum слышал? А про try-with-resources? Serialize. Ещё можно стратегию прикрутить, например.
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
09.11.2019, 13:30  [ТС] 11
xoraxax, Про enum слышал, но тут с ним будет только лишние усложнения и код. Меня напрягает switch-case по этому самому enum и enum начинается с нуля. А точнее считать байт из файла и сравнить его с enum без усложнения структуры enum не вижу способов.
Зачем здесь try-with-resources?
А про Serialize и стратегию вообще не в курсе.
Метод для чтения за основу был взят метод из шарпа от юнити и там был enum, но enum такого вида
C#
1
2
3
4
5
6
7
8
9
10
public enum JSONBinaryTag
{
   Array = 1,
   Class,
   Value,
   IntValue,
   DoubleValue,
   BoolValue,
   FloatValue
}
И использовался он так (в яве так не выйдет на сколько знаю)
C#
1
2
3
4
5
6
7
8
9
10
public static JSONNode Deserialize(BinaryReader aReader)
{
   JSONBinaryTag jSONBinaryTag = (JSONBinaryTag)aReader.ReadByte();
   switch (jSONBinaryTag)
   {
      case JSONBinaryTag.Array:
      { ... }
      ...
   }
}
Сейчас при обработке большого файла возникла ошибка.
Метод
Java
1
2
3
4
5
private byte[] read(InputStream in, int len) throws IOException {
   byte out[] = new byte[len];
   in.read(out);
   return out;
}
Получает на вход длинну в 6 байт, создает массив из 6 байт, но читает из потока на байт меньше, что приводит к исключению Error deserializing JSON. Unknown tag: Так как следующий за ним байт не тэг а буква, которая должна быть уже прочитана.

Добавлено через 1 минуту
Причем это происходит после середины файла ближе к концу, но до конца еще минимум около четверти файла.

Добавлено через 36 минут
Убрал строчку
Java
1
BufferedInputStream bis = new BufferedInputStream(is);
и читаю из FileInputStream и ошибка пропала. Хм, странно. Файл всего 16кб в несжатом виде
0
Эксперт Java
3639 / 2971 / 918
Регистрация: 05.07.2013
Сообщений: 14,220
09.11.2019, 13:36 12
Ты можешь конечно делать все, что угодно, но тогда непонятно, зачем ты тут советы спрашиваешь
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
09.11.2019, 13:48  [ТС] 13
Переделал на вот это
reader
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package ru.SimpleJson;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
 
public class JsonBinaryReader {
 
    private final byte TAG_ARRAY = 1;
    private final byte TAG_OBJECT = 2;
    private final byte TAG_STRING_VALUE = 3;
    private final byte TAG_INT_VALUE = 4;
    private final byte TAG_DOUBLE_VALUE = 5;
    private final byte TAG_BOOLEAN_VALUE = 6;
    private final byte TAG_FLOAT_VALUE = 7;
 
    public JsonElement loadFromCompressedFile(String fname) throws Exception {
        File file = new File(fname);
        try (FileInputStream fis = new FileInputStream(file)) {
            return loadFromCompressedStream(fis);
        }
    }
 
    public JsonElement loadFromCompressedStream(InputStream is) throws Exception {
        try (BZip2CompressorInputStream cis = new BZip2CompressorInputStream(is)) {
            return loadFromStream(cis);
        }
    }
 
    public JsonElement loadFromFile(String fname) throws Exception {
        File file = new File(fname);
        try (FileInputStream fis = new FileInputStream(file)) {
            return loadFromStream(fis);
        }
    }
 
    public JsonElement loadFromStream(InputStream is) throws Exception {
        try (BufferedInputStream bis = new BufferedInputStream(is)) {
            return deserialize(is);
        }
    }
 
    private JsonElement deserialize(InputStream in) throws Exception {
        byte z = readByte(in);
        switch (z) {
        case TAG_ARRAY: {
            int num = readInt(in);
            JsonArray jarr = new JsonArray();
            for (int i = 0; i < num; i++) {
                jarr.add(deserialize(in));
            }
            return jarr;
        }
        case TAG_OBJECT: {
            int num = readInt(in);
            JsonObject jobj = new JsonObject();
            for (int i = 0; i < num; i++) {
                String name = readString(in);
                jobj.add(name, deserialize(in));
            }
            return jobj;
        }
        case TAG_STRING_VALUE: {
            return new JsonPrimitive(readString(in));
        }
        case TAG_INT_VALUE: {
            return new JsonPrimitive(readInt(in));
        }
        case TAG_DOUBLE_VALUE: {
            return new JsonPrimitive(readDouble(in));
        }
        case TAG_BOOLEAN_VALUE: {
            return new JsonPrimitive(readBoolean(in));
        }
        case TAG_FLOAT_VALUE: {
            return new JsonPrimitive(readFloat(in));
        }
        default: {
            throw new Exception("Error deserializing JSON. Unknown tag: " + z);
        }
        }
    }
 
    private int readInt(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }
 
    private double readDouble(InputStream in) throws IOException {
        byte out[] = new byte[8];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getDouble();
    }
 
    private float readFloat(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    }
 
    private boolean readBoolean(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return (new Byte(out[0]).byteValue()) == 0 ? false : true;
    }
 
    private byte readByte(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return out[0];
    }
 
    private String readString(InputStream in) throws IOException {
        char c;
        String str = "";
        do {
            int tmp = Byte.toUnsignedInt(readByte(in));
            String s = String.format("%8s", Integer.toBinaryString(tmp)).replace(' ', '0');
            c = s.charAt(0);
            str = s.substring(1) + str;
        } while (c == '1');
        return new String(read(in, Integer.parseInt(str, 2)));
    }
 
    private byte[] read(InputStream in, int len) throws IOException {
        byte out[] = new byte[len];
        in.read(out);
        return out;
    }
}
writer
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package ru.SimpleJson;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
 
public class JsonBinaryWriter {
 
    private final byte TAG_ARRAY = 1;
    private final byte TAG_OBJECT = 2;
    private final byte TAG_STRING_VALUE = 3;
    private final byte TAG_INT_VALUE = 4;
    private final byte TAG_DOUBLE_VALUE = 5;
    private final byte TAG_BOOLEAN_VALUE = 6;
    private final byte TAG_FLOAT_VALUE = 7;
 
    public void saveToCompressedStream(JsonElement in, OutputStream os) throws IOException {
        try (BZip2CompressorOutputStream bic = new BZip2CompressorOutputStream(os)) {
            saveToStream(in, bic);
        }
    }
 
    public void saveToFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists()) {
            file.createNewFile();
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            try(BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                saveToStream(in, bos);
            }
        }
    }
 
    public void saveToCompressedFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists()) {
            file.createNewFile();
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            try (BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                saveToCompressedStream(in, bos);
            }
        }
    }
 
    public void saveToStream(JsonElement in, OutputStream os) throws IOException {
        serealize(os, in);
    }
 
    private void serealize(OutputStream out, JsonElement in) throws IOException {
        if (in.isJsonObject()) {
            writeByte(out, TAG_OBJECT);
            int size = in.getAsJsonObject().size();
            writeLen(out, size);
            Set<Entry<String, JsonElement>> set = in.getAsJsonObject().entrySet();
            for (Entry<String, JsonElement> ent : set) {
                String name = ent.getKey().toString();
                writeName(out, name);
                serealize(out, ent.getValue());
            }
        } else if (in.isJsonPrimitive()) {
            JsonPrimitive prim = in.getAsJsonPrimitive();
            if (prim.isBoolean()) {
                writeBoolean(out, prim.getAsBoolean());
            } else if (prim.isNumber()) {
                String num = prim.getAsString();
                if (num.contains(".") || num.contains(",")) {
                    try {
                        Float.parseFloat(num);
                        writeFloat(out, prim.getAsFloat());
                    } catch (NumberFormatException e) {
                        writeDouble(out, prim.getAsDouble());
                    }
                } else {
                    writeInt(out, prim.getAsInt());
                }
            } else if (prim.isString()) {
                writeString(out, prim.getAsString());
            }
        } else if (in.isJsonArray()) {
            writeByte(out, TAG_ARRAY);
            int size = in.getAsJsonArray().size();
            writeLen(out, size);
            for (int i = 0; i < size; i++) {
                serealize(out, in.getAsJsonArray().get(i));
            }
        }
    }
 
    private void writeInt(OutputStream out, int num) throws IOException {
        writeByte(out, TAG_INT_VALUE);
        writeLen(out, num);
    }
 
    private void writeLen(OutputStream out, int num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putInt(num);
        byte[] bytes = dbuf.array();
        out.write(bytes);
    }
 
    private void writeDouble(OutputStream out, double num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(8);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putDouble(num);
        byte[] bytes = dbuf.array();
        writeByte(out, TAG_DOUBLE_VALUE);
        out.write(bytes);
    }
 
    private void writeFloat(OutputStream out, float num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putFloat(num);
        byte[] bytes = dbuf.array();
        writeByte(out, TAG_FLOAT_VALUE);
        out.write(bytes);
    }
 
    private void writeString(OutputStream out, String str) throws IOException {
        writeByte(out, TAG_STRING_VALUE);
        writeName(out, str);
    }
 
    private void writeName(OutputStream out, String str) throws IOException {
        int len = str.length();
        while (true) {
            String bin = "";
            for (int i = 0; i < 7; i++) {
                bin = len % 2 + bin;
                len = len / 2;
            }
            if (len == 0) {
                bin = "0" + bin;
                writeByte(out, (byte) Integer.parseInt(bin, 2));
                break;
            } else {
                bin = "1" + bin;
                writeByte(out, (byte) Integer.parseInt(bin, 2));
            }
        }
        out.write(str.getBytes());
    }
 
    private void writeByte(OutputStream out, byte num) throws IOException {
        out.write(new byte[] { num });
    }
 
    private void writeBoolean(OutputStream out, boolean bool) throws IOException {
        writeByte(out, TAG_BOOLEAN_VALUE);
        if (bool) {
            writeByte(out, (byte) 1);
        } else {
            writeByte(out, (byte) 0);
        }
    }
}
Ошибка с чтением пропала.
Остальные вопросы хочу услышать ответы, особенно про про Serialize и стратегию
0
Эксперт Java
3639 / 2971 / 918
Регистрация: 05.07.2013
Сообщений: 14,220
09.11.2019, 16:18 14
Цитата Сообщение от alecss131 Посмотреть сообщение
Serialize
вот это просто написано неправильно было
А про стратегию - надо прочитать, что такое стратегия и подумать, куда ее можно засунуть. Иначе ты опять скажешь, что и так норм. Еще кстати, попробуй свой код тестами покрыть. Может так понятнее будет.
0
Эксперт функциональных языков программированияЭксперт Java
4486 / 2721 / 485
Регистрация: 28.04.2012
Сообщений: 8,590
09.11.2019, 22:48 15
Цитата Сообщение от alecss131 Посмотреть сообщение
Java
1
out.write(new byte[] { num });
Зачем создавать массив из одного байта?

Java
1
out.write(num);
Java
1
2
3
4
5
    private byte readByte(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return out[0];
    }
Зачем опять массив?
Java
1
2
3
    private byte readByte(InputStream in) throws IOException {
        return (byte) in.read();
    }
Java
1
2
3
4
5
    private boolean readBoolean(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return (new Byte(out[0]).byteValue()) == 0 ? false : true;
    }
Вот опять, зачем это new Byte(...).byteValue()?

А вообще, результаты вызовов всех вариантов методов InputStream.read нужно проверять. Почитай документацию.

Java
1
new String(read(in, Integer.parseInt(str, 2)));
— не указана кодировка — разный результат на разных платформах.

Добавлено через 15 минут
Java
1
String.format("%8s", Integer.toBinaryString(tmp)).replace(' ', '0');
=>
Java
1
String.format("%08s", Integer.toBinaryString(tmp));
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
09.11.2019, 22:52  [ТС] 16
Из одного байта так как без массива write принимает int а не byte и боюсь запишет int (4 байта) вместо byte (1 байт)
А ведь же read возвращает число прочитанных байт в формате int а мне нужно значение прочитанного байта в виде числа
Про new Byte… не усмотрел. Может есть вариант короче записать boolean в 1 байт в виде чисел 1 или 0?
Проверка по типу int test = in.read(byte[]); а потом если test != len то кидать исключение?
Добавлю кодировку, надеюсь с utf-8 и 1 буквой на 1 байт проблем не будет.
Во всех тонкостях не разбираюсь, поэтому сюда код на критику и выложил.
0
Эксперт функциональных языков программированияЭксперт Java
4486 / 2721 / 485
Регистрация: 28.04.2012
Сообщений: 8,590
09.11.2019, 23:25 17
Цитата Сообщение от korvin_ Посмотреть сообщение
Java
1
String.format("%08s", Integer.toBinaryString(tmp));
Тут погорячился.

Добавлено через 2 минуты
Цитата Сообщение от alecss131 Посмотреть сообщение
Из одного байта так как без массива write принимает int а не byte и боюсь запишет int (4 байта) вместо byte (1 байт)
А ты вместо того, чтобы бояться, документацию б почитал.

Цитата Сообщение от alecss131 Посмотреть сообщение
надеюсь с utf-8 и 1 буквой на 1 байт проблем не будет.
Конечно будет. В UTF-8 может быть больше одного байта на букву.

Добавлено через 1 минуту
Я вообще не понимаю, что там за адовая магия с чтением/записью строк происходит.
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
10.11.2019, 13:26  [ТС] 18
korvin_, Там происходит по сути вот что. Строка из себя представляет конструкцию из <размер строки в байтах><строка в виде байт>. Так вот этот размер надо получить и записать либо правильно прочитать. Размер там имеет нефиксированную длину от 1 до 5 байт (так как int занимает 4 байта). Суть описана тут, но там в примере порядок байт другой.
Лучше всего объяснит что происходит картинка во вложении, за исключением что байты идут в другом порядке, а следовательно выделенные байты другие.
Там результат
10000110-11000011-00010111
А тут надо вот так
10010111-11000011-00000110
На сколько понимаю в примере на вики используется BIG_ENDIAN для разбивки числа на группы и приписке MSB, а у меня LITTLE_ENDIAN
Грубо говоря это мои реализации методов BinaryReader.ReadString и BinaryReader.WriteString из c#
Готовой реализации в java данных штук не нашел.

Обновлю коды классов.
Кликните здесь для просмотра всего текста
reader
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package ru.SimpleJson;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
 
public class JsonBinaryReader {
 
    private final byte TAG_ARRAY = 1;
    private final byte TAG_OBJECT = 2;
    private final byte TAG_STRING_VALUE = 3;
    private final byte TAG_INT_VALUE = 4;
    private final byte TAG_DOUBLE_VALUE = 5;
    private final byte TAG_BOOLEAN_VALUE = 6;
    private final byte TAG_FLOAT_VALUE = 7;
 
    public JsonElement loadFromCompressedFile(String fname) throws Exception {
        File file = new File(fname);
        try (FileInputStream fis = new FileInputStream(file)) {
            return loadFromCompressedStream(fis);
        }
    }
 
    public JsonElement loadFromCompressedStream(InputStream is) throws Exception {
        try (BZip2CompressorInputStream cis = new BZip2CompressorInputStream(is)) {
            return loadFromStream(cis);
        }
    }
 
    public JsonElement loadFromFile(String fname) throws Exception {
        File file = new File(fname);
        try (FileInputStream fis = new FileInputStream(file)) {
            return loadFromStream(fis);
        }
    }
 
    public JsonElement loadFromStream(InputStream is) throws Exception {
        try (BufferedInputStream bis = new BufferedInputStream(is)) {
            return deserialize(is);
        }
    }
 
    private JsonElement deserialize(InputStream in) throws Exception {
        byte z = readByte(in);
        switch (z) {
        case TAG_ARRAY: {
            int num = readInt(in);
            JsonArray jarr = new JsonArray();
            for (int i = 0; i < num; i++) {
                jarr.add(deserialize(in));
            }
            return jarr;
        }
        case TAG_OBJECT: {
            int num = readInt(in);
            JsonObject jobj = new JsonObject();
            for (int i = 0; i < num; i++) {
                String name = readString(in);
                jobj.add(name, deserialize(in));
            }
            return jobj;
        }
        case TAG_STRING_VALUE: {
            return new JsonPrimitive(readString(in));
        }
        case TAG_INT_VALUE: {
            return new JsonPrimitive(readInt(in));
        }
        case TAG_DOUBLE_VALUE: {
            return new JsonPrimitive(readDouble(in));
        }
        case TAG_BOOLEAN_VALUE: {
            return new JsonPrimitive(readBoolean(in));
        }
        case TAG_FLOAT_VALUE: {
            return new JsonPrimitive(readFloat(in));
        }
        default: {
            throw new Exception("Error deserializing JSON. Unknown tag: " + z);
        }
        }
    }
 
    private int readInt(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }
 
    private double readDouble(InputStream in) throws IOException {
        byte out[] = new byte[8];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getDouble();
    }
 
    private float readFloat(InputStream in) throws IOException {
        byte out[] = new byte[4];
        in.read(out);
        return ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    }
 
    private boolean readBoolean(InputStream in) throws IOException {
        byte out[] = new byte[1];
        in.read(out);
        return out[0] == 0 ? false : true;
    }
 
    private byte readByte(InputStream in) throws Exception {
        int out = in.read();
        if (out == -1) {
            throw new Exception("Error reading file");
        }
        return (byte) out;
    }
 
    private String readString(InputStream in) throws Exception {
        char c;
        String str = "";
        do {
            int tmp = Byte.toUnsignedInt(readByte(in));
            String s = String.format("%8s", Integer.toBinaryString(tmp)).replace(' ', '0');
            c = s.charAt(0);
            str = s.substring(1) + str;
        } while (c == '1');
        return new String(read(in, Integer.parseInt(str, 2)), "UTF-8");
    }
 
    private byte[] read(InputStream in, int len) throws Exception {
        byte out[] = new byte[len];
        int test = in.read(out);
        if (test != len) {
            throw new Exception("Error reading file");
        }
        return out;
    }
}
writer
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package ru.SimpleJson;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
 
public class JsonBinaryWriter {
 
    private final byte TAG_ARRAY = 1;
    private final byte TAG_OBJECT = 2;
    private final byte TAG_STRING_VALUE = 3;
    private final byte TAG_INT_VALUE = 4;
    private final byte TAG_DOUBLE_VALUE = 5;
    private final byte TAG_BOOLEAN_VALUE = 6;
    private final byte TAG_FLOAT_VALUE = 7;
 
    public void saveToCompressedStream(JsonElement in, OutputStream os) throws IOException {
        try (BZip2CompressorOutputStream bic = new BZip2CompressorOutputStream(os)) {
            saveToStream(in, bic);
        }
    }
 
    public void saveToFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists()) {
            file.createNewFile();
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            try(BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                saveToStream(in, bos);
            }
        }
    }
 
    public void saveToCompressedFile(JsonElement in, String fname) throws IOException {
        File file = new File(fname);
        if (!file.exists()) {
            file.createNewFile();
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            try (BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                saveToCompressedStream(in, bos);
            }
        }
    }
 
    public void saveToStream(JsonElement in, OutputStream os) throws IOException {
        serialize(os, in);
    }
 
    private void serialize(OutputStream out, JsonElement in) throws IOException {
        if (in.isJsonObject()) {
            out.write(TAG_OBJECT);
            int size = in.getAsJsonObject().size();
            writeLen(out, size);
            Set<Entry<String, JsonElement>> set = in.getAsJsonObject().entrySet();
            for (Entry<String, JsonElement> ent : set) {
                String name = ent.getKey().toString();
                writeName(out, name);
                serialize(out, ent.getValue());
            }
        } else if (in.isJsonPrimitive()) {
            JsonPrimitive prim = in.getAsJsonPrimitive();
            if (prim.isBoolean()) {
                writeBoolean(out, prim.getAsBoolean());
            } else if (prim.isNumber()) {
                String num = prim.getAsString();
                if (num.contains(".") || num.contains(",")) {
                    try {
                        Float.parseFloat(num);
                        writeFloat(out, prim.getAsFloat());
                    } catch (NumberFormatException e) {
                        writeDouble(out, prim.getAsDouble());
                    }
                } else {
                    writeInt(out, prim.getAsInt());
                }
            } else if (prim.isString()) {
                writeString(out, prim.getAsString());
            }
        } else if (in.isJsonArray()) {
            out.write(TAG_ARRAY);
            int size = in.getAsJsonArray().size();
            writeLen(out, size);
            for (int i = 0; i < size; i++) {
                serialize(out, in.getAsJsonArray().get(i));
            }
        }
    }
 
    private void writeInt(OutputStream out, int num) throws IOException {
        out.write(TAG_INT_VALUE);
        writeLen(out, num);
    }
 
    private void writeLen(OutputStream out, int num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putInt(num);
        out.write(dbuf.array());
    }
 
    private void writeDouble(OutputStream out, double num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(8);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putDouble(num);
        out.write(TAG_DOUBLE_VALUE);
        out.write(dbuf.array());
    }
 
    private void writeFloat(OutputStream out, float num) throws IOException {
        ByteBuffer dbuf = ByteBuffer.allocate(4);
        dbuf.order(ByteOrder.LITTLE_ENDIAN).putFloat(num);
        out.write(TAG_FLOAT_VALUE);
        out.write(dbuf.array());
    }
 
    private void writeString(OutputStream out, String str) throws IOException {
        out.write(TAG_STRING_VALUE);
        writeName(out, str);
    }
 
    private void writeName(OutputStream out, String str) throws IOException {
        byte b[] = str.getBytes("UTF-8");
        int len = b.length;
        while (true) {
            String bin = "";
            for (int i = 0; i < 7; i++) {
                bin = len % 2 + bin;
                len = len / 2;
            }
            if (len == 0) {
                bin = "0" + bin;
                out.write((byte) Integer.parseInt(bin, 2));
                break;
            } else {
                bin = "1" + bin;
                out.write((byte) Integer.parseInt(bin, 2));
            }
        }
        out.write(b);
    }
 
    private void writeBoolean(OutputStream out, boolean bool) throws IOException {
        out.write(TAG_BOOLEAN_VALUE);
        if (bool) {
            out.write((byte) 1);
        } else {
            out.write((byte) 0);
        }
    }
}
0
Модератор
Эксперт Java
2558 / 1094 / 375
Регистрация: 11.08.2017
Сообщений: 3,332
10.11.2019, 13:29  [ТС] 19
Файл не приложился((
Миниатюры
Сохранение бинарного json  
0
10.11.2019, 13:29
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.11.2019, 13:29
Помогаю со студенческими работами здесь

Сохранение и открытие бинарного файла используя TFilestream
Блин, я знаю как это сделать дефолтной библиотекой языка но мне просто очень хочется реализовать...

Сохранение в JSON
Здравствуйте, делаю игру на подобии Hill Climb Racing и нужно сделать прокачку машин. Делаю так при...

Сохранение в файл JSON
Необходимо сохранить данные в файл формата json. Имеется код: import psycopg2 import sqlite3...

Сохранение объекта JSON
всем доброго времени суток. на работе поставили задачу , реализовать выгрузку данных в файл...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru