黑马程序员_IO流(三)

------------ android培训java培训、java博客、java学习型技术博客、期待与您交流! --------------

 

 本章主要的知识点总结:

                                1、使用File类创建文件及文件夹,还有File类对象功能

                                 2、学会使用递归列出和删除文件夹目录下的所有内容

                                 3、掌握使用Properties集合存取配置文件

                                 4、IO包中其他类:打印流 PrintWriter,合并流 ,对象序列化的流对象,管道流,
                                 5、特殊的RandomAccessFile类的使用

                                 6、其它流对象:操作基本数据类型(DataStream)、操作字节数组(ByteArrayStream)、                                      操作字符数组(CharArrayReader与CharArrayWriter )

                                     操作字符串(StringReader与StringWriter)

                                7、转换流和字符编码的问题

             


一、File类概述

 

       用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作。File对象可以作为参数传递给流的构造函数。

     ( 1)构造函数:

         public File(String pathname)通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。

如果给定字符串是空字符串,那么结果是空抽象路径名。

          参数:pathname - 路径名字符串

         public File(String parent,String child)

         根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。

         如果 parent 为 null,则创建一个新的 File 实例,这与调用以给定 child 路径名字符串作为参数的单参数 File 构造方法效果一样。否则,parent 路径名字符串用于表示目录,child 路径名字符串用于表示目录或文件。

         如果 child 路径名字符串是绝对路径名,则用与系统有关的方式将它转换为一个相对路径名。如果 parent 是空字符串,则通过将 child 转换为抽象路径名,并根据与系统有关的默认目录解析结果来创建新的 File 实例。否则,将每个路径名字符串转换为一个抽象路径名,并根据父抽象路径名解析子抽象路径名。

参数:

   parent - 父路径名字符串

    child - 子路径名字符串

抛出:

NullPointerException - 如果 child 为 null

        public File(File parent,String child)

根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。如果 parent 为 null,则创建一个新的 File 实例,这与调用给定 child 路径名字符串的单参数 File 构造方法的效果一样。

        字段摘要:

separator-----跨平台的目录分隔符

       public static final String separator与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。此字符串只包含一个字符,即 separatorChar。

 

   二、File对象功能

1.创建:

boolean createNewFile() throws IOException

       在指定位置创建文件,如果该文件已经存在,则不创建,返回false;和输出流不一样,输出流对象一建立创建文件,而且文件已经存在,会覆盖。

     boolean mkdir():创建文件夹。

      boolean mkdirs():创建多级文件夹。

2.删除:

      boolean delete()

删除此抽象路径名表示的文件或目录。 删除失败返回false.

        void deleteOnExit()

       在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。在程序退出时删除指定文件。

       注意:若前面的代码发生异常,则此时后面的删除操作就执行不到,此时就会产生垃圾。就算是在finally中删除有时也未必有效。因为正在被流操作的文件会报提示无法删除。此时用deleteOnExit()退出时删除方法就很容易解决这个问题了。

3.判断:

      boolean canExecute()

测试应用程序是否可以执行此抽象路径名表示的文件。

       boolean canRead()

测试应用程序是否可以读取此抽象路径名表示的文件。

      boolean canWrite()

测试应用程序是否可以修改此抽象路径名表示的文件。

      int compareTo(File pathname)

按字母顺序比较两个抽象路径名。

      boolean exists()

测试此抽象路径名表示的文件或目录是否存在。

      boolean isAbsolute()

测试此抽象路径名是否为绝对路径名。

      boolean isDirectory()

测试此抽象路径名表示的文件是否是一个目录。

       boolean isFile()

测试此抽象路径名表示的文件是否是一个标准文件。

       boolean isHidden()

测试此抽象路径名指定的文件是否是一个隐藏文件。

注意:文件夹也可能叫a.txt

4.获取信息:

       String getName()

    返回由此抽象路径名表示的文件或目录的名称。

      String getParent()

        返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。

         File getParentFile()

         返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。

       String getPath()

   将此抽象路径名转换为一个路径名字符串。

      String getAbsolutePath()

返回此抽象路径名的绝对路径名字符串。

       long lastModified()

返回此抽象路径名表示的文件最后一次被修改的时间。

       long length()

返回由此抽象路径名表示的文件的长度。

       boolean renameTo(File dest)

重新命名此抽象路径名表示的文件。

5.文件列表

文件列表功能:

    static File[] listRoots()

列出可用的文件系统根。

      String[] list()

返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。

      String[] list(FilenameFilter filter)

返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。

    String[] list(FilenameFilter filter)

返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。

      File[] listFiles()

返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。

       File[] listFiles(FileFilter filter)

返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。

       File[] listFiles(FilenameFilter filter)

返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目.

列出目录下所有内容-递归

    列出指定目录下文件或者文件夹,包含子目录中的内容。也就是列出指定目录下的所有内容。

class FileTest

{

public static void main(String[ ] args)

{

File dir=new File("d:javatest");

showDir(dir);

}

public static void showDir(File dir)

{

  System.out.println(dir);

File files=dir.listFiles();

for(int x=0;x<files.length;x++)

{

if(files[x].isDirectory()

showDir(files[x]);

else

System.out.println(files[x]);

}

}

}


  (创建java文件列表)
  1. 练习 
  2. 将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。 
  3. 建立一个java文件列表文件。 
  4. 思路: 
  5. 1,对指定的目录进行递归。 
  6. 2,获取递归过程所以的java文件的路径。 
  7. 3,将这些路径存储到集合中。 
  8. 4,将集合中的数据写入到一个文件中。 
  9.   
  10. class JavaFile  
  11. {  
  12. public static void main(String[] args)  
  13. {  
  14. File dir = new File("D:\\javatest");  
  15. ArrayList<File> list = new ArrayList<File>();  
  16. //写到集合中。  
  17. file2List(dir,list);  
  18. File javalist = new File(dir,"javalist.txt");  
  19. write2File(list,javalist.toString());  
  20. }  
  21. public static void file2List(File dir,List<File> list)  
  22. {  
  23. File files = dir.listFiles();  
  24. for(File file : files)  
  25. {  
  26. if(file.isDirectory())  
  27. file2List(file,list);  
  28. else if(file.endsWith("java"))  
  29. list.add(file);  
  30. }  
  31. }  
  32. public static void write2File(List<File> list,String javalist)throws IOException  
  33. {  
  34. BufferedWriter bufw = null;  
  35. try  
  36. {  
  37. bufw = new BufferedWriter(new FileWriter(javalist));  
  38. for(File file : list)  
  39. {  
  40. String dirpath  = file.getAbsolutePath();  
  41. bufw.write(dirpath);  
  42. bufw.newLine();  
  43. bufw.flush();  
  44. }  
  45. }  
  46. catch (IOException e)  
  47. {  
  48. throw new RuntimeException();  
  49. }  
  50. finally  
  51. {  
  52. try  
  53. {  
  54. if(bufw!=null)  
  55. bufw.close();  
  56. }  
  57. catch (IOException e)  
  58. {  
  59. throw e;  
  60. }  
  61. }  
  62. }  
  63. }  

 

三.Properties集合

1.Properties类


         Properties是Hashtable的子类。也就是说具备Map集合的特点。而且它里面存储的键值对都是字符串, 是集合和IO技术相结合的集合容器。

  该对象的特点:可以用于键值对形式的配置文件。但在加载数据时有固定格式 : 键 = 值。
       构造方法:
Properties():创建一个无默认值的空属性的列表。
Properties(Properties default) 创建一个带有指定默认值的空属性的列表。
      特有方法:
     String getProperty(String key) 用指定的键在此属性列表中搜索属性。
    String getProperty(String key,String defaultValue)
      Object setProperty(String key,String value)  调用它的父类Hashtable的put方法。
      Set<String> stringPropertyNames()  返回此属性列表中的键集,其中该键及其对应值是字符串。
如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。


2.Properties存取配置文件

       Properties方法:
         void list<PrintStream out) 将属性列表输出到指定的输出流。
         void list<PrintWriter out)  将属性列表输出到指定的输出流。
        void load(InputStream inStream) 从输入中读取属性列表。(键和元素对)
       void load(Reader reader)按简单的面向行的格式从输入字符中读取属性列表(键和元素对);
       void Store(Writer writer,String comments)
以适合使用load(Reader)方法的格式。将此Properties表中的属性列表写入输出流或文件中。
       void Store(OutputStream out ,String comments)

以适合使用load(InputStream )方法加载Properties表中的格式,将此Properties表中的属性列表写到输出流。

     Properties例题

  1. 想要将info.txt中的键值对数据存到集合中进行操作。  
  2. 思路:  
  3. <1>用一个读取流和info.txt文件关联。  
  4. <2>读取一行数据,将该行数据用“=”进行切割,  
  5. <3>等号左边作为键,等号右边作为值,存到Properties集合中即可。  
  6.   
  7. Class PropertiesTest  
  8. {  
  9.     public static void main(String[] args)  
  10.     {  
  11.         Properties prop = new Properties();  
  12.         BufferedReader bufr = new BufferedReader(new FileReader("info.txt");  
  13.         String line = null;  
  14.         While((line = bufr.readLine()))!= null)  
  15.         {  
  16.             String[] str = line.split("=");  
  17.             prop.setProperty(str[0],str[1]);  
  18.         }  
  19.         bufr.close();  
  20.     }  
  21. }  

  例题二:需求:  

  1.  用于记录应用程序运行次数。  
  2.  如果使用次数已到5次,那么给出注册提示。  
  3.   
  4. 思路:  
  5.   很容易想到的是:计数器。  
  6.   可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。  
  7.   可是随着该应用程序的退出,该计数器也在内存中消失了。  
  8.   所以要建立一个配置文件,用于记录该软件的使用次数。  
  9.   该配置文件使用键值对的形式。这样便于阅读数据,并操作数据。  
  10.   键值对数据是map集合。  
  11.   数据是以文件形式存储,使用io技术。  
  12.   那么map+io -->properties.  
  13.   
  14.   配置文件可以实现应用程序数据的共享。  
  15.   
  16. class PropertiesTest2  
  17. {  
  18.     public static void main(String[] args)  throws Exception
  19.     {  
  20.         Properties prop = new Properties();  
  21.         File file = new File("count.ini");  
  22.         if(!file.exists())  
  23.             file.creatNewFile();  
  24.         prop.load(new FileInputStream(file));  
  25.           
  26.         int count = 0;  
  27.         String value = prop.getProperty("time");  
  28.         if(value!= null)  
  29.         {  
  30.             count=Integer.parseInt(value);
  31.             if(count>=5
  32.              { 
  33.                 System.out.println("使用次数已到");  
  34.             return;  
  35.            }
  36.         }  
  37.         count++;  
  38.           
  39.         prop.setProperty("time",count+"");  
  40.         prop.store(new FileOutputStream(file),"");  
  41.           
  42.         fos.close();  
  43.         fis.close();  
  44.           
  45.     }  
  46. }  

 


四.PrintWriter

    

1.打印流:

  该流提供了打印方法,可以将各种数据类型的数据都原样打印。
  (1)字节打印流:
  PrintStream
  构造函数可以接收的参数类型:
         1、 file对象。File
         2、字符串路径。String
         3、字节输出流。OutputStream
  (2)字符打印流:

  PrintWriter

可以直接操作输入流和文件。

  构造函数可以接收的类型:
       file对象。File
      字符串路径。String
      字节输出流。OutputStream
      字符输出流。Writer.

 2
.Writer ---> PrintWriter类(java.io)
       向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。
  它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。
 3.Writer ---> PrintWriter类(java.io)
(  1)向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。
  它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。 

  与 PrintStream 类不同,如果启用了自动刷新,则只有在调用 println、printf 或 format 
  的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。
  这些方法使用平台自有的行分隔符概念,而不是换行符。 

  此类中的方法不会抛出 I/O 异常,尽管其某些构造方法可能抛出异常。
  客户端可能会查询调用 checkError() 是否出现错误。
 (2)字段摘要 
  protected  Writer out 
     此 PrintWriter 的底层字符输出流。 
  (3)构造方法摘要 
        PrintWriter(File file) 
     使用指定文件创建不具有自动行刷新的新 PrintWriter。 
      PrintWriter(OutputStream out) 
     根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 
     PrintWriter(OutputStream out, boolean autoFlush) 
     通过现有的 OutputStream 创建新的 PrintWriter。 
      PrintWriter(String fileName) 
     创建具有指定文件名称且不带自动行刷新的新 PrintWriter。 
     PrintWriter(Writer out) 
     创建不带自动行刷新的新 PrintWriter。 
      PrintWriter(Writer out, boolean autoFlush) 
     创建新 PrintWriter。 
 (4)特有方法:
  void println(Object x) 
     打印 Object,然后终止该行。

五.合并流


 1.InputStream ---> SequenceInputStream类(java.io包)  对多个流进行合并。

  (1)SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,
        并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,
        直到到达包含的最后一个输入流的文件末尾为止。
  (2)构造方法摘要 
      SequenceInputStream(Enumeration<? extends InputStream> e) 
       通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象         的 Enumeration 型参数。 
      SequenceInputStream(InputStream s1, InputStream s2) 
        通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然         后读取 s2),以提供从此 SequenceInputStream 读取的字节。 
(3)方法摘要 
    int available() 
      返回不受阻塞地从当前底层输入流读取(或跳过)的字节数的估计值,方法是通过下一次调用当前底层输入        流的方法。 (不明白这个方法)
     void close() 
     关闭此输入流并释放与此流关联的所有系统资源。 
     int read() 
     从此输入流中读取下一个数据字节。 
      int read(byte[] b, int off, int len) 
     将最多 len 个数据字节从此输入流读入 byte 数组。
2 切割文件 例题

  1. 合并文件的时候,要用到集合,而Vector的效率太低,所以选择用ArrayList.  
  2. 读取里要用用序列流SequenceInputStream.但该序列流要传入枚举类型的参数。  
  3. 而枚举是Vector中的方法,ArrayList 中没有枚举方法,只有相似的Iterator迭代器  
  4. 。故可建立枚举的匿名类,复写类中的方法以返回调用Iterator的方法即可。  
  5.   
  6. 注:匿名内部类访问的局部变量要用final修饰。  
  7.   
  8. class SplitFile  
  9. {  
  10.     public static void main(String[] args) throws IOException 
  11.     {  
  12.         merge();  
  13.         splitFile();  
  14.     }  
  15.   
  16.     public static void merge()throws IOException  
  17.     {  
  18.         ArrayList<FileInputStream> al = new ArraList<FileInputStream>();  
  19.         for(int x = 0;x<3;x++)  
  20.         {  
  21.             al.add(new FileInputStream(""c:\\splitfiles\\"+x+".part");  
  22.         }  
  23.         final  Iterator<FileInputStream> it =  al.iterator();  
  24.         Enumeration <FileInputStream> en = new Enumeration<FileInputStream>(){  
  25.             public boolean hasMoreElements(){  
  26.                 return it.hasNext();  
  27.             }  
  28.             public boolean nextElement(){  
  29.                 return it.next();  
  30.             }  
  31.         };  
  32.   
  33.   
  34.    SequenceInputStream sis = new SequenceInputStream(en);   
  35.   FileOutputStream fos = new FileOutputStream("C:\\5.bmp); 
  36.         byte[] buf = new byte[1024];  
  37.         int len = 0;  
  38.         while((len = sis.read(buf))!=-1)  
  39.         { 
  40.             fos.write(buf,0,len);  
  41.         }     
  42.         fos.close();  
  43.         sis.close();          
  44.     }     
  45.     public static void splitFile()throws IOException  
  46.     {  
  47.         FileInputStream fis = new FileInputStream("1.mp3");  
  48.         FileOutputStream fos = null;  
  49.           
  50.         byte[] buf = new byte[1024];  
  51.         int len = 0;  
  52.         int count = 1;  
  53.         while((len = fis.read(buf))!=-1)  
  54.         {  
  55.             fos = new FileOutputStream(""c:\\splitfiles\\"+(count++)+".part")  
  56.             fos.write(buf,0,len);  
  57.             fos.close();  
  58.       
  59.         }         
  60.     }  
  61.           


六、对象的序列化


1.OutPutStream ---> 类 ObjectOutputStream(java,io包)  

被操作的对象需要实现Serializable(标记接口);

 (1)ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。
  可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
  如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。 
  只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,
  编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
 (2)构造方法
        protected  ObjectOutputStream() 
     为完全重新实现 ObjectOutputStream 的子类提供一种方法,
     让它不必分配仅由 ObjectOutputStream 的实现使用的私有数据。 
        ObjectOutputStream(OutputStream out)  
     创建写入指定 OutputStream 的 ObjectOutputStream。
  (3)特有方法:
       void writeObject(Object obj) 
     将指定的对象写入 ObjectOutputStream。 
       void writeInt(int val) 

     写入一个 32 位的 int 值。


2.InputStream ---> 类 ObjectInputStream (java.io包)
  (1)ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。 

       ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 

        一起使用时 可以为应用程序提供对对象图形的持久存储

       ObjectInputStream 用于恢复那些以前序列化的对象。

      其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。 
      objectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。
      使用标准机制按需加载类。 
      只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。 
  (2)构造方法摘要 
  protected  ObjectInputStream() 

    为完全重新实现 ObjectInputStream 的子类提供一种方式,

   让它不必分配仅由 ObjectInputStream 的实现使用     的私有数据。 

  ObjectInputStream(InputStream in) 
     创建从指定 InputStream 读取的 ObjectInputStream。 
 ( 3)特有方法:
    Object readObject() 从 ObjectInputStream 读取对象。


3. 接口 Serializable (java.io包)
   (1)public interface Serializable类通过实现 java.io.Serializable 接口以启用其序列化功能。
  未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。
  序列化接口没有方法或字段,仅用于标识可序列化的语义。
   (2)可序列化类可以通过声明名为 "serialVersionUID" 的字段
  (该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
    ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

   如果可序列化类未显式声明 serialVersionUID,

  则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值.


 4.注意:
 (1)实现了Serializable接口的类都会有一个UID的序列号(java自动生成)标示,类改变,序列号也会改变。
    要想改变类而不改变序列号,可手动给类定义一个固定的序列号(方便序列化)。方法就是:
    显式声明其自己的 serialVersionUID: public static final long serialVersionUID = 42L;
 (2)静态变量不能被序列化,因为静态在方法区中,而对象是在堆里。序列化是对堆中的对象进行的。
  ( 3)如果对堆中的成员也不想进行序列的化的话。只需加上关键字transient修饰就可以了。

七、管道流


 1.InputStream ---> PipedInputStream类(java.io包)
          管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,
  数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。
         不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区, 可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在, 则认为该管道已损坏。
( 1)构造方法摘要 
       PipedInputStream() 
     创建尚未连接的 PipedInputStream。 
       PipedInputStream(int pipeSize) 
     创建一个尚未连接的 PipedInputStream,并对管道缓冲区使用指定的管道大小。 
      PipedInputStream(PipedOutputStream src) 
     创建 PipedInputStream,使其连接到管道输出流 src。 
     PipedInputStream(PipedOutputStream src, int pipeSize) 
     创建一个 PipedInputStream,使其连接到管道输出流 src,并对管道缓冲区使用指定的管道大小。 
 ( 2)特有方法:
  void connect(PipedOutputStream src) 
     使此管道输入流连接到管道输出流 src。 
 2.OutputStream ---> PipedOutputStream类(java.io包)
  (1)可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,
  数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。
  不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。
  如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,
  则该管道被视为处于 毁坏 状态
  (2)构造方法摘要 
     PipedOutputStream() 
     创建尚未连接到管道输入流的管道输出流。 
    PipedOutputStream(PipedInputStream snk) 
     创建连接到指定管道输入流的管道输出流。 
 ( 3)特有方法:
  void connect(PipedInputStream snk) 

     将此管道输出流连接到接收者。


3.代码例题:

  1. Class A 
  2. {  
  3. public static void main(String[] args)   
  4. {  
  5. PipedInputStream pis = new PipedInputStream();  
  6. PipedOutputStream pos = new PipedOutputStream();  
  7. pis.connect(pos);  
  8. new Thread(new Reader(pis)).start();  
  9. new Thread(new Writer(pos)).start();  
  10.   
  11. }  
  12. }  
  13. class Reader implements Runnable  
  14. {  
  15. private PipedInputStream pis;  
  16. Reader(PipedInputStream pis)  
  17. {  
  18. this.pis = pis;  
  19. }  
  20. public void run()  
  21. {  
  22. try  
  23. {  
  24. byte[] buf = new byte[1024];  
  25. int len = pis.read(buf);  
  26. System.out.println(new String(buf,0,len));  
  27. }  
  28. catch (IOException e)  
  29. {  
  30. e.printStackTrace();  
  31. }  
  32.   
  33. }  
  34. }  
  35. class Write implements Runnable  
  36. {  
  37. private PipedOutputStream pos ;  
  38. Write(PipedOutputStream pos)  
  39. {  
  40. this.pos = pos;  
  41. }  
  42. public void run()  
  43. {  
  44. try  
  45. {  
  46. pos.write("PipedStrea lai le!".getBytes());  
  47. pos.close();  
  48. }  
  49. catch (IOException e)  
  50. {  
  51. e.printStackTrace();  
  52. }  
  53.   
  54. }  

八、RandomAccessFile


 1. RandomAccessFile类:
      随机访问文件,自身具备读写的方法。

 

         该类不算是IO体系中的子类。而是直接继承Object。但是它是IO包中成员。因为它具备读写功能。
  内部封装了一个数组,而且通过指针对数组的元素进行操作, 可以通过getFilePointer获取指针位置。

  同时可以通过seek改变指针的位置。

 

  实现完成读写的原理就是内部封装了字节输入流和输出流。
  通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式:只读r,读写rw等。
  如果模式为只读r.不会创建文件。会去读取一个已存在文件。如果该文件不存在。则会出现异常。

  如果模式为rw.操作的文件不存在,会自动创建,如果存在,则不会覆盖。

     通过skipBytes(int x),seek(int x)来达到随机访问。


 2.Object ----> RandomAccessFile类:
  (1)此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的
  一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,
  并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;
  输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。
  写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,
  并通过 seek 方法设置。 
  (2)构造方法摘要 
      RandomAccessFile(File file, String mode) 
     创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 
       RandomAccessFile(String name, String mode) 
     创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 
 ( 3)特有方法:
  void writeInt(int v) 
     按四个字节将 int 写入该文件,先写高字节。 
  int skipBytes(int n) 
     尝试跳过输入的 n 个字节以丢弃跳过的字节。 
  void write(byte[] b) 
     将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。 
  void write(int b) 
     向此文件写入指定的字节。 
  void writeBoolean(boolean v) 
     按单字节值将 boolean 写入该文件。 
  void writeByte(int v) 
     按单字节值将 byte 写入该文件。 
  void writeBytes(String s) 
     按字节序列将该字符串写入该文件。 
 void seek(long pos) 
     设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。 
     int readInt() 
     从此文件读取一个有符号的 32 位整数。 
     String readLine() 
     从此文件读取文本的下一行。 
      long getFilePointer() 
     返回此文件中的当前偏移量。 
      long length() 
     返回此文件的长度。 
     int read() 
     从此文件中读取一个数据字节。 
      int read(byte[] b) 
     将最多 b.length 个数据字节从此文件读入 byte 数组。 
     void close() 
     关闭此随机访问文件流并释放与该流关联的所有系统资源。 


九、基本数据类型的数据的流对象

1.DataInputStream与DataOutputStream
  (1)数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,
  应用程序可以使用数据输入流将数据读入。 
 ( 2)构造方法
  DataOutputStream(OutputStream out) 
     创建一个新的数据输出流,将数据写入指定基础输出流。 
  (3)特有方法:
  void writeBoolean(boolean v) 
     将一个 boolean 值以 1-byte 值形式写入基础输出流。 
  void writeDouble(double v) 
     使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,
     然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。 
  void writeInt(int v) 
     将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。 
  void writeUTF(String str) 

     以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。 


 2.InputStream ---> DataInputStream类
 ( 1)数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。
  应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。 
  DataInputStream 对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责
  (2)构造方法摘要 
  DataInputStream(InputStream in) 
     使用指定的底层 InputStream 创建一个 DataInputStream。 
  (3)特有方法:
  boolean readBoolean() 
     参见 DataInput 的 readBoolean 方法的常规协定。 
  double readDouble() 
     参见 DataInput 的 readDouble 方法的常规协定。 
  int readInt() 
     参见 DataInput 的 readInt 方法的常规协定。 
  String readUTF() 
     参见 DataInput 的 readUTF 方法的常规协定。 
 3.注意UTF与UTF-8的差别:

   UTF-8是6个字节的两字。而UTF是8个字节的两字。


十、ByteArrayStream

 1.其它流

 (1)操作基本数据类型:
  DataInputStream与DataOutputStream
  (2)操作字节数组
  ByteArrayInputStream与ByteArrayOutputStream
 ( 3)操作字符数组
  CharArrayReader与CharArrayWrite 
  (4)操作字符串
  StringReader与StringWriter
2.InputStream ---> ByteArrayInputStream类
 ( 1)ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。
  内部计数器跟踪 read 方法要提供的下一个字节。 
 (2)构造方法摘要 
  ByteArrayInputStream(byte[] buf) 
     创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。 
  ByteArrayInputStream(byte[] buf, int offset, int length) 
     创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组。 
 ( 3)方法摘要 
   int available() 
     返回可从此输入流读取(或跳过)的剩余字节数。 
   int read() 
     从此输入流中读取下一个数据字节。 
   int read(byte[] b, int off, int len) 
     将最多 len 个数据字节从此输入流读入 byte 数组。 
   long skip(long n) 
     从此输入流中跳过 n 个输入字节。 
3.OutputStream ---> ByteArrayOutputStream类
  (1)此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。
  可使用 toByteArray() 和 toString() 获取数据。 
  关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
  (2)构造方法摘要 
  ByteArrayOutputStream() 
     创建一个新的 byte 数组输出流。 
  ByteArrayOutputStream(int size) 
     创建一个新的 byte 数组输出流,它具有指定大小的缓冲区容量(以字节为单位)。 
  (3)方法摘要 
  void close() 
     关闭 ByteArrayOutputStream 无效。 
  void write(byte[] b, int off, int len) 
     将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流。 
  void write(int b) 
     将指定的字节写入此 byte 数组输出流。 
  void writeTo(OutputStream out) 
     将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用 out.write(buf, 0, count) 调用该输出流的 write 方法效果一样。 
  int size() 
     返回缓冲区的当前大小。 
  byte[] toByteArray() 
     创建一个新分配的 byte 数组。 
  String toString() 

     使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。


十一、字符编码

 

1、字符编码

        字符流的出现为了方便操作字符。更重要的是加入了编码转换。
  通过子类转换流来完成。
   InputStreamReader
   OutputStreamWriter
  在两个对象进行构造的时候可以加入字符集。
  2、常见的编码表
 (1)ASCII:美国标准信息交换码。
     用一个字节的7位可以表示。
  (2)ISO8859-1:拉丁码表,欧洲码表。
     用一个字节的8位表示。
 ( 3)GB2312:中国的中文编码表。
 ( 4)GBK:中国的中文编码表升级,融合了更多的中文文字符号。
  (5)Unicode:国际标准码,融合了多种文字。
    所有文字都用两个字节来表示,Java语言使用的就是unicode.

  (6)UTF-8:最多用三个字节来表示一个字符。


  3.转换流的编码应用
  (1)可以将字符以指定编码格式存储。
  (2)可以对文本数据指定编码格式来解读。

  (3)指定编码表的动作由构造函数完成。


编码解码
 1.编码:字符串变成字节数组
   解码:字节数组变成字符串。
   String --> byte[]: str.getBytes(charsetName);
   byte[] ---> String : new String(byte[],charsetName);
 2.用到的方法:
 ( 1)String类(java.lang包)
  构造方法摘要 
  String() 
     初始化一个新创建的 String 对象,使其表示一个空字符序列。 
  String(byte[] bytes) 
     通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。 
  String(byte[] bytes, Charset charset) 
     通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。 
   特有方法:
  byte[] getBytes() 
     使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 
  byte[] getBytes(Charset charset) 
     使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。 
  2)Arrays类(java.util包)
  static String toString(byte[] a) 
     返回指定数组内容的字符串表示形式。 
  static String toString(Object[] a) 

     返回指定数组内容的字符串表示形式。


5.代码示例:
   String s = "你好";
  //String s = "哈哈"
  byte[] b1 = s.getBytes("gbk");
  Sytem.out.println(Arrays.toString(b1));
  String s1 = new String(b1,"iso8859-1");
  //String s1 = new String(b1,"utf-8");//因为utf-8和gbk都可以解码中文字符,所以出现乱码。故常用iso8859-1
  System.out.println("s1="+s1);

  //对s1进行iso8859-1编码。
  byte[] b2 = s1.getBytes("iso8859-1");
  //byte[] b2 = s1.getBytes("utf-8");
  System.out.println(Arrays.toString(b2));
  String s2 = new String(b2,"gbk");
  System.out.println("s2="+s2);
我们看一个有趣的例子:
创建一个记事本内容为“联通”,关闭后再打开显示异常。
我们看看他们对应的GB2312码:
联:C1AA------11000001 10101010
通:CDA8------11001101 10101000
        可见,“联”和“通”刚好符合UTF-8编码的特征(占用两个字节的字符:形式为  110xxxxx 10xxxxxx),所以记事本检查编码格式的时候认为它是UTF-8编码格式的,所以用UTF-8编码来显示。
        当记事本打开文件时,会检查文件中所有字符的编码规则,看他是否遵循某种编码规则,如果所有字符都遵循某一种编码规则,那就用这种字符编码集来显示这个文件。否则就用本地字符集显示文件。


练习题

有五个学生,每个学生有3门课的成绩, 
  1. 从键盘输入以上数据(包括姓名,三门课成绩), 
  2. 输入的格式:如:zhangsan,30,40,60计算出总成绩, 
  3. 并把学生的信息和计算出的总分高低顺序存放在磁盘文件"stud.txt"中。 
  4.  
  5.  1,描述学生对象 
  6.  2,定义一个可操作学生对象的工具类。 
  7.  
  8.  思路: 
  9.  1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。 
  10.  2,因为学生有很多,那么就需要存储,使用到集合,因为要对学生的总分排序。 
  11.   所以可以使用TreeSet. 
  12.  3,将集合的信息写入到一个文件中。 
  13. */  
  14.   
  15. class Student implements Comparable<Student>  
  16. {  
  17. private String name;  
  18. private int cn,en,ma,sum;  
  19. Student(String name,int cn,int en,int ma)  
  20. {  
  21. this.name = name;  
  22. this.cn = cn;  
  23. this.en = en;  
  24. this.ma = ma;  
  25. this.sum = cn+en+ma;  
  26. }  
  27.   
  28.   
  29. public String getName()  
  30. {  
  31. return name;  
  32. }  
  33. public int getSum()  
  34. {  
  35. return  sum;  
  36. }  
  37. public int compare(Student s)  
  38. {  
  39. int num = new Integer(this.sum).compareTo(new Integer(s.sum))  
  40. if(num==0)  
  41. return this.name.compareTo(s.name)  
  42. return num;  
  43. }  
  44. public int hashCode()  
  45. {  
  46. return name.hashCode()+sum*3;  
  47. }  
  48. public boolean equals(Object obj)  
  49. {  
  50. if(!(obj instanceof Student))  
  51. throw new RuntimeException("类型错误");  
  52. Student s = (Student)obj;  
  53. return this.name.equals(s.name) && this.age== s.age;  
  54. }  
  55.   
  56.   
  57. public String toString()  
  58. {  
  59. return "student["+name+","+en+","+cn+","+ma+"]";  
  60. }  
  61. }  
  62.   
  63.   
  64. class StudentTool  
  65. {  

  66. public static Set<Student> getStudents throws IOException{ 
          return  getStudents(null);
          }
  1. public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException{  
  2. BufferedReader bufr =   
  3. new BuffereReader(new InputStreamReader(System.in));  
  4. Set<Student> students = null;
  5. if(cmp==null)
  6. students=new TreeSet<Student>();
  7. else students=new TreeSet<Student>(cmp);

  8. new TreeSet<Student>();  
  9.   
  10. String line = null;  
  11. while((line = bufr.readLine())!= null)  
  12. {  
  13. if("over".equals(line))  
  14. break;  
  15. String[] str = line.split(",");  
  16. Student stu  = new Student(str[0],  
  17. Integer.parseInt(str[1]);  
  18. Integer.parseInt(str[2]);  
  19. Integer.parseInt(str[3]);  
  20.   
  21. students.add(stu);  
  22. }  
  23. bufr.close();  
  24. return students;  
  25. }  
  26.   
  27. public static write2File(Set<Student> students)  throws IOException 
  28. {  
  29. BufferedWriter bufw = new BufferedWriter(new FileWriter("Studentinfo.txt");  
  30. for(Student student : students)  
  31. {  
  32. bufw.write(student.toString+"\t");  
  33. bufw.write(student.getSum()+"");  
  34. bufw.newLine();  
  35. bufw.flush();  
  36. }  
  37. }  
  38. }  
  39. class  StudentInfoTest  
  40. {  
  41. public static void main(String[] args) throws IOException  
  42. {  
  43. Comparator<Student> cmp=Collections.reverseOrder();
  44. Set<Student> stus = StudentTool.getStudents(cmp);  
  45.   
  46.   
  47. StudentTool.write2File(stus);  
  48. }  





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值