分享

java学习---流、JFileChooser

 iversion 2007-05-22

java学习第八周总结(2) ---流、JFileChooser

这两天主要学习内容是java的I/O操作。I/O(输入/输出)是每个程序必须具备的。因此这个知识点也是作为一名程序员必须掌握的,由此可见它的重要性。虽然我们学习java1个多月以来,今天才开始正式的接触到I/O,但是之前我们的程序中也或多或少使用到了它,只是那个时候对它的概念还比较模糊而已。也正式由于它的重要性,因此它所涉及的面也非常的广,对于我们这些初学java的程序员来说要全面,透彻的了解它和掌握它也不大可能。学习本来就是一个循序渐进的过程,切忌好高骛远。要脚踏实地,不断的发现问题、解决问题,积累经验,这样才能更深刻地理解和掌握这一门语言,而不仅仅是熟练,或者所谓的精通某某技术。

今天主要总结两点:流(Stream)的概念和JFileChooser的用法。再深入点的内容我也仅仅只有点概念性的东西,没能完全理解,只有在今后不断实践中再总结经验。

一、流(Stream)
1、什么是流
当数据源需要将数据传输到某个目标的时候,那么他们之间就应该建立一个连接,这个连接我们就称之为流。比如当我们在一个程序中需要读取磁盘上某个文件时,这时文件就相当于目标,运行中的程序就相当于数据源,我们需要把目标的数据读入到程序中来,就是通过流作为中间媒介传输这些数据的。因此我们有个类FileInputStream.同样,当我们需要将程序中的某些数据输出到磁盘文件中时,那么这个时候程序就相当于数据源,文件就是目标。并在他们中间建立一个供数据传输的连接---流,也有个类FileOutputStream。这两个类是基于字节的文件读入写出流,稍候会看到他们的用法。由此我们可以看到,流一般分为两种,读取流(input)写入流(output)。

2、为什么需要流
我们知道,象I/O这类的操作其实是比较底层的,而且操作也是非常的烦琐,这个也不符合java语言的特点。因此就提出了流这个概念,并将一些比较底层的I/O数据操作封装起来,通过流这个概念来理解它,操作它。这样可以降低我们程序的复杂度,同时避开了更多的与系统底层打交道,提升了程序的可读性与可维护性。

3、什么地方需要使用流
当我们需要在数据源与目标之间读取或者写入数据时,就要在他们之间建立流连接。这就象我们电脑中的硬盘一样,我们要使用硬盘,读取或者写入数据,首先要将硬盘同电脑的主板连接起来,那么主板与硬盘之间就有一条数据线起到连接的作用,通过数据线来写入或者读取数据。这个数据线就相当于流的作用。

4、怎样建立流
明白了什么是流之后就需要建立流。那么如何建立呢,在java的基础类库中,提供了两种IO包来操作流,一种就是经常会使用到的java.io包,还有一种是jdk1.4引入的新IO包java.nio.*,这个包基本上是对原IO包进行了重新封装,以便提供更快的速度。新的IO包还没接触过,因此目前还是以旧的IO包来进行总结。虽然IO包中的类很多,但是很容易就能看出他们之间的规律。根据操作的数据类型基本上可以划分为三个层次

(1)基于字节输入输出,如InputStream/OutputStream
(2)基于字符输入输出,如Reader/Writer
(3)基于对象输入输出,如ObjectInputStream/ObjectOutputStream

由上面可以看出,基本上针对字节操作的类都是以Stream结尾的,针对字符操作的类则是以Reader或者Writer作为结尾。这样划分下来,就会减轻不少的API学习量。
针对字节和针对字符操作的类在使用上都很相似,怎么在这两者之间进行选择呢。由于操作字节还是比较底层的操作,因此一般在非必须使用字节操作的时候,尽可能的使用基于字符的输入输出。

基本上进行读取或者写入操作的时候按照下面五个步骤:
(1)首先要明确是需要读取还是写入操作,从而选择是使用Input/Output或者Reader/Writer
(2)明确操作的目标是什么,文件或者缓存、对象等等,从而选定具体操作的类
(3)选定好了类之后,我们就需要创建该类的对象,创建对象时一般是通过传入该类构造器的参数来建立流连接。
(4)完成读和写的操作。一般这些类当中都有read()或者write()方法,一个是读入流的方法,一个是写入流的方法。
(5)最后要使用close()关闭流连接,刷新缓存,释放资源。

根据这5个步骤,下面写个小程序来试验一下对文件的读去和写入操作。

/*从磁盘中以字节方式读取名为ball.jpg图片,并建立起之间的读取流*/
FileInputStream input = new FileInputStream("image/ball.jpg");
/*创建copyball.jpg图片格式文件,建立起之间的写入流*/
FileOutputStream output = new FileOutputStream("image/copyball.jpg");
int i;
//使用循环进行逐一读取其中的字节到读取流,转换成整型返回,同时将数据写入到写入流中,当下一个字节没有数据时,将返回-1,由此来跳出循环
while((i = input.read())!= -1)
{
 output.write(i);
}
//最后关闭读取和写入流。
input.close();
output.close();

关于随机访问以及对象的读取和写入下次再总结。

下面总结一下JFileChooser的用法
在看JFileChooser之前,先了解一下File这个文件类,其实更贴切点说应该叫文件路径类。因为这个类不仅可以实现对文件的操作,还可以对目录进行相关的操作。
可以把File类看作是对文件和目录的一个实用工具类。他里面有许多有用的方法,首先来看下他的构造方法:
要创建File对象必须要先创建它的对象,并且构造方法需要带参数。他一共有4个构造方法,一般比较常用的是下面三种:

//根据File对象parent的路径和字符串child连接起来形成个新的字符串,并将其作为新File的路径名字字符串
File(File parent, String child)
//根据字符串pathname作为路径名字创建新的File对象
File(String pathname)
//根据字符串parent和child作为路径名字创建新的File对象
File(String parent, String child)

比较常用的方法:
boolean canRead() 判断文件是否可读
boolean canWrite() 判断文件是否可写
int compareTo(File pathname) 按字母顺序比较两个File对象的路径
boolean delete() 删除目录或者文件
boolean exists() 测试此文件或目录是否存在
File getAbsoluteFile() 返回抽象路径的File对象
String getAbsolutePath()  返回绝对路径
String getName()  返回该文件或目录的名字
String getParent()  返回该抽象路径的父路径名,如果没有父路径则返回null
String getPath() 将抽象路径名转换为字符串]
boolean isAbsolute() 判断该抽象路径是否是一个绝对路径
boolean isDirectory() 判断是否为目录
boolean isFile() 判断是否为文件
boolean isHidden() 判断是否为隐藏
long lastModified() 获得最后一次修改的时间,该时间是一个毫秒数
long length() 获得文件的长度
String[] list() 将该抽象路径下的所有文件和目录路径名字符串包存在一个字符串数组中。这个方法非常有用。
 
其实JFileChooser基本使用方法还是很简单的,下面写两个示例看了就明白了,如果还要增加一些功能,我们还可以添加过滤器,只显示过滤后的文件。还可以再保存的时候,如果保存的是目录里已经存在的文件,那么对话框不会关闭,并且弹出一个JOptionPane提示用户是否保存文件。

打开文件对话框:

import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;

public class FileChooserTest {

  public static void main(String [] args) {

  //首先是创建JFileChooser 对象,里面带个参数,表示默认打开的目录,这里是默认打开当前文件所在的目录。

  JFileChooser file = new JFileChooser (".");
  //下面这句是去掉显示所有文件这个过滤器。
  file.setAcceptAllFileFilterUsed(false);
  //添加excel文件的过滤器
  file.addChoosableFileFilter(new ExcelFileFilter("xls"));
  //添加exe文件的过滤器
  file.addChoosableFileFilter(new ExcelFileFilter("exe"));

  /*使用showOpenDialog()方法,显示出打开选择文件的窗口,当选择了某个文件后,或者关闭此窗口那么都会返回一个

整型数值,如果返回的是0,代表已经选择了某个文件。如果返回1代表选择了取消按钮或者直接关闭了窗口*/
  int result = file.showOpenDialog(null);

/*JFileChooser.APPROVE_OPTION是个整型常量,代表0。就是说当返回0的值我们才执行相关操作,否则什么也不做。
  if(result == JFileChooser.APPROVE_OPTION)
  {

 /*获得你选择的文件绝对路径。并输出。当然,我们获得这个路径后还可以做很多的事。
   String path = file.getSelectedFile().getAbsolutePath();
   System.out.println(path);
  }
  else
  {

    System.out.println("你已取消并关闭了窗口!");
   }
 }

/*因为我们需要创建一个文件的过滤器,以便让文件对话框显示我们指定的文件。这里我们就以Excel文件和exe文件举例。

那么要做到这点我们就需要重写FileFilter 类的accept来设置相关的过滤器。这个继承类你可以写成外部类、内部类甚至是

匿名内部类。我这里写成了一个内部类的形式。因为是在main方法使用他,因此这个类也要定义成 静态的。

private static class  ExcelFileFilter extends FileFilter {

  String ext;

  //构造方法的参数是我们需要过滤的文件类型。比如excel文件就是 xls,exe文件是exe.

  ExcelFileFilter(String ext) {

   this.ext = ext;
  }

/*这个方法就是重写 FileFilter 类的方法,参数是File对象,一般这个参数是如何传入的我们可以不用关心。他返回一个布尔型。如果为真表示该文件符合过滤设置,那么就会显示在当前目录下,如果为假就会被过滤掉。

  public boolean accept(File file) {

  //首先判断该目录下的某个文件是否是目录,如果是目录则返回true,即可以显示在目录下。

   if (file.isDirectory())
   {
    return true;
   }

  //获得某个文件的文件名,然后使用lastIndexOf()来获得这个文件名字符串中‘.‘这个字符最后一次出现的位置。并且通过它返回的一个整型来判断该文件是否符合*.*这中文件+文件名的格式,如果不符合那么就不显示这个文件。如果符合,那么就将‘.‘字符后面的字符串提取出来与过滤的文件名相比较,如果相等则符合该文件格式,并显示出来。如果不相等那么就将其过滤掉。*/

   String fileName = file.getName();
   int index = fileName.lastIndexOf(‘.‘);

   if (index > 0 && index < fileName.length() - 1)
   {
    String extension = fileName.substring(index + 1).toLowerCase();
    if (extension.equals(ext))
     return true;
   }
   return false;
  }

/*这个方法也是重写FileFilter的方法,作用是在过滤名那里显示出相关的信息。这个与我们过滤的文件类型想匹配,通过这些信息,可以让用户更清晰的明白需要过滤什么类型的文件。*/ 

  public String getDescription() {

   if (ext.equals("xls"))
   {
    return "Microsoft Excel文件(*.xls)";
   }
   if(ext.equals("exe"))
   {
    return "可执行文件(*.exe)";
   }
   return "";
  }
 }
 
 }

 

打开选择文件的对话框就建立好了。但是上面的程序还有瑕疵。因为只有当用户点取消或关闭该窗口时才不会执行任何操作。而如果用户在对话框里输入的文件在当前目录中不存在时,那么窗口依然会关闭,这时可能就需要在程序中再来做判断。那么可不可以在当用户输入错误的文件名后,窗口不会关闭,而是不执行任何操作或者弹出个对话框提示用户,可以看看大多数window程序中的选择对话框都是这么做的,其实要实现这个功能也不难, 只需要再重写一下JFileChooser类的approveSelection()方法就行了。

我们将上面的程序做下修改,首先还是需要创建一个继承于JFileChooser的类,这个类可以写成外部或者内部类,我们这里依然写为内部类,注意,如果需要在静态方法中调用它,则需要将它设置为静态的。

private static class MyChooser extends JFileChooser {
  MyChooser(String path) {
   super(path);
  }

  /**
   * 重载JFileChooser的方法,当在文件选择对话框中,并在当前
   * 目录下没有找到输入的文件,则对话框不会关闭。直到选择的文件 在当前选择的目录下,才关闭对话框,并执行后面的操作。
   */
  public void approveSelection() {

   File file = new File(getSelectedFile().getPath());

 if (file.exists())
    super.approveSelection();
   else
    JOptionPane.showMessageDialog(null, "你选择的文件不存在,请重新选择!");

}

把上面这段代码添加进刚才的类里面,然后把

JFileChooser file = new JFileChooser (".");改成

JFileChooser file = new MyChooser (".");

好了,现在我们就可以在不关闭该对话框的情况下判断用户的输入是否错误了。还可以加入正则表达式,判断用户输入是否符合规定,操作方式按照这个框架来写就没问题了。这里不再赘述。下面是保存对话框!

保存对话框:

其实保存对话框和打开文件对话框在使用上没什么区别,他们都是使用同一个类JFileChooser,因为在swing当中打开和保存对话框不会做出任何对文件进行处理的功能,所有的这些功能需要我们自己去实现,而仅仅是提供了1个这样的窗口模型而已。因此这两种窗口其实只是将按钮的标签进行了替换而已 。创建他们唯一的区别就是打开是调用showOpenDialog()方法,保存则是调用showSaveDialog(),创建形式几乎一样。我们在使用他们的时候就需要分别对这两种窗口的返回后进行不同的处理,设置过滤器是一样的,因此过滤器我们就复用上面打开文件窗口的方法,但是在判断输入保存文件是否在当前目录下时,我们需要做出不一样的处理。当用户输入了与当前目录相同的文件名后,要弹出对话框询问用户是否需要覆盖原文件,如果用户选择否,那么返回保存文件的对话框允许用户继续选择或者输入保存的文件名。

下面我只需要修改上面代码的两个地方就能够达到目的。首先将修改一下MyChooser这个类

private static class MyChooser extends JFileChooser {
  MyChooser(String path) {
   super(path);
  }

/*同样是覆盖approveSelection方法,首先获得输入文件的路径,然后判断其是否在当前目录下,如果存在,那么弹出对话框询问是否需要覆盖当前文件,如果选择取消,则回到保存对话框,用户可以继续进行保存的操作。*/
  public void approveSelection() {
   File file = this.getSelectedFile();
   if (file.exists())
   {
    int copy = JOptionPane.showConfirmDialog(null,
      "是否要覆盖当前文件?", "保存", JOptionPane.YES_NO_OPTION,
      JOptionPane.QUESTION_MESSAGE);
    if (copy == JOptionPane.YES_OPTION)
     super.approveSelection();
   }
   else
    super.approveSelection();
  }
 }

再把上面的

int result = file.showOpenDialog(null);

改成

int result = file.showSaveDialog(null);

两个基本的选择文件对话框就创建完成了。

如果需要多选,那么要设置setMultiSelectionEnabled(true)

那么File file = this.getSelectedFile();这句我们就要改成

File [] files = this.getSelectedFiles();

files这个数组里面就存放的是选择多个文件File对象,然后我们只需要对这个数组进行操作即可。
 



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1531654

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多