黑马程序员——第六章 JavaIO操作

来源:互联网 发布:linux wifi局域网ip 编辑:程序博客网 时间:2024/05/22 05:11

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


异常

定义:程序的运行时候出现的不正常现象。

 

异常的继承体系

Throwable类是所有异常和错误的父类。

 Error错误:程序出现了严重的问题,不修改代码,根本不能运行。

 Exception异常:程序出现了比较轻的问题,处理掉之后,继续运行。

Exception类是所有异常的父类。

 

Throwable中的方法:

StringtoString()重写Object类的方法,异常信息的详细描述。

StringgetMessage() 返回异常信息的简短描述。

voidprintStackTrace() 异常信息输出到控制台。

编译异常和运行异常

编译时期异常:当你调用一个方法,这个方法抛出异常,调用者必须处理,否则编译失败,处理方式:可以try或者抛。

运行时期异常:RuntimeException类和他的所有子类,都称为运行时期异常,方法中如果抛出的异常是运行时期异常,处理方式:方法中try catch throw,不需要throws。

try catch处理异常。

运行时期异常的设计初衷:运行时起异常不能出现的,一旦发生,不要处理异常。程序必须停下,修改源代码。

 

常见运行时期异常

IndexOutOfBoundsException越界异常

NullPointerException空指针异常

ClassCastException 类型转换异常

NoSuchElementException没有元素被取出异常

IllegalArgumentException 无效参数异常

 

异常的处理方式

1,try catch处理

格式:

   try{

      检测的代码

      有可能发生异常的代码

    }catch(异常类 变量){

       异常的处理方式(循环,判断,调方法)

       有catch,就可以称为异常被处理了

   }


2,throws  throw抛出异常给调用者

 throw:写在方法中,手动抛出异常,后面接 new 异常对象。

 throws:写在方法的声明上,方法声明抛出异常,后面接异常类。

 

finally代码块

finally代码块中的程序,必须要运行,有释放资源意义。

finally跟随try出现,不能进行异常处理,必须抛出。

finally也可以跟随try...catch出现。

 

自定义异常

步骤:

定义类,后缀名Exception 继承Exception类,或者继承RuntimeException,自定义的异常类的构造方法中,把异常信息使用super传递到父类。

注意:

1,只有异常类,才具备可抛性,throw  new 异常体系的类。

2,如果一个方法中,抛出多个异常,必须要throws声明多个异常(运行时期除外)

调用者,使用多个catch进行异常的捕获,多个catch中,最大(继承关系)的父类,必须写在最后面,否则编译失败。

3,RuntimeException以及其子类如果在函数中被throw抛出,可以不用在函数上声明。

4,父类的方法抛异常,子类重写方法后,可抛可不抛,如果子类抛,不能抛出比父类还大的异常。

5,父类的方法不抛异常,子类重写方法后,子类不能抛出异常,只能try...catch处理异常。

 

IO流

IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,Java用于操作流的类都在java.io包中。

 

IO流的划分:

按流向分为两种:

输入流:程序读取文件。

输出流:程序写入文件。

按操作类型分为两种:

字节流 : 开始于JDK1.0,字节流可以操作任何数据,每次操作1个字节8个二进制,不查询编码表。

字符流 : 开始JDK1.1,字符流专门用于操作文本文件,方便Java程序操作纯文本,每次操作1个字符16个二进制,会查询本机默认的编码表。

文本文件:.txt  .java  .html .xml  .css文件等

 

IO流的书写

使用前,导入IO包中的类。

使用时,进行IO异常处理。

使用后,释放资源。

 

字符流

字符流的抽象父类:Reader和Writer

 

字符输出流

Writer类,抽象的,找子类 FileWriter 写入字符文件的便捷类。

写入顺序:

1,创建子类FileWriter对象,使用子类的构造器,传递String文件名。

2,子类对象调用父类方法write( )写文件。

3,flush( )刷新该流的缓冲。

4,close( )关闭流对象。

一旦流对象关闭,不能再次使用。

 

写入方式

1,写入字符串,write(String str)

2,写入单个的字符,write(int i)

3,写入字符数组,write(char[] c)

4,写入字符数组一部分,write(char[] c,int start,int length)

 

字符输入流

Reader类,抽象类,找子类FileReader读取字符文件的便捷类。

读取顺序:

1,创建子类FileReader对象,使用子类构造器,传递String文件名。

2,在调用父类方法read( )读取文件

3,close( )关闭流对象。

一旦流对象关闭,不能再次使用。

 

读取方式

1,读取单个字符,read()

2,读取字符数组,read(char[] c)

3,读取字符数组一部分,read(char[] c,int off, int len)

读取到文件末尾,返回-1

 

文件的复制效果--带异常处理

 

BufferedWriter类

  字符输出流缓冲区BufferedWriter,提高字符流的输出效率。

 BufferedWriter,也是Writer的子类,Writer类的方法都可以用,必须有一个输出流对象配合使用,newBfferedWriter(new FileWriter( ))

特有方法

 void newLine()文本中,写换行,具有跨平台性。

Windows中换行,newLine( )写的是\r\n   

Linux中换行,newLine( )写的是\n

 

BufferedReader类

  字符输入流的缓冲区BufferedReader,提高字符流的输入效率。

 BufferedReader也是Reader的子类,Reader的方法,都可以用,也需要一个输入流对象配合使用,newBufferedReader(new FileReader( ))

特有方法

 String readLine()读取文本一行,返回字符串。

读取到文件末尾,返回null

字节流

字节流的抽象父类:InputStream和OutputStream

 

字节输出流

OutputStream类,抽象的,找子类 FileOutputStream写入任意文件的便捷类。

写入顺序:

1,创建子类FileOutputStream对象,使用子类的构造器,传递String文件名。

2,子类对象调用方法write( )写文件。

3,close( )关闭流对象。

一旦流对象关闭,不能再次使用。

 

写入方式

1,写入单个的字节,write(int i)

2,写入字节数组,write(byte[] c)

3,写入字符数组一部分,write(byte[] c,int start,int length)

 

字节输入流

InputStream类,抽象类,找子类FileInputStream读取任意文件的便捷类。

读取顺序:

1,创建子类FileInputStream对象,使用子类构造器,传递String文件名。

2,在调用方法read( )读取文件

3,close( )关闭流对象。

一旦流对象关闭,不能再次使用。

 

读取方式

1,读取单个字节,read()

2,读取字节数组,read(char[] c)

3,读取字节数组一部分,read(char[] c,int off, int len)

读取到文件末尾,返回-1

 

BufferedOutputStream

字节输出流缓冲区BufferedOutputStream,提高字节流的输出效率。

 BufferedOutputStream,也是OutputStream的子类,OutputStream类的方法都可以用,必须有一个输出流对象配合使用。

new BufferedOutputStream (newFileOutputStream ( ))

 

BufferedInputStream

字节输入流的缓冲区BufferedInputStream,提高字节的输入效率。

 BufferedReader也是InputStream的子类,InputStream的方法,都可以用,也需要一个输入流对象配合使用。

new BufferedInputStream (newFileInputStream ( ))

 

标准输入输出流

它们各代表了系统标准的输入和输出设备,默认输入设备是键盘,输出设备是显示器。

System.in:类型是InputStream,标准输入流, 默认可以从键盘输入读取字节数据。

System.out:类型是PrintStream,标准输出流,是OutputStream的子类FilterOutputStream 的子类。

 

转换流

字节转成字符

InputStreamReader,本身是一个字符流,继承Reader,字节流向字符的桥梁。

转换顺序:

1,  InputStreamReader构造方法中,传递字节输入流。

2,  BufferedReader(Reader r) 可以缓冲这个转换流,进行行读取。

 

字符转成字节

OutputStreamWriter, 继承Writer,也是一个字符流,字符流向字节的桥梁。

转换顺序:

1,  BufferedWriter(Writer w)写入字符流

2,  OutputStreamWriter构造方法中,传递字节输出流。

 

转换流的好处,在于数据源和数据目的,可以随时改变,但是转换流是字符流,只能处理文本数据。

 

转换流编码效果

  流对象,没有指定查询哪一个码表,默认走操作系统的中GBK

  转换流OutputStreamWriter构造方法中,写一个字节输出流,写编码表的名字(String)不区分大小写,转换流会将文本数据,以指定的编码形式写入文件。

  转换流InputStreamReader构造方法中,写一个字节输入流,写编码表的名字(String)不区分大小写,转换流会将文本数据,以指定的编码形式读取文件。

 

字符的编码和解码

编码:字符串à字节数组

解码:字节数组à字符串

 

编码表:

ASCII:美国标准信息交换码,用一个字节的7位可以表示。

ISO8859-1:拉丁码表,欧洲码表,java网络服务器Tomcat,用一个字节的8位表示。

GB2312:中国的中文编码表,2个字节 对应1个汉字,4000左右汉字。

GBK:中国的中文编码表升级,2个字节对应1个汉字,20000个汉字。

Unicode:国际标准码,融合了多种文字,所有文字都用两个字节来表示,Java语言使用的就是unicode

UTF-83个字节对应1个汉字。

 

编码方法:String类方法getBytes(编码表名)

解码方法:String类的构造方法(字节数组,编码表名)

 

File类

  将文件或文件夹路径封装成File对象,File类提供方法来操作这些对象。

 File类,不属于流对象,不能读写文件。

 File类的对象,可以作为参数,传递给流对象的构造方法.

 File类方法,熟练掌握,用方法操作路径和文件夹,必须能够配合流对象实现更多功能。

绝对路径: 从盘符开始, 是一个固定的路径

相对路径: 不从盘符开始, 相对于某个位置。在Eclipse中的Java工程相对于工程根目录. cmd则相对应于当前目录。

 

File类的静态常量

目录分隔符,Windows中为“\” Linux中为“/”

public static String separator,返回String

public static char separatorChar,返回char

 

路径分隔符,Windows中“ ; ” Linux中为“:”

public static String pathSeparator,返回String

public static char pathSeparatorChar,返回char

 

File类构造方法

File(String pathname)传递字符串的路径。

File(String parent,String child)传递字符串的父路径,字符串的子路径。

File(File parent,String child)传递File父路径,字符串的子路径。

 

File类创建方法

boolean createNewFile() 创建文件,创建的是File构造方法中封装的路径,创建成功返回真,失败返回假。如果文件有,不在创建。只能创建文件。

boolean mkdir()创建文件夹,创建的是File构造方法中封装的路径,创建成功返回真,失败返回假。如果存在就不在创建。只能创建文件夹,能创建一级目录。

boolean mkdirs()可以创建多级目录,用法和mkdir完全一致,推荐使用。

 

File类的删除方法

boolean delete()删除构造方法中指定的路径,删除成功返回真,失败返回假。删除的时候,不走回收站,直接永久删除。删除一个文件夹时,只能删空文件夹。

void delectOnExit()删除构造方法中指定的路径,延迟删除,等JVM退出之前再删除。

 

File类的判断方法

boolean exists()判断File构造方法中封装的路径是不是存在,如果存储在返回真,不存在返回假。

boolean isAbsolute()判断File构造方法中封装的路径是不是绝对路径,如果是返回真,不是返回假。

boolean isDirectory()判断File构造方法中封装的路径是不是一个文件夹,如果是文件夹返回真,不是返回假。

boolean isFile()判断File构造方法中封装的路径是不是文件,如果是文件返回真,不是文件返回假

boolean isHidden()判断File构造方法封装的路径是不是隐藏属性,是隐藏属性返回真,不是返回假

 

File类的获取方法

String getName()获取到File构造方法中封装的路径的最后部分的名字。

String getParent()返回File构造方法中封装的路径的父路径,返回字符串,如果没有父路径返回null。

File getParentFile()返回File构造方法中封装的路径的父路径,返回的是一个File对象,如果没有父路径返回null。

String getAbsolutePath()返回File构造方法中封装的路径的绝对路径,返回的是一个String类对象。

File getAbsoluteFile()返回File构造方法中封装的路径的绝对路径,返回值是一个File对象。

 

File类的其他方法

boolean renameTo(File f)重命名,File封装一个路径,这个对象调用renameTo(修改后的路径的File对象),修改成功返回真,失败返回假。修改名字后路径不同,方法renameTo带有剪切效果。

long lastModified()返回File封装的路径中文件的最后修改时间的毫秒值。

static File[] listRoots()返回系统根,封装成File对象,存储数组。

String[] list()返回File构造方法封装的路径下的所有文件和文件夹。返回String

File[] listFiles()返回File构造方法封装的路径下的所有文件和文件夹,返回的Filed对象,带全路径。

 

list开头方法的文件过滤器

根据自己的需要,遍历目录的时候,只获取想要的文件,其他文件全部过滤。

过滤器FileFilter是一个接口,需要定义类实现FileFilter接口,重写方法accept,把实现类的对象,传递给listFiles()方法。

例:File file = new File("f:\\");

File[] files = file.listFiles(new MyFileFilter());

或者:

File[] files = file.listFiles(new FileFilter( ) {

                     publicboolean accept(File pathname) {

                            returnpathname.getName().endsWith(".hetml");

                     }

              });

 

递归

递归:编程技巧,方法自身调用自己。

适用情况:当某一功能要重复使用时,方法的运算主体不变,每次运行的参数在变化。

 

递归的好处和弊端:

好处:可以不知道循环次数(方法调用次数)。

弊端:有可能会栈内存溢出。

 

递归的注意事项:

1,  递归一定要有条件限制,否则就死循环。

2,  递归,方法进栈的次数不能太大。

3,  构造函数不能使用递归,因为若可以,将不断创建对象,永不停止。

4,  递归调用可以有返回值也可以没有。

   

打印流

该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷新的模式。

打印流不抛异常,因为只操作数据目的,不操作数据源。 

第一个打印流是字节输出流PrintStream ,System.out 返回值结果是PrintStream

第二个打印流是字符输出流PrintWriter,实现类PrintStream中的所有打印方法。

 

PrintStream类和PrintWrtier类的关系

共性:负责打印数据,不抛异常,不操作数据源,都有很多打印方法。

区别:一个是字节流,一个是字符流,两个流的构造方法。

  PrintStream构造方法,传递的都是数据目的,接收File对象,字节输出流,字符串的文件名,三种类型参数。

  PrintWrtier构造方法,传递的都是数据目的,接收File对象,字符输出流,字符串的文件名,字符输出流,四种类型参数。

  若构造方法中的参数是流对象,在流对象的构造方法的参数中加上true,就可以开启打印流的自动刷新功能。

   如果启用自动刷新,则必须调用三个方法之一:println、printf、format

 

对象操作流 

对象的序列化

将对象的数据写到文件中。

写对象数据的流 ObjectOutputStream,构造方法中,传递字节输出流 OutputStream子类FileOutputStream,写的方法void writeObject(Object obj)将对象中的数据,写入到字节输出流包装的文件。

例:ObjectOutputStreamoos =

                            new ObjectOutputStream(newFileOutputStream("f:\\Person.txt"));

Person p = new Person("张三", 18);

oos.writeObject(p);

oos.close();

关键字transient,修饰符,只能用在成员变量的修饰上,阻止变量序列化。

 

对象的反序列化

将文件中保存的对象的数据读取出来。

读取对象数据的流ObjectInputStream,构造方法中,传递字节输入流InputStream子类FileInputStream,读取对象的方法 Object readObject() 读取文件中的对象,返回Object。

  抛出类找不到异常. 必须有class文件,否则不能实现

例:ObjectInputStream ois =

                            new ObjectInputStream(newFileInputStream("f:\\Person.txt"));

              Object o = ois.readObject();

              ois.close();

对象的类必须实现Serializable接口,如果不实现这个接口,无法序列化和反序列化。

 

序列化中的序列号问题

  序列号冲突:编译Person.java生成class,class文件中就保存了这个类的序列号,此时对类进行了序列化操作,生成序列化文件person.txt,保存了一个序列号,这个号和class文件中的序列号是一致的。修改了Person.java源文件,将private修改成了public,从新编译class,序列号发生变化了,从新读取了序列化文件,此时的文件中保存的序列号和class文件中的序列号不一致,因此发生异常。

  修改源代码后,不让JVM重新计算序列号,就要自定义序列号。

例:static finallong serialVersionUID = 7865432134587654321L;

集合IO的结合使用

集合使用的是Hashtable的子类Properties。存储键值对的集合,不能存储null,并且是一个线程安全的集合。两个自己的方法setProperty ,getProperty。

Properties类的方法load(字节或者字符输入流),文件中的键值对就会自动被存储到集合中。

 配置文件中,存储键值对的文件,不想要这个键值对,使用#注释

Properties类的方法store(字节或字符输出流,字符串)将集合中的键值对自动保存回原来的文件中。

 

集合IO综合练习题

  题目要求: 已知一个文本,保存的是学生的姓名,考试成绩

  对成绩进行排序,成绩相同,按照姓名排,排序后的结果存储到新的文件中,文件的名字有要求,如果原始文件名字 score.txt  新生成排序后的文件 sortScore.txt

例:

/*

 * 需求:

 * 1,已知一个文本,保存的是学生的姓名,考试成绩,要求对成绩进行排序。

 * 2,成绩相同的,按照姓名排,排序后的结果存储到新的文件中。

 * 3,如果原始文件名字 score.txt,新生成排序后的文件 sortScore.txt

 */

import java.io.*;

import java.util.*;

public class ScoreSort {

   public static voidmain(String[] args) throws Exception {

          // 原始文件,封装到File对象

          File source = new File("c:\\score.txt");

          // IO流读取文件,按行读取

          BufferedReader bfr = new BufferedReader(newFileReader(source));

          // 创建集合对象

          List<Student> list = new ArrayList<Student>();

          // 读取后,切割字符,存到集合

          String line = null;

          while ((line = bfr.readLine()) != null) {

                 String[] str =line.split(" +");

                 list.add(newStudent(str[0], Integer.parseInt(str[1])));

          }

          // 关闭流

          bfr.close();

          bfr = null;

          // 对List集合进行排序

          Collections.sort(list, Collections.reverseOrder());

          // 迭代集合,将集合中数据,写到新的文件中

          // 获取源文件名

          String filename = source.getName();

          StringBuilder sb = new StringBuilder(filename);

          // 把s变为S

          char ch = (char) (sb.charAt(0) - 32);

          sb.setCharAt(0, ch);

          sb.insert(0, "sort");

          // 获取数据源目录的父路径

          String parent = source.getParent();

          // 父路径和文件名组成新的File对象

          File sort = new File(parent, sb.toString());

          // 创建打印流对象,包装File sort对象,开启自动刷新

          PrintWriter pw = new PrintWriter(new FileWriter(sort), true);

          // 遍历集合

          for (Student s : list) {

                 pw.println(s.getName()+ "  " + s.getScore());

          }

          pw.close();

   }

}

 

基本数据操作流

DataOutputStream写基本数据类型

继承OutputStream,字节输出流

构造方法中,传递字节输出流 FileOutputStream

写基本数据类型的方法writeInt(int),将4个字节的int值写入输出流。

 

DataInputStream读取基本数据类型

继承InputStream,字节输入流

构造方法中,传递字节输入流FileInputStream

读取基本数据类型的方法 int readInt(),4个字节读取。

读取到文件末尾抛出EOFException,利用异常进行循环读取。

 

字节数组操作流

ByteArrayInputStream,读取内存中的字节数组,不占用操作系统底层资源,无需关闭。构造方法中传递字节数组。

 

ByteArrayOutputStream,往内存中写字节数组,不占用操作系统的资源,无需关闭,空参数构造方法。

byte[] toByteArray,流中的数组返回来。

String toString,将流中的字节数组,变成字符串,默认编码表GBK

String toString(String字符集名字)将流中的字节数组,变成字符串,指定编码表。

例:

FileInputStreamfis = new FileInputStream("a.txt");//创建字节输入流,关联a.txt

ByteArrayOutputStreambaos = new ByteArrayOutputStream();//创建内存输出流

byte[] arr = newbyte[5]; //创建字节数组,大小为5

int len;

while((len =fis.read(arr)) != -1) {//将文件上的数据读到字节数组中

   baos.write(arr, 0, len); //将字节数组的数据写到内存缓冲区中

}

System.out.println(baos);//将内存缓冲区的内容转换为字符串打印

fis.close();

 

随机读写流RandomAccessFile

  非常特殊的流对象,拥有读和写的能力,这个类中封装了一个大型字节数组,数组的下标,看成是这个文件的指针

 seek(long l)方法对指针定位。

  随机读写:可以中文件中的任意位置进行读和写。

  构造方法,String filename , String mode 读取模式

 

0 0
原创粉丝点击