黑马学习笔记6

来源:互联网 发布:单片机上电复位电路 编辑:程序博客网 时间:2024/06/03 05:05

---------------------- android培训、java培训、期待与您交流!----------------------

在Java程序中,对于数据的输入/输出操作以“流”方式进行,Java提供了各种各样的“流”类,可以分为两种,输入有关的所有类都从InputStream 继承,从InputStream(输入流)衍生的所有类都拥有名为read()的基本方法,用于读取单个字节或者

字节数组;而与输出有关的所有类都从OutputStream继承,从OutputStream 衍生的所有类都拥有基本方法write(),用于写入单个字节或者字节数组。

可以从不同的角度对Java的IO进行分类:

1、按照数据流的方向不同,可以分为输入流和输出流

2、按处理数据单位不同,可以分为字节流和字符流

3、按照功能的不同可以分为节点流和处理流(节点流可以从一个特定的数据源读写数据,而处理流是建立在已存在的流的基础上,提供了更为强大的读写功能,在Java中是使用装饰模式进行处理的)

位于java.io包内的类都分别继承自四种抽象流类型

字节输入流InputStream、字节输出流OutputStream、字符输入流Reader、字节输出流Writer

可以用树状结构表示java.io包内的类的继承关系

字节输入流InputStream

            -- FileInputStream

            -- PipedInputStream

InputStream -- FilterInputStream --------- BufferedInputStream、LineNumberinputStream、DataInputStream、PushbackInputStream

            -- ByteArrayInputStream

            -- SequenceInputStream

            -- StringBufferInputStream

            -- ObjectInputStream

 

字节输出流OutputStream:

             -- FileOutputStream

             -- PipedOutputStream

OutputStream -- FilterInputStream ------ BufferedOutputStream、DataOutputStream、PrintStream

             -- ByteArrayOutputStream 

             -- ObjectOutputStream

字符输入流Reader

         -- BufferedReader    ----- LineNumberReader

         -- CharArrayReader

Reader   -- InputStreamReader ----- FileReader

         -- FilterReader      ----- PushbackReader

         -- PipedReader

         -- StringReader     

字节输出流Writer

         -- BufferedWriter   

         -- CharArrayWriter

Writer   -- OutputStreamReader ----- FileWriter

         -- FilterWriter     

         -- PipedWriter

         -- StringWriter  

从上面这四个树状图可以看出,java的io类基本上都是成对出现的,这样可以方便我们记忆。

JavaIO中有一个非常重要的类,叫File,File代表文件和目录路径名的抽象表示形式,它的常用构造方法是用一个路径创建File对象,下面这些代码介绍了FIle类常用的方法

创建一个绝对路径名为d:/java/Test.java的文件,当new出这个File对象时只是存在于内存中,而不是存在于磁盘上,只要调用createNewFile方法时才会真正在磁盘上创建,此时创建出来的时一个空文件,这个方法会抛出IOException异常

public static void main(String[] args) { 

  //在内存里创建这个文件,分隔符使用/,这样保证了既可以在windows上运行,也可以在linux上运行
  File file = new File("d:/java/Test.java");
  //判断此文件在磁盘上是否存在
  if (!file.exists()) {
   try {
    //不存在的话就创建它
    file.createNewFile();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

创建一个目录d:/java,与创建文件类似,当new出这个File对象时只是存在于内存中,而不是存在于磁盘上,只要调用mkdir方法时才会真正在磁盘上创建这个目录

//创建一个目录
 
public static void main(String[] args) { 
  //在内存里创建这个文件
  File file = new File("d:/java");
  //判断此文件在磁盘上是否存在
  if (!file.exists()) {
   //不存在的话就创建它
   file.mkdir();
  }
 }

File的路径分隔符,路径分割符是用来分割路径的,如:windows中"d:\java\test.java",符号"\"就是路径分割符,由于不同操作系统的路径分隔符使用的字符不同,所以为了保证Java的跨平台这一特性,所以Java在File类中,提供了一个与操作系统无关的分隔符:File.separator。

这句代码

System.out.println(File.separator)

在windows下运行结果是 \   而在linux下运行结果是 /  ,所以在我们的程序中路径分隔符不要硬编码,尽量使用File.separator作为分隔符,如果想省事的话就是用/,windows也支持这种,可以保证在windows和linux上都可以运行

 

得到一个指定文件的详细信息

public static void main(String[] args) { 
  File file = new File("d:/java/Test.java");
  System.out.println(file.canRead());//
测试应用程序是否可以读取此抽象路径名表示的文件
 
System.out.println(file.canWrite());//测试应用程序是否可以修改此抽象路径名表示的文件
  System.out.println(file.canExecute());//测试应用程序是否可以执行此抽象路径名表示的文件
  System.out.println(file.isFile());//测试此抽象路径名表示的文件是否是一个标准文件
  System.out.println(file.isDirectory());//测试此抽象路径名表示的文件是否是一个目录
  System.out.println(file.length());//返回由此抽象路径名表示的文件的长度
 }

递归的获得一个目录下的所有文件与目录,并打印出树状结构

public static void main(String[] args) { 
  File file = new File("d:/java");
  list(file,0);
 }
 
 public static void list(File file,int level) {
  //根据层次拼出,打印file时前面出现的空白字符,单线程下使用StringBuilder速度快且安全
  StringBuilder tree = new StringBuilder("");
  for (int i = 0;i <= level;i++) {
   tree.append("  ");
  }
 
  //如果参数file表示的不是一个目录方法不执行
  if (file.isDirectory()) {
   //获得一个目录下的所有文件和目录
   File[] children = file.listFiles();
   //使用高级循环遍历children
   for (File child : children) {
    //打印child,前面加上拼出来的空白字符
    System.out.println(tree.toString() + child);
    //如果child为目录的话,递归调用,并把级别加上1
    if (child.isDirectory()) {   
     list(child,level + 1);
    }
   }
  } 
 }

上面使用FIle这个类只能对文件进行简单的操作,还不能读写文件。

字节流

FIleInputStream和FileOutputStream都属于节点流,他们的数据源都是硬盘上的一个具体文件。为打开一个文件以便输入,需要使用FileInputStream,同时使用String或File对象作为文件名使用。同样的输出到文件需要FileOutputStream。要注意的是,构造FIleInputStream,对应的文件必须是可读的,而构造FIleOutputStream时,若输出文件已存在,则必须是可覆盖的。写一个测试程序,使用这两个类,完成把复制文件的功能(把d:/java/Person.java复制到d:/Person.java)

 

public static void main(String[] args) {
 
FileInputStream fis = null;//
输入流
 
FileOutputStream fos = null;//输出流
  String srcFileName = "d:/java/Person.java";
  try {
   //通过打开一个到实际文件的连接来创建一个 FileInputStream
   fis = new FileInputStream(srcFileName);
   // 创建一个向具有指定名称的文件中写入数据的输出文件流
   fos = new FileOutputStream("d:/Person.java");
   int i = 0;
   while (( i = fis.read()) != -1) {
    fos.write(i);
   }
  } catch (FileNotFoundException e) {  
   System.out.println("找不到文件" + srcFileName);
  } catch (IOException e) {  
   System.out.println("出现了错误");
  } finally {
   try {
    //一定要关闭,否则日积月累会造成内存泄露
    fis.close();//关闭输入流
    fos.close();//关闭输出流
   } catch (IOException e) {   
    e.printStackTrace();
   }
  }
 }

需要注意的是当我们使用完流时,一定要关闭,不然的话日积月累会造成内存泄露,这点对于我们自己的电脑无所谓,但是对于服务器端的应用程序来说就至关重要了,因为服务器是不经常重启的。关闭的代码最好写在finally里面,这样保证了无论如何这段代码都会被执行。

 

字符流   

字符流主要是用来处理字符的。Java采用16位的Unicode来表示字符。字符流类有两个基类Reader和Writer,继承自Reader的流都是用于向程序中输入数据,且数据的单位为字符。继承自Writer的流都是用于输出单位为字符的数据。可以把上面那个复制文件的程序,改为使用FIleReader和FileWriter这两个字符流类来完成

//复制文件,使用字符流
 
public static void main(String[] args) {
  FileReader fr = null;//输入流
  FileWriter fw = null;//输出流
  String srcFileName = "d:/java/Person.java";
  try {
   //通过打开一个到实际文件的连接来创建一个 FileReader
   fr = new FileReader(srcFileName);
   // 创建一个向具有指定名称的文件中写入数据的输出字符流
   fw = new FileWriter("d:/Person.java");
   int i = 0;
   while (( i = fr.read()) != -1) {
    fw.write(i);
   }
  } catch (FileNotFoundException e) {  
   System.out.println("找不到文件" + srcFileName);
  } catch (IOException e) {  
   System.out.println("出现了错误");
  } finally {
   try {
    //一定要关闭,否则日积月累会造成内存泄露
    fr.close();//关闭输入流
    fw.close();//关闭输出流
   } catch (IOException e) {   
    e.printStackTrace();
   }
  }
 }

这个程序和上面那个使用FIleInputStream和FileOutputStream进行文件复制,看似差不多,但是根本区别在于底层,第一个数据传输的单位是字节,第二个程序的传输单位是字符

缓冲流

缓冲流要套接在相应的节点流之上,对读写的数据提供了缓冲功能,可以减少对硬盘的读写次数,即保护了硬盘,也提高了读写的效率,同时增加了一些新的方法。Java为InputStream、OutputStream、Reader、Writer都提供了相应的缓冲流。就以BufferedInputStream和BufferedOutputStream这两个类为例来说明缓冲流,把复制文件的例子进行改写,把字节流套接在缓冲流之上 

//复制文件,使用缓冲流
 
public static void main(String[] args) {
  FileInputStream fis = null;//输入流
  FileOutputStream fos = null;//输出流
  BufferedInputStream bis = null;//带缓冲的输入流
  BufferedOutputStream bos = null;//带缓冲的输出流
  String targetFileName = "d:/java/Person.java";
  try {
   //通过打开一个到实际文件的连接来创建一个 FileInputStream
   fis = new FileInputStream(targetFileName);
   //使用装饰模式,把字节流fis套接在缓冲流之上,为其提供缓冲
   bis = new BufferedInputStream(fis);
   // 创建一个向具有指定名称的文件中写入数据的输出文件流
   fos = new FileOutputStream("d:/Person.java");
   //使用装饰模式,把字节流fos套接在缓冲流之上,为其提供缓冲
   bos = new BufferedOutputStream(fos);
   int i = 0;
   while (( i = bis.read()) != -1) {
    bos.write(i);
   }
  } catch (FileNotFoundException e) {  
   System.out.println("找不到文件" + targetFileName);
  } catch (IOException e) {  
   System.out.println("出现了错误");
  } finally {
   try {
    //把缓冲流关闭,套接在缓冲流之上的字节流也随着被关闭
    bis.close();
    bos.close();
   } catch (IOException e) {   
    e.printStackTrace();
   }
  }
 }

转换流

在程序中有时候,需要把字节流转换为字符流使用,Java为我们提供了这样的类。InputStreamReader和OutputStreamWriter用于字节数据到字符数据之间的转换,以 InputStreamReader 为例,写个把字节输入流转化为字符输入流使用的测试程序,功能是从键盘上读取一行输入并打印出来,具体代码:

//转换流,把从键盘上输入的字节流,转换为带缓冲的字符流使用
 
public static void main(String[] args) {
  BufferedReader br = null;
  try {
   System.out.println("输入一行数据:");
   br = new BufferedReader(
     new InputStreamReader(System.in));
   System.out.println("你输入的数据为:" + br.readLine());
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   try {
    br.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  } 
 }

程序中 InputStreamReader 作为字节输入流 System.in 和 带缓冲的字符输入流之间的桥梁,通过包装完成流转换

 关于java的io这里只是说了一小部分,Java的io设计初衷是设计的小巧一点,但事实上非常庞大,这点Thank in Java这个书中也有说到,初学时很头痛,慢慢的用的多了就能熟练的运用了。

0 0
原创粉丝点击