Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java ME (J2ME) > Позиционирование в файле


Автор: WildChild 28.3.2006, 13:11
допустим есть файл (это только пример, на самом деле он больше)
Структура файла:
Код

eng_word1:rus_trans1
eng_word2:rus_trans2
.
.
eng_wordN:rus_transN


Как позиционироваться в файле, чтобы можно было начинать не с начала файла, а из произвольного места?
Вывод на экран мобилы должен быть, приблизительно, такой:
Код

eng_word
rus_trans


Спасибо!

Автор: powerOn 29.3.2006, 12:04
Попробуй вначале все данные из файла прочитать в массив. Потом с поизвольно места читаь легко сможешь.

Автор: Dancer 29.3.2006, 12:45
какой массив, не вздумай!!! (я там понимаю никакой памяти в телефоне не хватит, если ты будешь не хилый словарик держать в телефоне. просто напросто приложение по OutOfMemory загнётся.
Есть метод тайкой как skip() точно не помню, нужно будет проверить, вот если тебе это подойдёт, то ты можешь узнать размер твоего файлика и пропустить первые N байт, потом начать читать с N+1 байта. (это если JSR-75 используешь и файлик у тебя в файловой системе телефона валяется)
Если же файлик ты таскаешь вместе со своим мидлетом, то у тебя есть InputStream скорее всего на этот файлик, там то же можно skip(long n) применить.

---------------
smile читаем доки.......
Добавлено @ 12:57
да, лучше всего думаю для твоей структуры хранения подойдёт XML (для мобилок есть библиотечка kXML. Очень не плохая штука http://kxml.sourceforge.net)
Так что сделаешь либо хеш функцию для вычисления ID английского слова и это ID у тебя будет как атрибут в XML тэге, по этому атрибуту будешь искать превод слова.
что-то наподобие

<dict>
<word>
<eng_word ID = "123456789">mother</eng_word>
<rus_word ID = "123">мама</rus_word>

</word>
</dict>

Хотя конечно, структуру делаешь так, как подскажет здравый смысл и опыт (то что выше это просто пример и ничего более), далее расширение на другие языки можно будет делать достаточно просто, ну и соответственно все буковки естественно лучше всего будет писать в уникоде /uXXXX

Автор: redrick 29.3.2006, 12:59
MoonCat, если размер файла действительно большой, то я бы поостерегся весь его читать в массив(10кб юникода это на самом деле даже не страница). Предлагаю запомнить в массиве просто смещения в байтах каждой строчки.

Автор: Dancer 29.3.2006, 13:19
redrick, не плохое решение про хранить в массиве смещения, но тогда уже лучше делать второй файлик, зависимый от нашего файла словаря, то есть если внесли изменения в словарь, то запускаем скрип (ну, или кто что напишет), который бегает по нашему словарю и запихивает в другой фалик смещения для каждой строчки (возможно даже лучше писать ID для этой строчки и смещение к этой строчки. В словаре сначала будет идти ID слова далее eng:rus\n)
тогда можно будет позиционироваться по строчками и если сделать хорошую функцию создания ID для слова (в Кнуте не плохо данные алгоритмы описаны) то позиционироваться по файлику словаря будет достаточно легко. Самая загвоздка при создании хешей - это конечно решение коллизий, но это уже тема не этой беседы smile

Автор: powerOn 29.3.2006, 13:42
Цитата

какой массив, не вздумай!!! (я там понимаю никакой памяти в телефоне не хватит, если ты будешь не хилый словарик держать в телефоне. просто напросто приложение по OutOfMemory загнётся.


smile О размере файла ничего конкретного сказано не было.

Более того, поиск через постоянные операции файлового ввода вывода не эффективен.
Если речь идет о действительно большом словаре, то предлагаю немного поменять структуру файла.
Дополнить например ее какими либо методанными по которым можно ускорить поиск. Например, вначале
файла хранить таблицу, где обозначить с какой позиции начинаются слова на определенную букву. Или вообще разбить словарь на несколько файлов для каждой начальной буквы, ну и таком духе....

Автор: WildChild 29.3.2006, 15:40
MoonCat, Dancer, redrick, спасибо большое за помощь!

MoonCat, извини! Я не указал размер файла и тебе досталось. Sorry! В следующий раз буду повнимательней!
На самом деле размер файла будет колебаться от 10 до N (в разумных пределах) слов.

Dancer
Цитата

<eng_word ID = "123456789">mother</eng_word>
<rus_word ID = "123">мама</rus_word>

ID русского и английского слов НЕ должы совпадать?

Цитата

первые N байт, потом начать читать с N+1 байта

Я пробывал... Если попадаешь в середину байта, то очень не хорошая вещь получается...
Можно, конечно, дальше читать до \n, ну и так далее. Но, сильно муторно...

Автор: Dancer 29.3.2006, 16:31
ну, насчёт того должны эти ID совпадать или нет - не знаю. Если к примеру ты делаешь какую-то хитрую универсальную хеш функцию, то на вход подаёшь слово на любом языке, получаешь ID ищешь это ID и переводишь слово на любой доступный язык из твоего файлика.
Если же тебе нужно чётко с английского на русский, то наверное лучше чтобы ID совпадали. (я же говорил, что это дано лишь для примера, и никак не руководство к действию. Как лучше организовать логику уже тебе думать (и выбирать, мне так кажется)

Вот про то что мы попадем на серидину байта не совсем понял - это как?
читаем то мы постоянно побайтно, так что прочить полбайта и остановиться просто не можем. (ты как себе такое представляешь. Реально видел такие ситуации?)

Автор: WildChild 29.3.2006, 20:35
Я ошибся, сказав, что попадаю в середину байта.
Наверное, в середину UTF символа, если так можно сказать. Ну в общем, не работало...

Ошибку свою понял.

Автор: WildChild 30.3.2006, 20:22
Есть вот такой код
Код

  public void startApp() {
    Random r = new Random();
    try {
      parser.setInput(reader); //назначим парсеру источник данных
    } catch (XmlPullParserException e) {
      System.out.println("Не удалось связать парсер с потоком данных");
    }
    while (doJob) {
        int number = 0;
        number = (int)(10 * r.nextDouble());
      try {
        event = parser.next(); //переместим курсор на следующий элемент документа
        name = parser.getName(); //получим имя этого элемента
        if (event == KXmlParser.END_DOCUMENT) {
          doJob = false;
          break;
        }
        if ((event == KXmlParser.START_TAG) && (name.startsWith("trunk"))) {
            if (parser.getAttributeValue(0).equals(java.lang.Integer.toString(number))) {
                event = parser.next();
                name = parser.getName();
                //System.out.println(parser.getAttributeValue(0) + "    " + parser.getAttributeValue(1)); 
                if ((event == KXmlParser.START_TAG) && (name.startsWith("branch")))
                    System.out.println("    " + parser.getAttributeValue(0) + ":" + parser.getAttributeValue(1));
            }
        }
      } catch (XmlPullParserException e) {
        System.out.println("Во время парсинга с парсером случилось что-то нехорошее");
      } catch (IOException e) {
        System.out.println("Во время парсинга парсер потерял связь с источником данных");
      } catch (NullPointerException e) {
       System.out.println("Что-то не так!");
      }
    }
  }

На строку 23 (если её раскомментировать) WTK22 выдает ошибку
Код

startApp threw an Exception
java.lang.IndexOutOfBoundsException
java.lang.IndexOutOfBoundsException
    at org.kxml2.io.KXmlParser.getAttributeValue(+15)
    at MobileXmlParser.startApp(+156)
    at javax.microedition.midlet.MIDletProxy.startApp(+7)
    at com.sun.midp.midlet.Scheduler.schedule(+270)
    at com.sun.midp.main.Main.runLocalClass(+28)
    at com.sun.midp.main.Main.main(+116)

В if, на строке 24, не входит...
Текст xml-файла следующий
Код

<?xml version="1.0" standalone="yes"?>
<root>
      <trunk id="0">
              <branch eng="mother" rus="мама">
              </branch>
      </trunk>
    <trunk id="1">
        <branch eng="bad" rus="плохой">
        </branch>
    </trunk>
    <trunk id="2">
        <branch eng="live" rus="жить">
        </branch>
    </trunk>
</root>


В чем проблема, не могу понять... Может кто сталкивался
Работаю с kXML 2.2.

Автор: redrick 30.3.2006, 20:53
ну наверное у того элемента всего один атрибут, а не 2 (хотя вроде как это должен быть <branch>...)

чем гадать - залезь в дебагер да посмотри что на самом деле в parser в этой строчке

Автор: WildChild 30.3.2006, 21:52
Вот пример xml файла, из работающей программы взятой отсюда - http://lib.juga.ru/article/articleview/209/1/16/
Код

<?xml version="1.0" standalone="yes"?>
<root>
    <trunk id="0">
        <branch name="branch1" id="1">
            <!--This is a branch that belongs to our tree-->
        </branch>
        <branch name="branch2" id="2">
            <leaf name="leaf1" id="3"></leaf>
            <leaf name="leaf2" id="4"></leaf>
            <leaf name="leaf3" id="5"></leaf>
        </branch>
    </trunk>
</root>

Автор: WildChild 31.3.2006, 11:34
Кажется я разобрался...
Нельзя повторно использовать
Код

event = parser.next();

Я так понимаю, что если его использовать повторно, то я попадаю сразу в конец документа...
То есть первый раз попадаю на <root>, а второй вызов - на </root>, а не на <trunk>.
Если я хочу гулять по тэгам, то необходимо делать следующее: smile
Код

event = parser.nextTag();

На том примере, что есть в данной теме я ещё не проверял. Проверил на другом - РАБОТАЕТ! smile

Автор: redrick 31.3.2006, 12:47
ну вот, "а ты боялась..." =)

Автор: WildChild 31.3.2006, 12:50
Думал, успею отредактировать свое сообщение... Ан нет. ;о)
Просто, неправильно работает код...
Буду ещё smile

Спасибо за поддержку!

Автор: Dancer 31.3.2006, 14:28
Код

import javax.microedition.midlet.*;
import org.kxml2.io.*;
import org.xmlpull.v1.*;
import java.io.*;
import java.util.*;

public class XmlUse extends MIDlet {
    private KXmlParser parser;
    private InputStreamReader reader;
    private boolean doJob = true;
    private int event;
    private String name;    

    public void startApp() {
        Random r = new Random();
        parser = new KXmlParser();
Log("parser = " + parser);

        reader = new InputStreamReader(this.getClass().getResourceAsStream("new_data.xml"));
Log("reader = " + reader);
        try {
            parser.setInput(reader); //назначим парсеру источник данных
        } catch (XmlPullParserException e) {
            System.out.println("Не удалось связать парсер с потоком данных");
        }
        while (doJob) {
//            int number = 0;
//            number = (int)(10 * r.nextLong());
            try {
                event = parser.next(); //переместим курсор на следующий элемент документа
                name = parser.getName(); //получим имя этого элемента
//Log("element Name = " + name);
                if (event == KXmlParser.END_DOCUMENT) {
                    doJob = false;
                    break;
                }
                if ((event == KXmlParser.START_TAG) && (name.startsWith("trunk"))) {
//                    if (parser.getAttributeValue(0).equals(java.lang.Integer.toString(number))) {
                        event = parser.nextTag();
                        name = parser.getName();
Log("name in trunk = " + name);
//                        event = parser.next();
//                        name = parser.getName();
//Log("name in trunk = " + name);

                        System.out.println(parser.getAttributeValue(0) + "    " + parser.getAttributeValue(1)); 
                        if ((event == KXmlParser.START_TAG) && (name.startsWith("branch")))
                            System.out.println("    " + parser.getAttributeValue(0) + ":" + parser.getAttributeValue(1));
//                    }
                }
            } catch (XmlPullParserException e) {
                System.out.println("Во время парсинга с парсером случилось что-то нехорошее");
            } catch (IOException e) {
                System.out.println("Во время парсинга парсер потерял связь с источником данных");
            } catch (NullPointerException e) {
                System.out.println("Что-то не так!");
            }
        }
    }

    public void pauseApp() {
    }
    
    public void destroyApp(boolean unconditional) {
    }

    public void Log(String str) {
        System.out.println(str);
    }
}


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)