一、概述
运用图形界面工具实现文本文档的界面,再通过I/O流进行文件的读取和保存,以此实现文本文档的新建、保存、打开、另存外等功能。
二、具体实现
新建一个名为notepad的java项目。
1.新建util包
util包中用来存放一些静态的工具方法。这里存放两个文件选择器,分别为文件打开选择器和文件保存选择器。
代码如下:
package util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
public class FileChoose {
private static final String path = ".";// 表示当前目录
public static void main(String[] args) {
new FileChoose();
}
public FileChoose() {
// System.out.println(getFileChoose());
System.out.println(saveFile());
}
/**
* 文件选择
*/
public static File getFileChoose() {
JFileChooser jf = new JFileChooser(path);// 实例化文件选择器
/*
* 设置可选类型 参数有三个 分别为
* •JFileChooser.FILES_ONLY 仅仅选择文件
* •JFileChooser.DIRECTORIES_ONLY 仅仅选择目录
* •JFileChooser.FILES_AND_DIRECTORIES 既选择文件又选择目录
*/
jf.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
// 设置文件过滤,会覆盖原有过滤
jf.setFileFilter(new FileFilter() {// FileFilter 为抽象类
// 注意:这个不是实例化FileFilter类 , 这是采用内部类的方式
@Override
public String getDescription() {// 显示为指定后缀名的文件
return ".java";
}
@Override
public boolean accept(File f) {// 判断文件是否以java结尾
if (f.getName().endsWith("java")) {
return true;
} else {
return false;
}
}
});
//添加文本文件过滤
jf.addChoosableFileFilter(new FileFilter() {// FileFilter 为抽象类
// 注意:这个不是实例化FileFilter类 , 这是采用内部类的方式
@Override
public String getDescription() {// 显示为指定后缀名的文件
return ".txt";
}
@Override
public boolean accept(File f) {// 判断文件是否以txt结尾
if (f.getName().endsWith("txt")) {
return true;
} else {
return false;
}
}
});
jf.showOpenDialog(null);// 设置打开时的窗口 null表示没有父窗口
return jf.getSelectedFile(); // 返回得到选择器选择的文件
}
//文件保存
public static File saveFile() {
//弹出文件选择框
JFileChooser chooser = new JFileChooser();
//后缀名过滤器
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"文本文件(*.txt)", "txt");
chooser.setFileFilter(filter);
chooser.setSelectedFile(new File("*.txt"));//初始化文件名
//下面的方法将阻塞,直到【用户按下保存按钮且“文件名”文本框不为空】或【用户按下取消按钮】
int option = chooser.showSaveDialog(null);
if(option==JFileChooser.APPROVE_OPTION){//假如用户选择了保存
File file = chooser.getSelectedFile();
String fname = chooser.getName(file);//从文件名输入框中获取文件名
// while(fname.indexOf("*") == -1)
//假如用户填写的文件名不带我们制定的后缀名,那么我们给它添上后缀
if(fname.indexOf(".txt") == -1){
file=new File(chooser.getCurrentDirectory(),fname+".txt");
}
return file;
}
return null;
}
}
2.新建service包
service包用来存放逻辑层的代码,这里新建了一个输入流和一个输出流的接口并进行实现。
a.输入流接口
package service;
public interface Input {
//打开文件,并获取内容
String[] getFile() throws Exception;
}
b.输入流接口实现
package service;
import java.io.File;
import java.io.FileInputStream;
import util.FileChoose;
public class InputImpl implements Input{
@Override
public String[] getFile() throws Exception {
//从文件选择器获取文件
File file = FileChoose.getFileChoose();
//文件内容读取
FileInputStream ips = new FileInputStream(file);
byte[] bt = new byte[1024];//创建直接数组用来读取文件内容
StringBuffer s = new StringBuffer();//创建字符串流将读取的字符串合并
String[] strArray = new String[2];//存储文件名和文件读取内容
int len;
while((len = ips.read(bt)) != -1) {
String str = new String(bt,0,len);//将读取的字节转换为字符串
s.append(str);
}
ips.close();
strArray[0] = file.toString();
strArray[1] = s.toString();
return strArray;
}
}
c.输出流接口
package service;
public interface Output {
//新建一个文件并将内容保存到新建文件中
void createAndSave(String text) throws Exception;
//保存文件
void saveFile(String fileName,String text) throws Exception;
}
d.输出流接口实现
package service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import util.FileChoose;
public class OutputImpl implements Output{
@Override
public void createAndSave(String text) throws Exception {
File newFile = FileChoose.saveFile();//从文件选择器中获取文件
if(newFile != null){//如果文件不为空
newFile.createNewFile();//创建文件
byte[] bt = text.getBytes();
FileOutputStream ops = new FileOutputStream(newFile);
ops.write(bt,0,bt.length);
ops.close();
}
}
@Override
public void saveFile(String fileName,String text) throws Exception {
FileOutputStream ops = new FileOutputStream(new File(fileName));
byte[] bt = text.getBytes();
ops.write(bt,0,bt.length);
ops.close();
}
}
3.图形界面设计
新建一个用来存放图形界面的名为view的包,并创建一个Notepad类,作为文本文档的主要界面,并根据功能需求添加监听事件,并实现。
代码如下:
package view;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import service.Input;
import service.InputImpl;
import service.Output;
import service.OutputImpl;
import java.awt.Toolkit;
import javax.swing.JMenu;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.SwingConstants;
import javax.swing.BoxLayout;
import java.awt.GridLayout;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTextArea;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Notepad extends JFrame {
private String fileName = null;
Output op = new OutputImpl();//输出流对象
Input in = new InputImpl();//输入流对象
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Notepad frame = new Notepad();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Notepad() {
getJFram();
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//防止新窗口和旧窗口一起关闭
}
/**
* 初始化窗体的构造
*/
private void getJFram() {
setIconImage(Toolkit.getDefaultToolkit().getImage("images\\图片1.png"));
setTitle("记事本");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 729, 553);
JTextArea textArea = new JTextArea();
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu mnNewMenu = new JMenu("文本(F)");
menuBar.add(mnNewMenu);
JMenuItem mntmNewMenuItem = new JMenuItem("新建(N)");
//给新建选项设置监听事件
mntmNewMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
create(textArea);
}
});
mnNewMenu.add(mntmNewMenuItem);
JMenuItem mntmNewMenuItem_1 = new JMenuItem("新窗口(W)");
//给新窗口添加监听事件
mntmNewMenuItem_1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Notepad().setVisible(true);
}
});
mnNewMenu.add(mntmNewMenuItem_1);
JMenuItem mntmNewMenuItem_2 = new JMenuItem("打开(O)");
//给打开添加监听事件
mntmNewMenuItem_2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String text;
try {
text = getFile();
textArea.setText(text);
} catch (Exception e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
});
mnNewMenu.add(mntmNewMenuItem_2);
JMenuItem mntmNewMenuItem_3 = new JMenuItem("保存(S)");
//给保存添加监听事件
mntmNewMenuItem_3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
save(textArea.getText());
}
});
mnNewMenu.add(mntmNewMenuItem_3);
JMenuItem mntmNewMenuItem_4 = new JMenuItem("另存外(A)");
//给另存外添加监听事件
mntmNewMenuItem_4.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
otherSave(textArea.getText());
}
});
mnNewMenu.add(mntmNewMenuItem_4);
JMenu mnNewMenu_1 = new JMenu("编辑(E)");
menuBar.add(mnNewMenu_1);
JMenu mnNewMenu_2 = new JMenu("格式(O)");
menuBar.add(mnNewMenu_2);
JMenu mnNewMenu_3 = new JMenu("查看(V)");
menuBar.add(mnNewMenu_3);
JMenu mnNewMenu_4 = new JMenu("帮助(H)");
menuBar.add(mnNewMenu_4);
JPanel panel = new JPanel();
GroupLayout groupLayout = new GroupLayout(getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(panel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(panel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 493, Short.MAX_VALUE)
);
GroupLayout gl_panel = new GroupLayout(panel);
gl_panel.setHorizontalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addComponent(textArea, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)
);
gl_panel.setVerticalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addComponent(textArea, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 493, Short.MAX_VALUE)
);
panel.setLayout(gl_panel);
getContentPane().setLayout(groupLayout);
}
//另存外当前内容
private void otherSave(String text) {
if(text != null && !text.equals("")) {
//如果当前文件内容不为空
//新建文件并保存
try {
op.createAndSave(text);
} catch (Exception e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
}
//保存当前内容
private void save(String text) {
if(this.fileName != null && text != null && !text.equals("")) {//如果当前内容为打开文件内容,则文件名不为空
try {
op.saveFile(fileName, text);
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}else {//否则就保存进一个新文件中
if(text != null && !text.equals("")){
//如果当前文件内容不为空
//新建文件并保存
try {
op.createAndSave(text);
} catch (Exception e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
}
}
/**
* @param textArea
*新建文件
*/
private void create(JTextArea textArea) {
String text = textArea.getText();//获取文件内容
if(text != null && !text.equals("")){
//如果当前文件内容不为空
//保存当前文件并打开一个新窗口
save(text);
new Notepad();
}
}
/*
* 打开文件
* */
private String getFile() throws Exception {
String[] file = in.getFile();
this.fileName = file[0];
return (file[1] == null) ? "" : file[1];
}
}
三、测试
1.测试打开文件
我在桌面新建了一个txt文件,并适当添加了内容,如下:
现在通过java编写的文本文档打开并获取此文档内容。
选择打开,如下:
然后找到目标文件:
结果如下:
2.测试修改后保存
接着上面内容,先修改内容,在进行保存,如下:
重新打开记事本文件,会发现内容已经被修改,如下:
3.测试文件另存外
继续接着上面内容,点击文件另存外:
选择目标路径,输入新建文件名称,当文件名不包含后缀时默认使用txt作为后缀,如下:
点击保存后,可以发现桌面以及多出来了一个新文件,如下:
其内容为测试文件1中的内容,如下:
四、部分功能说明
1.关于新建
当文本内容为空时,不做任何处理,否则会保存当前文本内容,然后再打开一个新窗口。
2.关于保存
若当前窗口的文本框内容是来源于打开其他文件获取的内容时,修改其内容后直接可以保存,若非从其他文件打开获取的内容,则保存时需要选择保存路径和保存文件的文件名称。
3.关于打开新窗口
点击打开新窗口,则会在原来的窗口上弹出一个新窗口,两者相互不影响。