Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Java программирование > Общие вопросы по Java, Java SE, Kotlin
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 21.04.2020, 14:44   #1
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию Перевёрнутые числа в бинарном файле

Здравствуйте.
Есть две программы, написанные на C++ и Java. Они пишут числа в бинарный файл.
Необходимо, чтобы они могли читать данные, записанные друг другом.
Но вот проблема:
Java пишет так
Код:

            DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("bin.dat")));
            int x = 256;
            dos.writeShort((short)x);
            dos.writeInt(x);
            dos.close();
//HEX: 01 00 00 00 01 00
а WinAPI так
Код:
	
        DWORD dw = 0;
        int x = 256;
        WriteFile(fh, &x, sizeof(short), &dw, NULL);
        WriteFile(fh, &x, sizeof(int), &dw, NULL);
//HEX: 00 01 00 01 00 00
То есть, числа перевёрнуты. Почему так?
И как тогда на Java писать числа так же как в WinAPI, чтобы программа на С тоже могла их читать?
Понятно что можно переворачивать, но как?
BLACK_RAIN вне форума Ответить с цитированием
Старый 21.04.2020, 19:26   #2
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,285
По умолчанию

Java сохраняет данные с порядком байтов Big Endian, а WinAPI, похоже, Little Endian. Не знаю, как именно правильно (быстро и эффективно) подгонять порядок на Java, но теперь вам будет что погуглить.
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )
BDA вне форума Ответить с цитированием
Старый 22.04.2020, 08:05   #3
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Цитата:
Сообщение от BDA Посмотреть сообщение
WinAPI, похоже, Little Endian
WinAPI тупо пишет блок памяти. Как числа в памяти лежат, так и пишет.
А вот почему Java переворачивает - надо смотреть

Действительно, прямо в доке написано
Цитата:
writeInt(int v)
Writes an int to the underlying output stream as four bytes, high byte first.
StackOverflow предлагает использовать ByteBuffer

Последний раз редактировалось Black Fregat; 22.04.2020 в 08:17.
Black Fregat вне форума Ответить с цитированием
Старый 22.04.2020, 14:16   #4
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию

Цитата:
Сообщение от BDA Посмотреть сообщение
java сохраняет данные с порядком байтов Big Endian, а WinAPI, похоже, Little Endian.
Да, я это уже понял и написал классы
Код:
package xxx;

import java.io.*;

public class LittleEndianDataInputStream extends FilterInputStream implements DataInput {

    public LittleEndianDataInputStream(InputStream in) {
        super(in);
    }

    @Override
    public void readFully(byte[] b) throws IOException {

    }

    @Override
    public void readFully(byte[] b, int off, int len) throws IOException {

    }

    @Override
    public int skipBytes(int n) throws IOException {
        return 0;
    }

    @Override
    public boolean readBoolean() throws IOException {
        return false;
    }

    @Override
    public byte readByte() throws IOException {
        return 0;
    }

    @Override
    public int readUnsignedByte() throws IOException {
        return 0;
    }

    @Override
    public short readShort() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        if ((ch1 | ch2) < 0)
            throw new EOFException();
        return (short)(ch1 + (ch2 << 8));
    }

    @Override
    public int readUnsignedShort() throws IOException {
        return 0;
    }

    @Override
    public char readChar() throws IOException {
        return 0;
    }

    @Override
    public int readInt() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4 ;
    }

    @Override
    public long readLong() throws IOException {
        return 0;
    }

    @Override
    public float readFloat() throws IOException {
        return 0;
    }

    @Override
    public double readDouble() throws IOException {
        return 0;
    }

    @Override
    public String readLine() throws IOException {
        return null;
    }

    @Override
    public String readUTF() throws IOException {
        return null;
    }
}
Код:
package xxx;

import java.io.*;

public class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput {

    private int writtenBytes;

    public LittleEndianDataOutputStream(OutputStream out){
        super(out);
//        writtenBytes = 0;
    }

    private void incCount(int value) {
        int temp = writtenBytes + value;
        if (temp < 0) {
            temp = Integer.MAX_VALUE;
        }
        writtenBytes = temp;
    }

    @Override
    public void writeBoolean(boolean v) throws IOException {
        out.write(v ? 1 : 0);
        incCount(1);
    }

    @Override
    public void writeByte(int v) throws IOException {
        out.write(v);
        incCount(1);
    }

    @Override
    public void writeShort(int v) throws IOException {
        out.write(v & 0xFF);
        out.write((v >>> 8) & 0xFF);
        incCount(2);
    }

    @Override
    public void writeChar(int v) throws IOException {

    }

    @Override
    public void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);

    }

    @Override
    public void writeLong(long v) throws IOException {

    }

    @Override
    public void writeFloat(float v) throws IOException {

    }

    @Override
    public void writeDouble(double v) throws IOException {

    }

    @Override
    public void writeBytes(String s) throws IOException {

    }

    @Override
    public void writeChars(String s) throws IOException {

    }

    @Override
    public void writeUTF(String s) throws IOException {

    }

    public int size() {
        return writtenBytes;
    }
}
Теперь всё работает. Java пишет и читает Little endian. Но появился странный косяк. Массивы байт пишутся страшно медленно. Например, массив размером 4 мегабайта через стандартный DataOutputStream пишется мгновенно, а через мой класс за 12 секунд. Почему так? Я же в своём классе не оверрайдю метод, который пишет массив. Должен использоваться стандартный из FilterOutputStream.
BLACK_RAIN вне форума Ответить с цитированием
Старый 23.04.2020, 05:26   #5
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,285
По умолчанию

Цитата:
FilterOutputStream.write:
Note that this method does not call the write method of its underlying input stream with the same arguments. Subclasses of FilterOutputStream should provide a more efficient implementation of this method
То есть DataOutputStream пишет более эффективно, чем FilterOutputStream.
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )
BDA вне форума Ответить с цитированием
Старый 23.04.2020, 08:50   #6
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию

просто надо было добавить метод
Код:
    public void write(byte b[]) throws IOException {
        out.write(b, 0, b.length);
        incCount(b.length);
    }
Тогда массив пишется одним вызовом и по-этому получается мгновенно.
Я думал, что этот метод уже где-то в базовых классах прописан.

Пардон, ошибочка вышла. Надо вот так:
Код:
//чтение
    @Override
    public short readShort() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        if ((ch1 | ch2) < 0)
            throw new EOFException();
        return (short)(ch1 + (ch2 << 8));
    }

    @Override
    public int readInt() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return ch1 + (ch2 << 8) + (ch3 << 16) + (ch4 << 24);
    }

//запись
    @Override
    public void writeShort(int v) throws IOException {
        out.write(v & 0xFF);
        out.write((v >> 8) & 0xFF);
        incCount(2);
    }

    @Override
    public void writeInt(int v) throws IOException {
        out.write(v & 0xFF);
        out.write((v >> 8) & 0xFF);
        out.write((v >> 16) & 0xFF);
        out.write((v >> 24) & 0xFF);
        incCount(4);
    }
Кстати, в оригинальных классах используются три хрени >>> хотя работает и с двумя.
В чем разница, две или три?

Последний раз редактировалось BLACK_RAIN; 23.04.2020 в 11:44.
BLACK_RAIN вне форума Ответить с цитированием
Старый 23.04.2020, 22:10   #7
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,285
По умолчанию

>>> - беззнаковый сдвиг (в старшие биты всегда будет записываться 0), а >> - знаковый (в старшие биты запишется значение знакового бита). В данном случае срабатывают одинаково из-за масок, которые отбрасывают те биты, в которых будет различие.
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )
BDA вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
поиск hex значения в бинарном файле (большого объема) witia03 Общие вопросы Delphi 10 23.05.2012 20:25
сортировка структуры в бинарном файле миклух Общие вопросы C/C++ 0 16.04.2012 10:00
сортировка структур в бинарном файле vvsh Общие вопросы C/C++ 1 25.06.2011 16:04
Сортировка списка в бинарном файле J_D Помощь студентам 0 28.05.2011 10:34
Поиск числа в бинарном файле. mazak Общие вопросы C/C++ 5 18.02.2010 12:05