Приложение StreamToken

Оглавление Работа с файлами Классы потоков Стандартные потоки Потоки и файлы Запись и чтение потоков Закрывание потоков Сброс буферов Потоки в памяти Stream Tokenizer String Tokenizer Класс File Произвольный доступ Приложение StreamToken Приложение DirectFile

Назад Вперед

В приложении StreamToken мы демонстрируем использование класса StreamTokenizer для разбора входного потока.

Вначале приложение запрашивает у пользователя строку для разбора, записывая ее в файл. Затем этот файл открывается для чтения буферизованным потоком и разбирается на составные элементы. Каждый такой элемент выводится в отдельной строке, как это показано на рис. 4.

Рис. 4. Разбор входного потока в приложении StreamToken

Обратите внимание, что в процессе разбора значение 3.14 было воспринято как числовое, а 3,14 - нет. Это потому, что при настройке разборщика мы указали, что символ '.' является обычным.

Исходный текст приложения

Исходный текст приложения StreamToken представлен в листинге 1.

Листинг 1. Файл StreamToken.java

    import java.io.*;

    public class StreamToken
    {
      public static void main(String args[])
      {
        DataOutputStream OutStream;
        DataInputStream  InStream;

        byte bKbdInput[] = new byte[256];
        String sOut;

        try
        {
          System.out.println(
            "Enter string to parse...");

          System.in.read(bKbdInput);

          sOut = new String(bKbdInput, 0);

          OutStream = new DataOutputStream(
            new BufferedOutputStream(
              new FileOutputStream(
               "output.txt")));

          OutStream.writeBytes(sOut);
          OutStream.close();

          InStream = new DataInputStream(
            new BufferedInputStream(
              new FileInputStream(
                "output.txt")));

          TokenizerOfStream tos =
            new TokenizerOfStream();

          tos.TokenizeIt(InStream);
          InStream.close();

          System.out.println(
            "Press <Enter> to terminate...");
          System.in.read(bKbdInput);
        }
        catch(Exception ioe)
        {
          System.out.println(ioe.toString());
        }
      }
    }

    class TokenizerOfStream
    {
      public void TokenizeIt(InputStream is)
      {
        StreamTokenizer stok;
        String str;

        try
        {
          stok = new StreamTokenizer(is);
          stok.slashSlashComments(true);

          stok.ordinaryChar('.');

          while(stok.nextToken() !=
             StreamTokenizer.TT_EOF)
          {
            switch(stok.ttype)
            {
              case StreamTokenizer.TT_WORD:
              {
                str = new String(
                  "\nTT_WORD >" + stok.sval);
                break;
              }

              case StreamTokenizer.TT_NUMBER:
              {
                str = "\nTT_NUMBER >" +
                   Double.toString(stok.nval);
                break;
              }

              case StreamTokenizer.TT_EOL:
              {
                str = new String("> End of line");
                break;
              }

              default:
                {
                  if((char)stok.ttype == '"')
                  {
                    str = new String(
                      "\nTT_WORD >" + stok.sval);
                  }

                  else
                    str = "> " +
                      String.valueOf(
                        (char)stok.ttype);
                }
            }

            System.out.println(str);
          }
        }
        catch(Exception ioe)
        {
          System.out.println(ioe.toString());
        }
      }
    }

Описание исходного текста приложения

После ввода строки с клавиатуры и записи ее в файл через поток наше приложение создает входной буферизованный поток, как это показано ниже:

    InStream = new DataInputStream(
      new BufferedInputStream(
      new FileInputStream("output.txt")));

Далее для этого потока создается разборщик, который оформлен в отдельном классе TokenizerOfStream, определенном в нашем приложении:

    TokenizerOfStream tos =
      new TokenizerOfStream();

Вслед за этим мы вызываем метод TokenizeIt, определенный в классе TokenizerOfStream, передавая ему в качестве параметра ссылку на входной поток:

    tos.TokenizeIt(InStream);

Метод TokenizeIt выполняет разбор входного потока, отображая результаты разбора на консоли. После выполнения разбора входной поток закрывается методом close:

    InStream.close();

Самое интересное в нашем приложении связано, очевидно, с классом TokenizerOfStream, поэтому перейдем к его описанию.

В этом классе определен только один метод TokenizeIt:

    public void TokenizeIt(InputStream is)
    {
      . . .
    }

Получая в качестве параметра ссылку на входной поток, он прежде всего создает для него разборщик класса StreamTokenizer:

    StreamTokenizer stok;
    stok = new StreamTokenizer(is);

Настройка параметров разборщика очень проста и сводится к вызовам всего двух методов:

    stok.slashSlashComments(true);
    stok.ordinaryChar('.');

Метод slashSlashComments включает режим распознавания комментариев в стиле языка программирования С++, а метод ordinaryChar объявляет символ '.' обычным символом.

После настройки запускается цикл разбора входного потока, причем условием завершения цикла является достижение конца этого потока:

    while(stok.nextToken() !=
      StreamTokenizer.TT_EOF)
    {
      . . .
    }

В цикле анализируется содержимое поля ttype, которое зависит от типа элемента, обнаруженного во входном потоке:

    switch(stok.ttype)
    {
      case StreamTokenizer.TT_WORD:
      {
        str = new String("\nTT_WORD >"
           + stok.sval);
        break;
      }
      case StreamTokenizer.TT_NUMBER:
      {
        str = "\nTT_NUMBER >" +
          Double.toString(stok.nval);
        break;
      }
      case StreamTokenizer.TT_EOL:
      {
        str = new String("> End of line");
        break;
      }
      default:
      {
        if((char)stok.ttype == '"')
          str = new String(
            "\nTT_WORD >" + stok.sval);
        else
          str = "> " + String.valueOf(
           (char)stok.ttype);
      }
    }

На слова и численные значения мы реагируем очень просто - записываем их текстовое представление в рабочую переменную str типа String. При обнаружении конца строки в эту переменную записывается строка End of line.

Если же обнаружен обычный символ, мы сравниваем его с символом кавычки. При совпадении в переменную str записывается содержимое поля sval, в котором находятся слова, обнаруженные внутри кавычек. Если же обнаруженный символ не является символом кавычки, он преобразуется в строку и записывается в переменную str.

В заключении метод выводит строку str в стандартный поток вывода, отображая на консоли выделенный элемент потока:

    System.out.println(str);

Назад Вперед