JOptionPane.showInputDialog("Введите новое имя:");
if (newName==null) newName="";
if (!newName.trim().isEmpty())
{
File newFile =
new File(nf.getParent()+"\\"+newName);
nf.renameTo(newFile);
JOptionPane.showMessageDialog(null,
"Файл переименован!","Сообщение",1);
}
}
else
{
JOptionPane.showMessageDialog(null,
"Файл не найден!","Ошибка",0);
}
}
}});
Опишем процесс переименования файла. Для начала работы с файлом, необходимо создать переменную типаFile, передать в переменную strпуть к нему. Очевидно, переменная nfпривязывается к этому файлу –она отвечает за файл, указанный пользователем.
Метод exists()определяет наличие файла, его существование (с англ. exists - существует. Если этот метод возвращает значение "Истина",выполняется конструкция, находящаяся в блоке if. Если же файл не существует, выполняется конструкция else.Файл можно переименовать, только при условии его существования на диске,поэтому проверка здесь необходима.
Если файл не существует,пользователю, как и в предыдущем случае,выводится сообщение: "Файл не найден!" – эта часть кода не меняется.
Но теперь нужно выполнить не удаление файла, а его переименование, строку, описывающую этот процесс, удаляем. После переименования файла, пользователю выводится другое сообщение: "Файл переименован!" – вносим изменения.
Перед выводом сообщения об успешном переименовании файла выполним эту операцию.
Сначала необходимо обратиться к пользователю, чтобы он указал новое имя для файла.
String newName =
JOptionPane.showInputDialog("Введите новое имя:");
Создадим переменную строкового типа, называем её newName, новое имя, в которую запишем новое имя, введенное пользователем. Запросим новое значение у пользователя с помощью диалогового окна.Для этого обратимся к классу JOptionPane, и вызовем методshowInputDialog().
В отличие от методаshowMessageDialog(), метод showInputDialog()позволяет пользователю ввести значение с клавиатуры.
Метод showMessageDialog() отображает сообщения пользователю, а метод showInputDialog()позволяет пользователю ввести значение, которое он хочет передать в программу.
Пользователь увидит окно, запрашивающее этот результат.Теоретически пользователь может ничего туда не ввести и просто закрыть окно. В этом случае переменная newNameне получит никакого значения. Чтобы это определить, надо записать конструкциюif, проверяющую,если newName равноnull. null– это пустое значение(получается, когда пользователь не ввел ничего, переменная newNameосталась пустой). В этом случае ей присваивается значение пустой строки.
Обратите внимание,значение null, т.е. пустое значение, и пустая строка – это не одно и то же.Пустая строка подразумевает, какое-то значение есть, но оно не содержит символов,а nullозначает полное отсутствие любого значения.
Далее осуществляется проверка: Значение выражения !newName.trim().isEmpty(),как и ранее, позволит проверить: пустая строка или нет. Если строка, введённая пользователем, не пустая,то переименуем файл. Иначе, если строка пустая - в этом случае делать ничего не нужно. Действие осуществляется, если пользователь ввёл какое-то имя. Поэтому в нашем случае мы проверяем обратное условие: если строка НЕ пустая, тогда выполняются какие-то действия. Чтобы обозначить признак отрицания (НЕ),нужно поставить вначале выражения символ:"!".
Наша конструкция работает следующим образом:
· Происходит обращение к введённой пользователем переменной newName.
· К этому методу применяется методtrim(), он срезает пробелы справа и слева.
· Применяется метод isEmpty(), который проверяет, пустое это значение или нет.
· Восклицательный знак выполняет отрицание, т. е. происходит проверка, что строка не пустая. Если строка не пустая,следует переход к переименованию файла.
Прежде, чем записывать программный код, запустим приложение на исполнение и посмотрим, что происходит при нажатии на кнопку. Допустим, пользователь вводит имя файла text.txt, нажимает на кнопку "Переименовать", ему выводится сообщение: "Файл не найден!".Метод exists()определил, что файла нет, он не существует, т.к. мы такой файл создали и удалили.
Создадим файл заново,воспользовавшись кнопкой "Создать новый" нашего приложения. Проверим, есть ли он на диске C:\. Действительно этот файл там появился.
Теперь переименуем его.Появляется окно, оно предлагает ввести новое имя файла (см. рис.9.24). Вводим произвольное имя файла с расширением .txt, и нажимаем кнопку "OK".
Рис. 9.24
В данном случае пользователь может поступить по-разному:может нажать крестик, и окно будет закрыто,может нажать кнопку "Отмена"и тоже ничего не ввести, а может просто ввести пустую строку, нажав кнопку "OK". Если он нажимает "Отмена", либо крестик,он не вводит никакого значения. В этом случае значение будет равно null.
Если же он введет пустую строку и нажмёт "OK", значение будет равняться пустой строке.
Переданное пользователем значение можно обработать программно.
Внутри конструкции,сделавшей проверку на отсутствие пустой строки, теперь есть какое-то имя, которое можно изменить, переименовать. Для этого надо создать еще одну переменную типаFile (назовём еёnewFile), создать объект, и, в качестве параметра в круглых скобках, передать значение,соответствующее новому имени файла. Это значение будет представлять собой путь к файлу плюс его имя.
File newFile =
new File(nf.getParent()+"\\"+newName);
Перейдём к примеру,разобранному в самом начале. Пусть у нас имеется некоторый путь к файлу: C:\Windows\regedit.exe.
Пользователь хочет переименовать файл с именем regedit.exe, находящийся на диске C: в папкеWindows.
Мы просим пользователя ввести новое имя файла, пользователь его вводит, например: temp.txt. Путь к файлу остаётся тот же самый – C:\Windows\,а имя файла уже новое. Таким образом, полный путь к файлу теперь такой: C:\Windows\temp.txt. Имя файла было введено пользователем в диалоговом окне.
Для создания файла,который нужно переименовать, следует указать новый путь к файлу с другим именем.
Обратимся к переменнойnf (она отвечает за исходный файл), и вызываем метод getParent() – получить родителя, т. е. получить родительский каталог, путь к родительскому каталогу. К этому значению добавляется косая черта, спецсимвол в языке Java (указывается\\, а реально прибавляется \ ), затем, новое имя файла, введённое пользователем. Это имя находится в переменной newName.
Эта операция называетсяконкатенацией,сложением строк. В этом случае строки склеиваются в одно целое. Почему между сложением двух переменных понадобилось также поставить косую черту? Потому, что метод getParent()возвращает путь к родительскому каталогу без наклонной черты в конце.
Вернёмся к примеру и посмотрим, что получает метод getParent().
Если исходный файлC:\Windows\regedit.exe, то метод getParent()вернёт C:\Windows. C:\Windows– это первая часть,которая будет участвовать в сложении строк.
Затем мы прибавили косую черту \.
Наконец, третья составляющая – новое имя файла.
Если пользователь указал temp.txt,именно это имя и добавится.
Таким образом, эти три составляющие будут складываться вместе, в сумме они склеиваются в единое целое, и получается новый путь к файлу.
Новый путь выглядит так:C:\Windows\temp.txt .
Вернёмся к программному коду. Теперь есть переменная newFile, она отвечает за новое название файла. Для выполнения переименования, обратимся к исходному файлу, хранящемуся в переменной nf, вызовем метод renameTo(), и в круглых скобках укажем новое имя. Новое имя у нас хранится в переменной newFile:
nf.renameTo(newFile);
Перейдём в корень дискаC:, убедимся, что там присутствует файл temp.txt.
Запустим приложение на исполнение, введем имя temp.txt, укажем к нему путь, нажмём кнопку "Переименовать".Получаем ответ: "Файл не найден!", т.к.неправильно указано название файла.
Указываем имя text.txt, нажимаем на кнопку "Переименовать"–предлагается ввести новое имя файла.
Введем новое имя файла,например, regedit.txt. нажмем на кнопку "OK", появляется сообщение: "Файл переименован!".
Перейдём в корень дискаC\:. Файл теперь называется regedit.txt. Таким образом, выполнено переименование файла.
Осталось реализовать ещё две кнопки: "Прочитать"и "Записать". Но это уже материал следующего занятия.
Занятие 10. "Работа с файловой системой из Java. Чтение и запись в файл"
На прошлом занятии мы начали работать с файловой системой, создали приложение, позволяющее выполнять основные операции с файлами. На этом занятии мы завершим работу с приложением, а попутно обсудим несколько новых аспектов работы с файловой системой.
Откроем и запустим приложение, cозданное на предыдущем занятии. Вспомним, что уже сделано на текущий момент.
Открывается окно, в верхнюю строку можно ввести путь к файлу.
Реализовано действие трёх кнопок –создание, удаление и переименование нового файла.
Осталось задействовать ещё две кнопки: "Прочитать"и "Записать"(см. рис.10. 1).
Рис. 10.1
Кнопка "Прочитать"будет выполнять считывание информации из файла и выводить её в окно –наше многострочное текстовое поле.
Кнопка "Записать"будет производить обратную операцию: содержимое многострочного текстового поля будет записываться в файл с указанным именем.
Но перед началом работы над реализацией приложения рассмотрим небольшой теоретический материал, который нам понадобится для работы с файлами и файловой системой. Для его изучения создадим новый, отдельный проект.
Выполняем привычные действия: Файл,Cоздать, ПроектJava. Назовём проект lesson22,нажмем кнопку "Готово". В списке проектов появляется новая папка, lesson22.Выделяем её, нажимаем правую клавишу, и в контекстном меню выбираем команду "Создать",в появившемся списке выбираем пунктКласс.
Визуальная обработка здесь использоваться не будет, поэтому выбираем обычный класс, называем егоprog, ставим галочку public static void main, нажимаем кнопку "Готово".Появляется знакомая заготовка. Все комментарии можно удалить.
Добавим библиотеку,которая будет выводить окна JFrame.
import javax.swing.*;
Под основным классомprog, создадим новый класс. Назовём его myFrameи выполним наследование от класса JFrame (JFrame–класс окон, мы его уже неоднократно использовали). Словоextendsговорит о наследовании: класс myFrameнаследуется от класса JFrame.
class myFrame extends JFrame
{
}
Одна эта запись сразу наделяет класс myFrameвсеми возможностями и свойствами класса JFrame.
Если в методе mainсоздать переменную типа myFrameи создать новый объект myFrame, это равносильно созданию объекта на основании классаJFrame.
import javax.swing.*;
public class prog {
public static void main(String[] args) {
//Создание объекта на основании классаmyFrame
myFrame ob1 = new myFrame();
//Создание объекта на основании классаJFrame
JFrame ob2 = new JFrame();
}
}
class myFrame extends JFrame
{
}
Рассмотрим представленный программный код. В нем были созданы две переменные: ob1и ob2.
Первая переменная, типаmyFrame, - имя только что созданного класса, который наследуется от класса JFrame.
Вторая переменная типаJFrame–это тип окно.
Эти две строки равноценны, Т. к. класс myFrameнаследуется от класса JFrameПоэтому он наделяется всеми возможностями и характеристиками класса JFrame. Используя переменные ob1 иob2, можно делать абсолютно идентичные действия, эти два класса равноценны.
Если внутри классаmyFrameдобавить новый функционал, в отличие от обычного класса JFrame,класс myFrame будет обладать дополнительными возможностями.
Таким образом, мы настраиваем уже имеющийся класс JFrameпод свои конкретные задачи. Создадим конструктор класса myFrame.
class myFrame extends JFrame
{
// Конструктор классаmyFrame
public myFrame(int val)
{
setBounds(0,0,500,400);
setVisible(true);
}
}
Конструктор класса имеет такое же наименование, как имя класса, он не возвращает никакого значения.Конструктор классавсегдаоткрытый,public.
При создании объекта,если нужно передать какое-либо значение внутрь класса, в его конструкторе можно создать специальную переменную. Здадим переменную целого типа под названиемval.
public myFrame(int val)
Таким образом, при создании объекта на основании классаmyFrameможно передать ему некоторое значение через круглые скобки. Например, значение 100. Это значение можно передать при создании объекта:
// Создание объекта на основании класса myFrame
myFrame ob1 = new myFrame(100);
Обратите внимание, что теперь при создании объекта мы передаем значение. Вспомним, при создании объекта конструктор выполняет стартовые действия, своего рода настройку(инициализацию). Настройки могут быть разные, в зависимости от объекта, к которому они относятся.
В данном случае речь идёт об окне, значит, в настройке задаются размеры окна. Если вызвать метод setBounds, можно указать первые два значения, координаты верхней левой точки окна, ширину и высоту окна,например, 500и400. Для отображения окна на экране нужно вызвать метод setVisibleсо значением true (Истина). Создание объекта типа myFrameнедостаточно для отображения окна на экране. Для того чтобы оно появилось на экране, необходимо вызвать метод setVisible.
Запустим приложение на исполнение. Появилось окно, его расположение позиционируется, начиная от точки (0,0). В этой точке находится угловая верхняя левая точка окна, т. е. окно начинается от угла экрана. 500пикселей –ширина и 400–высота окна.
Обратите внимание на строку, записанную в левой части myFrame, в круглых скобках указано значение 100.
myFrame ob1 = new myFrame(100);
Это и есть вызов конструктора, т. е. конструктор вызывается при создании объекта. При необходимости,если потребуется в задаче, конструктору можно передать некоторые значения.
В данном случае, через круглые скобки передаётся значение100,следовательно, переменная valпринимает значение100. Вместо координат xиyможно указать переменную val,тогда при запуске окно позиционируется по отступу 100и100слева и сверху, т. к., вместо конкретных значений указана переменная val.
class myFrame extends JFrame
{
// Конструктор классаmyFrame
public myFrame(int val)
{
setBounds(val,val,500,400);
setVisible(true);
}
}
Переменная valможет иметь разные значения при создании объекта. Если задать ей значения, например, 300, отступы сверху и слева при создании окна теперь будут равны по 300.Таким образом, если передать некоторое значение переменной конструктору класса,можно присваивать это значение, применяя конструктор.
Для получения доступа к текущему объекту можно использовать конструкцию this.Слово this (с англ.) означает "этот" (объект). Если указано this,происходит обращение к текущему объекту,создаваемому на основании этого класса, в данном случае к окну. Обращаясь к нему через оператор "точка" (.) , можно обращаться ко всем свойствам и методам объекта.Таким образом, можно записать следующее:
this.setBounds(val, val, 500, 400);
setBounds(val, val, 500, 400);
Такие две строки программного кода совершенно равноценны. В первом случае используется служебное слово this, а во втором случае –нет. Если слово thisне указывается, то умолчанию считается, что происходит обращение к свойствам и методам именно этого класса. В круглых скобках методаsetBounds, указаны параметры, valиval (ширина и высота).
В некоторых случаях слово thisнеобходимо указывать явно. Например:объявляется переменная класса, закрытая,целого типа, под названием val.
// Объявляется переменная класса
private int val;
Этой переменной нужно присвоить значение, передаваемое через конструктор.
class myFrame extends JFrame
{
// Объявляется переменная класса
private int val;
// Конструктор классаmyFrame
public myFrame(int val)
{
// Присвоение значения,передаваемого
// через конструктор
this.val = val;
setBounds(val,val,500,400);
this.setBounds(val, val, 500, 400);
setVisible(true);
}
}
Обратите внимание,название переменной, указанное в конструкторе, и название переменной класса одинаковы, но, несмотря на этот факт, это две различные переменные. Допустим, через конструктор класса передаётся некоторое значение, его нужно присвоить переменной класса с тем же названием. Если написать:
val = val;
возникает некоторая путаница: неясно, какая именно из этих переменных valявляется переменной класса, а какая передаётся через конструктор. Для устранения путаницы перед переменной класса можно использовать слово this:
this.val = val;
Переменная this.val–переменная,объявленная как переменная класса, а переменная, записанная в правой части–та, которая передаётся через круглые скобки. При помощи слова thisудалось явно различить эти переменные и устранить неясность. Таким образом:слово thisявно указывается для идентификации разных элементов программного кода, имеющих одинаковое название.
Приведем еще один пример. Пусть записаны две строки:
this.setBounds(val, val, 500, 400);
this.setVisible(true);
Здесь явно указано, к какому объекту принадлежат вызываемые методы. Метод setBoundsи метод setVisibleвызываются относительно объектаthis (этот).Некоторые программисты, несмотря на то, что слово thisможно явно не указывать, все равно используют его, т. к. становится более понятно,относительно какого объекта вызывается тот или иной метод.
В определённых случаях слово thisуказывается обязательно, для устранения неоднозначности в программном коде.
Для обозначения пустых значений используется служебное словоnull (пустое). Мы его уже использовали.
Удалим программный код в методе mainи вместо него добавим следующее:
public static void main(String[] args) {
myFrame ob1 = null;
ob1 = new myFrame(300);
}
Создаем переменную типа myFrame, окно.Этому окну задаютсянекоторые характеристики в конструкторе класса. Окно является видимым. В самом начале, после создания переменной, ей было присвоено значение под названием null (пустое). Заметьте,null не равен нулю и не равен пустой строке!
Разберёмся, зачем необходимо слово null,для чего оно используется.
Сначала переменная только объявляется: она объявляется один раз, указывается её тип. Затем идет работа с этой переменной, при повторном её использовании указывается только имя переменной. Вторая строка у нас следующая:
ob1 = new myFrame(300);
Через круглые скобки в конструктор передано значение 300. Объявленной переменной присвоено значение null(первой строкой),значит, пока никакого объекта в памяти ещё нет. Во второй строке создаётся объект и связывается с этой переменной.
Когда объявляется переменная ob1, в оперативной памяти компьютера выделяется небольшое пространство, за ним закрепляется имя (см. рис.10.2).
Рис. 10.2
Пространство,выделенное переменную, носит такое же название, в нашем случае –ob1.
Во второй строке происходит обращение к переменной ob1и после знака равенства записана командаnew myFrame(300) В этот момент, в оперативной памяти создаётся объект, т. е., выделяется некоторое пространство оперативной памяти, в котором хранится вся информация, связанная с этим объектом.
Знак равенства записывает в переменную ob1адрес, по которому хранится этот объект в оперативной памяти компьютера. Переменная под названиемob1начинает ссылаться на объект myFrame, т.к. она содержит адрес объекта (см. рис.2).
Итак, образуются две составляющие: первая –небольшая область памяти,выделенная для переменной ob1и вторая - большая область памяти, в которой создаётся объект (см. рис. 2).Переменная, подобная ob1,называется ссылкой.
В нашем случае переменная ob1является ссылкой на объект, созданный при помощи команды new. Слово nullиспользуется для указания на то, что переменная-ссылка не ссылается ни на какой объект. Например запись в строке:
myFrame ob1 = null;
означает,что переменная не ссылается ни на какой объект, она равна значению null.
Таким образом, null–это своего рода метка, при помощи которой помечается переменная-ссылка, которая не ссылается ни на какой объект. Поэтому значение nullне равно нулю, или,например, пустой строке, это другое понятие.
После выполнения второй строки переменной ob1 присвоено значение:
ob1 = new myFrame(300);
После присвоения значения она уже не равна null, т. к. начинает ссылаться на некоторый объект в оперативной памяти.
Ну, а теперь вернёмся к основному проекту, который мы начали на прошлом занятии.
Автоматизируем кнопку"Записать",отвечающую за запись в файл информации,введенной в текстовое поле. Имя файла, в который нужно записать информацию,вводится в текстовое поле "Укажите путь к файлу:".
Сначала этот файл нужно создать. Сделать это можно при помощи кнопки "Создать новый". Создадим этот файл в корне дискаC:\, назовем егоtemp.txt. (см. рис. 10.3).
Рис. 10.3
Переходим в корень диска C:\и проверяем: файл temp.txtдействительно появился на дискеC:\.
Прежде, чем выполнять запись в файл, посмотрим, что может храниться внутри каждого файла.
Откроем только что созданный файл в Блокноте. Внутри файла пока ничего нет,размер файла 0байт (см. рис. 10.4).
Рис. 10.4
Занесём в файл один символ (см. рис. 10.5) и сохраним файл.
Рис. 10.5
Откроем свойства файла.Размер файла 1байт (см. рис. 10.6).
Рис. 10.6
Таким образом, делаем вывод, что каждый символ, хранящийся внутри файла, занимает 1байт.
В свойствах, однако,видно, что, что файл, содержащий один символ, на диске занимает сразу 4килобайта (4096байт), а не 1 байт.
Это обусловлено тем, что данные на диске хранятся некоторыми порциями. Даже если файл занимает всего 1байт, под него выделяется фрагмент размером, как минимум, 4килобайта. Содержимое файла в этом случае все равно представляет собой 1 байт.
Если сделать перевод строки: перевести курсор на следующую строку и сохранить файл, в свойствах видно– файл занимает3байта. Таким образом, любой символ, включая перевод строки, также является символом.
В тот момент, когда делается перевод строки, в файл записываются ещё два символа, просто визуально их не видно. Символы следующие:символ перевода строки (клавиша Enter) и возврат каретки,возврат курсора в самое начало строки. На эти символы и выделяются два дополнительных байта.
Каждый символ имеет свой код–номер, находящийся в диапазоне от 0до 255.
Например, буква dимеет код 100; пробел,отображаемый просто отступом, имеет код32;восклицательный знак –33. Цифра 0имеет код 48, клавиша Enter–код 13.
Буквы русского алфавита тоже имеют коды, но, если буквы английского алфавита всегда имеют чётко закреплённый за ними, конкретный код, с русскими буквами картина сложнее. Существует несколько вариантов русских кодировок, поэтому одна и та же русская буква может иметь разный код.
Вспомним, 1байт содержит 8бит, 8разрядов, или ячеек двоичного кода.
В 1байт можно поместить число от0до 255, поэтому, когда в файл записывается хотя бы один символ,записывается порция размером в 1байт, а точнее, код этого символа.
Если ввести в блокноте строку: Hello - она содержит шесть символов, значит, файл будет занимать 6 байт.
Сделаем перевод строки.Файл занимает уже 8байт, на перевод строки выделяется ещё 2байта, в которые помещаются коды 13и 10. Код 13–код клавиши Enter, перевод строки;код 10–возврат каретки,возврат курсора на начало строки.