Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Чары файлов, не могу развеять 
V
    Опции темы
Platon
Дата 25.4.2006, 20:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Я тут пытался реализовать метод сжатия LZ78 на моем любимом Java. Вроде все понятно, но проблемы, кажется, с сохранением в файл. Наверное, проблемы с переводом из класса Record в строку и обратно. Напомню людям, что каждая запись содержит номер записи, с которой начинается данная и символ, который к ней дописывается. Запись состоит из одного чара и 1-го int'а. Как понимаете, int в файл может записываться с разной длиной, а мне надо с фиксированой. Я выбрал 2 байта. Вот код:

Код

import java.io.*;
import java.util.*;

public class LZ78 {

    void packToFile(String po, Vector<Record> values) throws IOException {
        BufferedWriter out = new BufferedWriter(new FileWriter(po));
        for (Record i : values)
            out.write(i.toString());
        out.close();
    }

    void unpackToFile(String po, Vector<String> values) throws IOException {
        BufferedWriter out = new BufferedWriter(new FileWriter(po));
        for (String i : values)
            out.write(i);
        out.close();
    }

    public void encode(String pi, String po) throws IOException {
        // Здесь код закодирования. Он правильный
        // values - Vector<Record>
        // po - выходной файл
        packToFile(po, values);
    }

    public void decode(String pi, String po) throws IOException {
        // Здесь код разкодирования. Он правильный
        unpackToFile(po, dictionary);
    }
    public static void main(String[] args) throws IOException {
        LZ78 temp = new LZ78();
        temp.encode("in.txt", "arch.txt");
        temp.decode("arch.txt", "out.txt");
    }
}

class Record {
    char s;
    int pos;
    public Record(char s, int pos) {
        this.s = s;
        this.pos = pos;
    }
    public char[] toCharArray() {
        return new char[]{s, (char)(pos >> 8), (char)(pos & 0xFF)};
    }
    public static Record toRecord(String str) {
        return toRecord(str.toCharArray());
    }

    public String toString() {
        return String.valueOf(toCharArray());
    }

    public static Record toRecord(char[] str) {
        return new Record(str[0], ((int)str[1] << 8) | (int)str[2]);
    }
}


Код работает для ультра-коротких файлов, и дает сбои со сравнительно средними файлами. Вероятно, это происходит из-за увеличения размера словаря. Если не сохранять в файл и раскодировать сразу из values, то все прекрасно для всех файлов умеренных размеров, а вот раскодировать архив уже не получается.  
PM MAIL ICQ   Вверх
LSD
Дата 25.4.2006, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



С LZ78 я незнаком, поэтому пока объясни поподробней, что именно там происходит.

Дело в том, что char это UTF-16, он хранит 65536 различных символов. А запись в файл идет в системной кодировке, как правило это однобайтовые кодировки, т.е. 256 символов. И подобное преобразование конечно не может пройти без потерь. Так что сам принцип сохранения не верен. 


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
jimur
Дата 25.4.2006, 22:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 21.4.2006

Репутация: 2
Всего: 3



А out.flush() не пробовал ставить? 
PM MAIL   Вверх
LSD
Дата 25.4.2006, 23:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(jimur @  25.4.2006,  23:59 Найти цитируемый пост)
А out.flush() не пробовал ставить? 

close() - выполняет flush(). 


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
jimur
Дата 25.4.2006, 23:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 21.4.2006

Репутация: 2
Всего: 3



Цитата(LSD @  25.4.2006,  23:02 Найти цитируемый пост)
close() - выполняет flush(). 


Цитата(java.io.BufferedWriter.flushBuffer())

/**
     * Flush the output buffer to the underlying character stream, without
     * flushing the stream itself.  This method is non-private only so that it
     * may be invoked by PrintStream.
     */

 
PM MAIL   Вверх
LSD
Дата 25.4.2006, 23:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Не понял. Ты предлагаешь вызвать именно flushBuffer() вместо flush()?

И чем это поможет, если перед закрытием буффер все равно очищается? 


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
jimur
Дата 25.4.2006, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 21.4.2006

Репутация: 2
Всего: 3



Предлагаю попробовать вызывать
вместо
        out.close();

вызывать
        out.flush();
        out.close();

выдержка из исходников в сочетании с приведенными выше фрагментами объясняет почему
Код

    /**
     * Flush the stream.
     *
     * @exception  IOException  If an I/O error occurs
     */
    public void flush() throws IOException {
    synchronized (lock) {
        flushBuffer();
        out.flush();
    }
    }

    /**
     * Close the stream.
     *
     * @exception  IOException  If an I/O error occurs
     */
    public void close() throws IOException {
    synchronized (lock) {
        if (out == null)
        return;
        flushBuffer();
        out.close();
        out = null;
        cb = null;
    }
    }
 
PM MAIL   Вверх
Platon
Дата 26.4.2006, 06:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Ээээ, люди со flush() и close() все отлично, дело в другом.


LSD, значит с байтами. А я чего-то не пойму, ведь смотрю в архивный файл и вижу все нормально: 1 байт под символ, 2 байта под int. И как-бы чары и без этого жмутся в 1 байт. А с байтами очень уж неудобно работать.

Ну, это не очень важно, но если требуешь попробую объяснить:
В общем начинаем. Фраза, записываемая в файл, будет состоять из 3-х байт: 1 под символ, 2 под число.
В методе есть строчный вектор словарь и фразный вектор значения.
Каждый цикл считываем по 1-му чару. И прибавляем его к исследуемой строке curString. Ищем эту строку в словаре, если она есть, то запоминаем номер ее позиции, если нет, надо занести в словарь и добавить новую запись с последним прочитанным символом и позицией последней совпавшей строки. Фу... вроде ничего не упустил, правда пока не проверял, но хвост может оставаться, я там такую пришпандорку сделал.

Прошу прощения за бестактный вопрос, но как байты то в BufferedWriter записывать?  

Это сообщение отредактировал(а) Platon - 26.4.2006, 17:42
PM MAIL ICQ   Вверх
jimur
Дата 26.4.2006, 06:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 21.4.2006

Репутация: 2
Всего: 3



Цитата(Platon @  26.4.2006,  06:07 Найти цитируемый пост)
Прошу прощения за бестактный вопрос, но как байты то в BufferedWriter записывать? 

дак он для этого не предназначен - он для чаров. 
PM MAIL   Вверх
Platon
Дата 26.4.2006, 08:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Так. Я выяснил в чем ошибка. Проблема в том, что выражение return new Record(str[0], ((int)str[1] << 8) | str[2]); работает некорректно.

В случае когда int равен 128 оно естественно представляется в виде 0x0080 в двухбайтной системе. Хе а когда обратно перевожу у меня два байта один равен нулю, а второй -128, второй приводится к int, причем знак сохраняется!!! И получается все равно -128 вместо 128. Козалось бы чего сложного. В С++ это решается просто, а в Java как? 

Это сообщение отредактировал(а) Platon - 26.4.2006, 17:25
PM MAIL ICQ   Вверх
Platon
Дата 26.4.2006, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Тупейшим образом решил свою проблему:
Код

    public static Record toRecord(byte[] str) {
        return new Record((char)str[0], ((int)str[1] << 8) | (str[2] & 0x7F) | ((((byte)str[2] & 0x80) == 0)? 0:0x0080));

    }


Как проще-то? 
PM MAIL ICQ   Вверх
LSD
Дата 26.4.2006, 22:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(jimur @  26.4.2006,  00:35 Найти цитируемый пост)
выдержка из исходников в сочетании с приведенными выше фрагментами объясняет почему

Вовсе не объясняет (а исходники я и так видел). close() вызывает очистку данного буфера, и закрытие нижележащего потока, который в свою очередь сам очистит свой буфер перед закрытием.


Цитата(Platon @  26.4.2006,  07:07 Найти цитируемый пост)
А я чего-то не пойму, ведь смотрю в архивный файл и вижу все нормально: 1 байт под символ, 2 байта под int. И как-бы чары и без этого жмутся в 1 байт. А с байтами очень уж неудобно работать.

В Java char - это 2 байта, а int - 4 байта. Зачем тебе вообще нужны char, почему ты не работаешь с byte, что в них такого сложного? 


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
jimur
Дата 27.4.2006, 06:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 21.4.2006

Репутация: 2
Всего: 3



Цитата(LSD @  26.4.2006,  22:13 Найти цитируемый пост)
Вовсе не объясняет (а исходники я и так видел). close() вызывает очистку данного буфера, и закрытие нижележащего потока, который в свою очередь сам очистит свой буфер перед закрытием.

Да, согласен, при работе с FileWriter'ом достаточно close(). 
PM MAIL   Вверх
Platon
Дата 27.4.2006, 08:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



LSD, да согласен уже перешел. Но загвоздка в переводе 2-х байтов в int. Я решил ее одним методом, но уж больно кривенький он. Неужели в Java нет unsigned byte?

Код

public static Record toRecord(byte[] str) {
    return new Record((char)str[0], ((int)str[1] << 8) | (str[2] & 0x7F) | ((((byte)str[2] & 0x80) == 0)? 0:0x0080));


Добавлено @ 08:15 
И еще. Можно ли порции битов из файла читать? Или свой класс разрабатывать? 
PM MAIL ICQ   Вверх
batigoal
Дата 27.4.2006, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



Цитата(Platon @  27.4.2006,  09:14 Найти цитируемый пост)
Неужели в Java нет unsigned byte?

Нет, беззнаковых типов нету. 


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0595 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.