LXF86:Java
(→Свободный доступ) |
(→Протоколирование работы программы) |
||
Строка 112: | Строка 112: | ||
=== Протоколирование работы программы === | === Протоколирование работы программы === | ||
+ | Для контроля и анализа работы приложения существуют методы протоколирования. Популярным инструментом для этих целей в мире | ||
+ | Java является библиотека Log4j, которая разрабатывается в Apache Software Foundation. Текущую версию можно загрузить с [http://logging.apache.org/[http://logging.apache.org/]]. | ||
+ | |||
+ | Для использования библиотеки необходимо создать конфигурационный файл, который описывает, что, куда и как нужно протоколировать. Log4j имеет три базовые составляющие: logger, appender и layout. | ||
+ | |||
+ | layout — это элементы, определяющие вид и содержание записей. Изначально имеется несколько заранее созданных layout-ов, а в случае необходимости можно создать свой собственный. | ||
+ | |||
+ | Appender — это элемент, определяющий местоположение протокола, с его помощью задается тип протоколирования: | ||
+ | * файловое протоколирование (FileAppender); | ||
+ | * консольное протоколирование (ConsoleAppender); | ||
+ | * протоколирование в базы данных (JDBCAppender); | ||
+ | * протоколирование на SMTP-сервера (SMTPAppender) и др. | ||
+ | |||
+ | Logger — это элемент, который обеспечивает протоколирование какого-либо события. Если обратиться к ранее приведенной аналогии | ||
+ | ленточного конвейера, logger — это и есть тот самый конвейер, вызывая методы которого, мы формируем протокол работы программы. | ||
+ | Элемент logger предусматривает следующие уровни протоколирования: DEBUG, INFO, WARN, ERROR, FATAL; уровням соответствуют методы класса org.apache.log4j.Logger: debug; info; warn; error; fatal. | ||
+ | |||
+ | Ниже представлен пример записей для конфигурационного файла нашего приложения, которые нужно сохранить в файл с названием '''log.properties''' (название файла может быть любым). | ||
+ | |||
+ | <code> | ||
+ | log4j.logger.simple=DEBUG, nameLogAppender | ||
+ | log4j.appender.nameLogAppender=org.apache.log4j.FileAppender | ||
+ | log4j.appender.nameLogAppender.File=nameLogFile.log | ||
+ | log4j.appender.nameLogAppender.layout=org.apache.log4j.SimpleLayout | ||
+ | </code> | ||
+ | |||
+ | Первая строка указывает используемый уровень logger (DEBUG) и appender (nameLogAppender). Далее идут настройки appender: указание типа — FileAppender. В третьей строке указываем путь до файла журнала, а в последней — формат записи. Использовать экземпляр класса Logger можно примерно так (пример протоколирования приведен на диске в каталоге '''examples 3'''): | ||
+ | <source lang = "java"> | ||
+ | File propertiesFile = new File("log.properties"); | ||
+ | PropertyConfigurator.configure(propertiesFile.toString()); | ||
+ | Logger logger = Logger.getLogger("simple"); | ||
+ | logger.info("the program has started"); | ||
+ | </source> | ||
=== Документы XML === | === Документы XML === |
Версия 13:11, 13 марта 2008
|
|
|
Содержание |
Хранение данных
ЧАСТЬ 3: Даже самой замечательной программе надо откуда-то черпать данные для своей работы. Данные, как известно, хранятся в файлах. Тему продолжает Антон Черноусов.
В предыдущей статье из цикла, посвященного программированию на Java, были рассмотрены вопросы организации простых вычислений, ветвлений, циклов, а также генерации и обработки исключений.
В течение третьего урока мы поговорим о работе с файлами, о протоколировании работы программы и коснемся методов работы с XML-данными.
Файлы — потоки
Сказочное королевство под руководством царевны Несмеяны (так как cупруг практически всегда отсутствовал), благодаря талантам и приобретенным навыкам, стало разрастаться, и результаты полюдья просто-напросто перестали помещаться в семейный чулан. Чтобы накапливать и хранить богатства, потребовались дополнительные помещения, роль которых для нас привычно играют файлы.
Отношение к файлам в Java достаточно непростое: если рассматривать файл как устройство для ввода/вывода информации — с этой точ ки зрения он подобен блоку памяти или экрану, интерфейс доступа к которому унифицирован: это поток. Но несмотря на унифицированный интерфейс, существует большое количество классов сходной функциональности, в которых легко запутаться.
Поток можно представить в виде ленточного конвейера с последовательным размещением или извлечением данных, при использовании которого задача программиста сводиться к осуществлению операций «поместить/читать» данные, а остальные детали реализации скрыты от него.
Чтение данных
Разнообразие классов для работы с файлами позволяет выбрать для себя ту связку, которая больше нравится. Лично я для чтения данных использую BufferedReader, InputStreamReader и FileInputStream. Собственно взаимодействие этих классов для программиста заканчивается в момент создания экземпляра BufferedReader, что делается следующим образом:
BufferedReader br = null; br = new BufferedReader(new InputStreamReader(new FileInputStream(pathToFile), encoding));
В процессе создания участвуют строковые переменные, содержащие путь к файлу и кодировку, в которой производится считывание данных: pathToFile и encoding. В классах, работающих с файлами, считается обязательным создавать переменную для кодировки по умолчанию:
protected static String DEFAULT_ENCODING = "UTF-8";
Любой текстовый файл можно представить себе в виде набора строк, поэтому давайте реализуем метод для считывания содержимого файла в массив String[]. Далее представлен метод rippedCurrentFile(path ToFile, encoding) класса FileRipper, который извлекает данные из файла с помощью метода readLine() экземпляра класса BufferedReader:
protected boolean rippedCurrentFile(String pathToFile, String encoding) { // connecting to file BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(new FileInputStream(pathToFile),encoding)); } catch (UnsupportedEncodingException e) { this.error = FILE_ERROR_UNSUPPORTED_ENCODING; return false; } catch (FileNotFoundException e) { this.error = FILE_ERROR_NO_FILE; return false; } // ripping the file String str = null; ArrayList allStrings = new ArrayList(); try { while (!(str = br.readLine()).equals(null)) { allStrings.add(str); } } catch (IOException e) { this.error = FILE_ERROR_IO_READ; return false; } catch (NullPointerException e) { this.error = FILE_ERROR_END_OF_FILE; } // free the resources try { br.close(); } catch (IOException e) { this.error = FILE_ERROR_IO_CLOSE; return false; } this.allStrings = (String[]) allStrings.toArray(new String[0]); return true; }
Полный код примера, в том числе код класса ConsoleToFileRipper, применяющий экземпляр класса FileRipper для извлечения данных из файла, можно найти на диске в каталоге examples 1.
Запись данных
Процесс записи данных в файл хоть и отличается от чтения, но тоже достаточно похож на организацию конвейера. Для записи я обычно использую связку BufferedWriter, OutputStreamWriter, FileOutputStream.
BufferedWriter out; out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(pathToFile), encoding));
Для освобождения ресурсов, которые используют экземпляры классов BufferedReader и BufferedWriter, необходимо вызвать метод close().
Далее приведу простой пример метода, который записывает строковый массив в файл (полный код метода расположен на диске в директории examples 2):
public boolean createCurrentFile(String pathToFile, String[] allStrings, String encoding){ try { BufferedWriter out; out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(pathToFile), encoding)); for (int i = 0; i < allStrings.length; i++) { out.write(allStrings[i]); out.write(‘\n’); } out.close(); } catch (IOException e) { e.printStackTrace(); return false; } return true; }
Свободный доступ
В представленных ранее примерах доступ к данным осуществляется последовательно, что не всегда удобно (хотя в большинстве случаев именно такой доступ и используется). Для осуществления чтения и записи данных из файла в произвольном порядке существует специальный класс RandomAccessFile, экземпляр которого создается следующим образом:
RandomAccessFile raf = new RandomAccessFile(pathToFile, mode);
При этом pathToFile — путь до файла, а mode — режим работы. mode может принимать значения: r (только чтение), rw (чтение-запись), rws (чтение-запись с синхронным сохранением содержимого и метаданных), rwd (чтение-запись с синхронным сохранением содержимого файла). К сожалению, кодировку указать нельзя. Огромным преимуществом подхода является то, что с помощью метода getFilePointer() можно узнать текущее месторасположение указателя, а с помощью метода seek() можно передвинуть указатель в необходимое место в файле. Я предпочитаю не использовать данный класс — считайте это личным предубеждением.
Протоколирование работы программы
Для контроля и анализа работы приложения существуют методы протоколирования. Популярным инструментом для этих целей в мире Java является библиотека Log4j, которая разрабатывается в Apache Software Foundation. Текущую версию можно загрузить с [http://logging.apache.org/].
Для использования библиотеки необходимо создать конфигурационный файл, который описывает, что, куда и как нужно протоколировать. Log4j имеет три базовые составляющие: logger, appender и layout.
layout — это элементы, определяющие вид и содержание записей. Изначально имеется несколько заранее созданных layout-ов, а в случае необходимости можно создать свой собственный.
Appender — это элемент, определяющий местоположение протокола, с его помощью задается тип протоколирования:
- файловое протоколирование (FileAppender);
- консольное протоколирование (ConsoleAppender);
- протоколирование в базы данных (JDBCAppender);
- протоколирование на SMTP-сервера (SMTPAppender) и др.
Logger — это элемент, который обеспечивает протоколирование какого-либо события. Если обратиться к ранее приведенной аналогии ленточного конвейера, logger — это и есть тот самый конвейер, вызывая методы которого, мы формируем протокол работы программы. Элемент logger предусматривает следующие уровни протоколирования: DEBUG, INFO, WARN, ERROR, FATAL; уровням соответствуют методы класса org.apache.log4j.Logger: debug; info; warn; error; fatal.
Ниже представлен пример записей для конфигурационного файла нашего приложения, которые нужно сохранить в файл с названием log.properties (название файла может быть любым).
log4j.logger.simple=DEBUG, nameLogAppender log4j.appender.nameLogAppender=org.apache.log4j.FileAppender log4j.appender.nameLogAppender.File=nameLogFile.log log4j.appender.nameLogAppender.layout=org.apache.log4j.SimpleLayout
Первая строка указывает используемый уровень logger (DEBUG) и appender (nameLogAppender). Далее идут настройки appender: указание типа — FileAppender. В третьей строке указываем путь до файла журнала, а в последней — формат записи. Использовать экземпляр класса Logger можно примерно так (пример протоколирования приведен на диске в каталоге examples 3):
File propertiesFile = new File("log.properties"); PropertyConfigurator.configure(propertiesFile.toString()); Logger logger = Logger.getLogger("simple"); logger.info("the program has started");