黑马程序员——IO笔记 第十三篇

File类、IO流类、其他流

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

File类

File类的构造方法:

File(String pathname)   指定一个文件或者文件夹的路径构建一个File对象. 

File(File parent, String child)  根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例     

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

 

File类常用的方法:

创建:

    createNewFile() 在指定位置创建一个空文件,成功就返回true,如果已存在就不创建然后返回false

    mkdir()         在指定位置创建目录,这只会创建最后一级目录,如果上级目录不存在就抛异常。

    mkdirs()        在指定位置创建目录,这会创建路径中所有不存在的目录。

    renameTo(File dest) 重命名文件或文件夹,也可以操作非空的文件夹,文件不同时相当于文件的剪切,剪切时候不能操作非空的文件夹。移动/重命名成功则返回true,失败则返回false。

 

删除

    delete()        删除文件或一个空文件夹,如果是文件夹且不为空,则不能删除,成功返回true,失败返回false。

    deleteOnExit()  在虚拟机终止时,请求删除此抽象路径名表示的文件或目录,保证程序异常时创建的临时文件也可以被删除

 

判断:

    exists()        文件或文件夹是否存在。

    isFile()        是否是一个文件,如果不存在,则始终为false。

    isDirectory()   是否是一个目录,如果不存在,则始终为false。

    isHidden()      是否是一个隐藏的文件或是否是隐藏的目录。

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

获取:

    getName()       获取文件或文件夹的名称,不包含上级路径。

    getPath()       返回绝对路径,可以是相对路径,但是目录要指定

    getAbsolutePath()   获取文件的绝对路径,与文件是否存在没关系

    length()        获取文件的大小(字节数),如果文件不存在则返回0L,如果是文件夹也返回0L。

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

    lastModified()  获取最后一次被修改的时间。

文件夹相关:

staic File[] listRoots() 列出所有的根目录(Window中就是所有系统的盘符)

list()                   返回目录下的文件或者目录名,包含隐藏文件。对于文件这样操作会返回null。

list(FilenameFilter filter) 返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。

listFiles()                 返回目录下的文件或者目录对象(File类实例),包含隐藏文件。对于文件这样操作会返回null。

listFiles(FilenameFilter filter)   返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。

 

 

   

IO流类

    判断输入输出流的依据:以程序作为参照物

   

    按照流向划分(输入流、输出流)   

    按照处理的单位划分:

        字节流:字节流每次都读写一个字节的数据,读到的数据不会经过处理。

        字符流:处理的是以字符为单位的流。 字符流 = 字节数据 + 解码(编码)

 

字节流

    输入字节流:

    -------------|InputStream 

    ---------------| FileInputStream  读取文件字节的输入字节流。

    ---------------| BufferedInputStream缓冲输入字节流、 实际内部维护了一个8kb的字节数组。 缓冲输入字节流主要的目的就是为了提高读取文件数据的效率。

 

如何使用FileInputStream?

    1、找到目标文件

    File file = new File(path);

    2、建立程序与数据的输入通道

    FileInputStream fileInputStream = new FileInputStream(file);

    3、读取文件数据

    int content = fileInputStream.read();

    4、关闭资源

    fileInputStream.close();

 

四种方式读取文件

public class Demo1 {

    public static void main(String[] args) throws IOException {

       readTest4();

    }

   

    //第四种读取方式:使用缓冲数组读取    12G

    public static void  readTest4() throws IOException{  // 16755

       long startTime = System.currentTimeMillis();

       //第一步:找到目标文件

       File file = new File("F:\\美女\\4.mp3");

       //第二步:建立数据与程序的输入通道

       FileInputStream fileInputStream  = new FileInputStream(file);

      

       //第三步:使用缓冲数组配合循序读取数据

       byte[] buf = new byte[1024*8];  // 缓冲数组的大小一般是1024的倍数. 这样子理论上的效率会更高。

       int  length = 0 ; //用于保存读取到的字节个数。  

      

       while((length = fileInputStream.read(buf))!=-1){  // {97 98 99  }

           System.out.println(new String(buf,0,length));

       }

       //关闭资源

       fileInputStream.close();

      

       long endTime = System.currentTimeMillis();

       System.out.println("耗费的时间:"+ (endTime- startTime));

    }

   

    //第三种读取方式:使用缓冲数组读取     缺点:读取不完整文件数据。      12G

    public static void readTest3() throws IOException{

       //第一步:找到目标文件

       File file  =  new File("F:\\a.txt");

       //第二步:建立数据与程序的输入通道

       FileInputStream fileInputStream = new FileInputStream(file);

       //第三步:使用缓冲字节数组读取文件的数据

       byte[] buf = new byte[1024];

      

       int length  = fileInputStream.read(buf);  // read(byte[] buf这个方法读到的数据是存储到了字节数组中了,返回值是存储到字节数组中的字节个数。

       System.out.println("length : "+ length);

       System.out.println(new String(buf,0,length));

      

       //关闭资源

       fileInputStream.close();

      

    }

   

    //第二种读取方式:

    public static void readTest2() throws IOException{  // 562

       long startTime = System.currentTimeMillis();

       //第一步:找到目标文件

       File file = new File("F:\\美女\\1.jpg");

       //第二步:建立数据与程序的输入通道

       FileInputStream fileInputStream = new FileInputStream(file);

       //第三步:读取文件的数据。

       int content = 0 ; //定义一个变量用于保存读取到的数据

      

       while( (content = fileInputStream.read())!=-1){

           System.out.print((char)content);

       }

       //关闭资源

       fileInputStream.close();

       long endTime = System.currentTimeMillis();

       System.out.println("耗费的时间:"+ (endTime- startTime));

   

    }

   

    //缺点:没法读取完整一个文件的数据。

    public static void readTest1() throws IOException{

       //第一步:找到目标文件

       File file = new File("F:\\a.txt");

       //第二步:建立程序与数据的输入通道。

       FileInputStream fileInputStream = new FileInputStream(file);

       //第三步:读取文件的数据。

       int  contentfileInputStream.read(); //read() 读取一个字节的数据。返回值就是把读到的数据返回。

       System.out.println((char)content);  //为什么读取出来的是97而不是a,其实97就是a对应的码值。

       //第四步:关闭资源   释放资源文件。

       fileInputStream.close();       

    }

}

 

 

    输出字节流:

    -------------| OutputStream 所有输出字节流的基类。抽象类

    ---------------| FileOutputStream   读取文件输入的字节流

    ---------------| BufferedOutputStream 缓冲输出字节流。  实际内部维护了一个8kb的字节数组。

FileOutputStream 注意细节:

1、 使用FileoutputStream 的时候,如果目标文件不存在时会自动创建一个目标文件。

2、 使用FileoutputStream 写数据时,默认情况先清空文件的数据,然后再写入;如果需要追加数据,那么可以使用new FileOutputStream(file , append)的构造方法,第二参数为true即可。

3、 使用FileOutputStream的write方法写数据的时候,虽然write接收的是一个int类型的数据,但是只会把int类型数据的低八位写出去,其他24位全部丢弃。

 

BufferedInputStream缓冲器本身不具备读写能力,要使用时,必须借助FileInputStream  

 

BufferedInputStream 注意的细节

1.  BufferedInputStream 的close方法实际上关闭的是你传递进去的InputStream对象流。

 

public class Demo1 {

   

    public static void main(String[] args) throws IOException {

       readTest();

    }

   

    //使用缓冲流读取文件的数据

    public static void readTest() throws IOException{

       //找到目标文件

       File file = new File("F:\\a.txt");

       //建立数据的输入通道

       FileInputStream fileInputStream = new FileInputStream(file);

       //创建缓冲输入字节流

       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); 

       //疑问一:为什么BufferedInputStream要接收一个FileInputStream ,目的是做什么?

       //因为:凡是缓冲流的作用都是为了提高读或者写的效率,凡是缓冲流都不具备读写文件的能力。

      

       //读取数据

       int content = 0;

       byte[] buf = new byte[1024];

       while((content =bufferedInputStream.read() )!=-1){

           //疑问: FileInputStream read方法一次也是读取一个字节数据,BufferedInputStreamread方法一次也是读取一个字节的数据,

           //BufferedInputStream出现的目的是为了提高我们读取文件的效率,那么两个read方法都是一次读取一个字节,效率高从何而来?

          

           System.out.print((char)content);

       }

       //关闭资源

       bufferedInputStream.close();

    }

   

    public static void  readTest4() throws IOException{  // 16755

       long startTime = System.currentTimeMillis();

       //第一步:找到目标文件

       File file = new File("F:\\美女\\4.mp3");

       //第二步:建立数据与程序的输入通道

       FileInputStream fileInputStream  = new FileInputStream(file);

      

       //第三步:使用缓冲数组配合循序读取数据

       byte[] buf = new byte[1024*8];  // 缓冲数组的大小一般是1024的倍数. 这样子理论上的效率会更高。

       int  length = 0 ; //用于保存读取到的字节个数。  

      

       while((length = fileInputStream.read(buf))!=-1){  // {97 98 99  }

           System.out.println(new String(buf,0,length));

       }

       //关闭资源

       fileInputStream.close();

       long endTime = System.currentTimeMillis();

       System.out.println("耗费的时间:"+ (endTime- startTime));

    }

}

 

疑问:

BufferedInputStream 与FileInputStream 的read方法每次都是读取一个字节的数据,为何BufferedInputStream 的读取文件效率较高?

    BufferedInputStream 的实现原理:每次read的方法的时候都会去坚持它内部维护了缓冲字节数组是否已经被取光,如果中取光了,那么再去读取8Kb的字节数据回来放到缓冲字节数组,否则会直接从缓冲数组返回一个字节的数据。

 

IO字节流异常处理

public class Demo1 {

    public static void main(String[] args) {

       readTest();

    }

   

    //拷贝图片

    public static void copy(){

       FileInputStream fileInputStream  = null;

       FileOutputStream fileOutputStream = null;

      

       try{

           //找到目标文件

           File inFile = new File("F:\\美女\\1.jpg");

           File outFile = new File("F:\\美女\\1.jpg");

           //建立数据的输入输出通道

           fileInputStream = new FileInputStream(inFile);

           fileOutputStream = new FileOutputStream(outFile);

           //边读边写

           byte[] buf = new byte[1024];

           int length = 0 ;

           while((length = fileInputStream.read(buf))!=-1){

              fileOutputStream.write(buf,0,length);

           }

          

       }catch(IOException e){

           System.out.println("读取文件出错了...");

           throw new RuntimeException(e);

       }finally{

           try {

              if(fileOutputStream!=null){              

                  fileOutputStream.close();

              }

           } catch (IOException e) {

              System.out.println("关闭资源失败...");

              throw new RuntimeException(e);

          

           }finally{

              try {

                  if(fileInputStream!=null){

                     fileInputStream.close();

                  }

              } catch (IOException e) {

                  System.out.println("关闭输入流对象失败了...");

                  throw new RuntimeException(e);

              }

           }

       }

    }

   

    //读取文件

    public static void readTest(){

       FileInputStream fileInputStream  = null;

       try{

           //找到目标文件

           File file = new File("F:\\abc.txt");

           //建立数据的输入通道

           fileInputStream = new FileInputStream(file);

           //读取文件的数据

           byte[] buf = new byte[1024];

           int length = 0 ;

           while((length = fileInputStream.read(buf))!=-1){

              System.out.println(new String(buf,0,length));

           }

       }catch(IOException e){

           System.out.println("读取文件失败....");

           throw  new RuntimeException(e);  //把错误的真正原因包装到RuntimeException中再抛出去。

       }finally{

           //释放资源

           try{

              if(fileInputStream!=null){ // 先判断是否空指针

                  fileInputStream.close();

                  System.out.println("关闭资源成功....");

              }

           }catch(IOException e){

              System.out.println("关闭资源失败...");

              throw new RuntimeException(e);

             

           }

       }

    }

}

 

字符流

常见的码表如下:

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

ISO8859-1:   拉丁码表。欧洲码表,用一个字节的8位表示。又称Latin-1(拉丁编码)或“西欧语言”。ASCII码是包含的仅仅是英文字母,并且没有完全占满256个编码位置,所以它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号,

藉以供使用变音符号的拉丁字母语言使用。从而支持德文,法文等。因而它依然是一个单字节编码,只是比ASCII更全面。

GB2312:   英文占一个字节,中文占两个字节.中国的中文编码表。

GBK:      中国的中文编码表升级,融合了更多的中文文字符号。

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

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

 

ISO8859-1:一个字节

GBK:两个字节包含了英文字符和扩展的中文   ISO8859-1+中文字符

UTF-8 万国码,推行的。是1~3个字节不等长。英文存的是1个字节,中文存的是3个字节,是为了节省空间。

 

字符流 = 字节流 + 编码(解码)

输入字符流

----------|Reader 所有输入字符流的基类。抽象类

------------|FileReader读取文件字符数据的输入字符流。

------------|BufferedReader 缓冲输入字符流,主要是为了提高读取数据的效率,还拓展了FileReader的功能。 readLine();

BufferedReader 的使用步骤

    1.找到目标文件。

    2.建立数据的输入通道。

    3.建立缓冲输入字符流。

    4.读取文件数据。

    5.关闭资源

 

public class Demo2 {

    public static void main(String[] args) throws IOException {

       readTest2();

    }

   

    //使用缓冲区,配合循序读取、

    public static void readTest2() throws IOException{

       //找到目标文件

       File file = new File("F:\\a.txt");

       //建立数据的输入通道

       FileReader fileReader = new FileReader(file);

       //创建一个字符缓冲数组,读取文件的数据

       char[] buf = new char[1024];

       int length = 0 ; //定义该变量是用于记录读到的字符个数。

       while((length = fileReader.read(buf))!=-1){ // 读到的内容都是存储到了字符数组中,length是记录了本次读到了多少个字符数据。

           System.out.println(new String(buf,0,length));

       }

       //关闭资源

       fileReader.close();

    }

   

    //使用输入字符流     读取不完整文件数据

    public static void readTest() throws IOException{

       //找到目标文件

       File  file = new File("F:\\b.txt");

       //建立数据的输入通道

       FileReader fileReader = new FileReader(file);

       //读取字符数据

       int content = fileReader.read();  //读取单个字符

       System.out.println((char)content);

       //关闭资源

       fileReader.close();

    }

}

 

BufferedReader每次可以读取一行

public static void bufferedTest() throws FileNotFoundException, IOException {

       //找到目标文件

       File file = new File("F:\\a.txt");

       //建立数据的输入通道

       FileReader fileReader = new FileReader(file);

       //建立缓冲输入字符流对象

       BufferedReader bufferedReader = new BufferedReader(fileReader);

       //读取数据

   

       String line = null ; //bufferedReader.readLine(); //readLine方法一次读取一行文本。

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

           System.out.println(Arrays.toString(line.getBytes()));                 // \r \ n 10 13

       }

       //关闭资源

       bufferedReader.close();

    }

 

 

输出字符流

 

----------|Writer  所有输出字符流 的基类。  抽象类

-------------|FileWriter 向文件输出字符数据的输出字符流

-------------|BufferedWriter 缓存输出字符流,主要也是为了提供写出数据的效率,还拓展了FileWriter 的功能,newLine();

FileWriter的使用步骤:

    1. 找到目标文件。

    2. 建立数据的输出管道。

    3. 写数据。

    4. 关闭资源。

 

FileWriter注意的事项

1. 使用FileWriter的时候,如果目标文件不存在,那么FileWriter会自动创建目标文件。

2. 使用FileWriter的时候,默认是会先清空文件中的内容,然后再写入数据的,如果需要追加数据,那么需要使用FileWriter(File file, boolean append)这个构造函数,第二个参数为true,这时候就是追加文件数据。

3. FileWrirter 内部是维护了一个字符数组的,当调用writer方法的时候,数据是写入到内部维护的字符数组中,如果真正需要把数据写入需要调用flush方法或者是close方法的。 它内部的字符数组是1024个字符。

 

总结:

什么情况才使用字符流?

            只有数据是要使用文本形式展示给用户查看的,才使用字符流。

什么时候使用字节流?  比如: 图片、 视频、 word ...

            如果数据不需要以字符的形式展示出来,那么就可以使用字节流。

 

   

装饰者设计模式 (增强设计模式):

步骤:

1.  在增强类中维护者一个需要被增强类的引用。

2.  让这些装饰类有一个共同的父类(接口),已达到可以互相装饰的效果。

疑问:为什么要让这些装饰类有一个共同的父类,目的是什么?

目的是为了这几个有一个共同父类,然后达到互相装饰的效果。(一般达到增强类的功能)

 

装饰器与继承:

问题:

    修饰模式做的增强功能按照继承的特点也是可以实现的,为什么还要提出修饰设计模式呢?

继承实现的增强类和修饰模式实现的增强类有何区别?

    继承实现的增强类:

       优点:代码结构清晰,而且实现简单

       缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大。

修饰模式实现的增强类:

       优点:内部可以通过多态技术对多个需要增强的类进行增强

       缺点:需要内部通过多态技术维护需要增强的类的实例。进而使得代码稍微复杂。

 

//带行号的缓冲类   增强类

class BufferedLineNum2 extends BufferedReader{

    BufferedReader bufferedReader;

    int count = 1;

   

    public BufferedLineNum2(BufferedReader bufferedReader){

       super(bufferedReader); //注意:BufferedReader没有无参的构造方法,这一句话主要的目的就是为了不报错。没有任何的作用。

       this.bufferedReader = bufferedReader;

    }

   

    public String readLine() throws IOException {

       String line = bufferedReader.readLine(); //这里的readLine方法是调用传递进来的缓冲类的readLine方法,与父类无关。

                                          //父类只不过是为了让他们可以互相传递对方的对象而已。

       if(line==null){

           return null;

       }

       line = count+ " "+ line;

       count++;

       return line;

    }

}

 

//带分号

class BufferedSemi2 extends BufferedReader{

   

    BufferedReader bufferedReader;

   

    public BufferedSemi2(BufferedReader bufferedReader){  // BufferedReader bufferedReader = new BufferedLineNum();

       super(bufferedReader);

       this.bufferedReader = bufferedReader;

    }

   

    public String readLine() throws IOException {

       String line = bufferedReader.readLine(); //问题:如何才能让这里的readLine方法是使用BufferedLineNumReadLine方法呢?

       if(line==null){

           return null;

       }

       line = line+";";

       return line;

    }

}

 

//带双引号

class BufferedQuto2 extends BufferedReader{

   

    BufferedReader bufferedReader;

   

    public BufferedQuto2(BufferedReader bufferedReader){ //BufferedReader bufferedReader = new  BufferedSemi2()

       super(bufferedReader);

       this.bufferedReader = bufferedReader;

    }

    public String readLine() throws IOException {

       String line = bufferedReader.readLine();

       if(line==null){

           return null;

       }

       line = "\""+line+"\"";

       return line;

    }

}

 

public class Demo2 {

 

    public static void main(String[] args) throws IOException {

       File file = new File("F:\\Demo2.java");

       //建立数据的输入通道

       FileReader fileReader = new FileReader(file);

       //建立缓冲输入字符流

       BufferedReader bufferedReader = new BufferedReader(fileReader);

       //建立带行号的缓冲输入字符流

       BufferedLineNum2 bufferedLineNum2 = new BufferedLineNum2(bufferedReader);

      

       BufferedSemi2 bufferedSemi2new BufferedSemi2(bufferedLineNum2);

 

       BufferedQuto2 bufferedQuto = new BufferedQuto2(bufferedSemi2);

       String line = null;

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

           System.out.println(line);

       }

    }

}

 

其他流

SequenceInputStream(序列流)

序列流,对多个流进行合并。

SequenceInputStream表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

 

如果是两个文件合并成一个文件可以使用格式:

SequenceInputStream(fileInputStream1, fileInputStream2 );

 

对于合并三个或者三个以上的文件,需要先把三个被合并流对象保存到集合,然后转换为

Enumeration对象,才能调用SequenceInputStream(Enumeration<?extendsInputStream> e)

 

合并三个文件的两种方法

public static void merge4() throws IOException{

       //找到目标文件

       File file1 = new File("F:\\a.txt");

       File file2 = new File("F:\\b.txt");

       File file3 = new File("F:\\c.txt");

      

       File file4 = new File("F:\\d.txt");

      

       //建立对应的输入输出流

       FileInputStream fileInputStream1 = new FileInputStream(file1);

       FileInputStream fileInputStream2 = new FileInputStream(file2);

       FileInputStream fileInputStream3 = new FileInputStream(file3);

       FileOutputStream fileOutputStream = new FileOutputStream(file4);

      

       //创建一个ArrayList对象

       ArrayList<FileInputStream> list = new ArrayList<FileInputStream>();

       list.add(fileInputStream1);

       list.add(fileInputStream2);

       list.add(fileInputStream3);

      

       final Iterator<FileInputStream> it = list.iterator();//匿名内部类要访问局部变量的时候,必须使用final修饰,因为生命周期的不一致,然后拷贝了一份作为副本

      

       //创建一个序列流对象

       SequenceInputStream sequenceInputStream = new SequenceInputStream(new Enumeration<FileInputStream>() {

           @Override

           public boolean hasMoreElements() {

              return it.hasNext();

           }

           @Override

           public FileInputStream nextElement() {

              return it.next();

           }         

       });

      

       //读取文件

       byte[] buf = new byte[1024];

       int length = 0 ;

       while((lengthsequenceInputStream.read(buf))!=-1){

           fileOutputStream.write(buf,0,length);

       }

       //关闭资源

       fileOutputStream.close();

       sequenceInputStream.close();

    }

   

   

    //合并三个文件

    public static void merge3() throws IOException{

       //找到目标文件

       File file1 = new File("F:\\a.txt");

       File file2 = new File("F:\\b.txt");

       File file3 = new File("F:\\c.txt");

      

       File file4 = new File("F:\\d.txt");

      

       //建立对应的输入输出流

       FileInputStream fileInputStream1 = new FileInputStream(file1);

       FileInputStream fileInputStream2 = new FileInputStream(file2);

       FileInputStream fileInputStream3 = new FileInputStream(file3);

      

       FileOutputStream fileOutputStream = new FileOutputStream(file4);

       //创建一个Vector的对象

       Vector<FileInputStream> vector = new Vector<FileInputStream>();

       vector.add(fileInputStream1);

       vector.add(fileInputStream2);

       vector.add(fileInputStream3);

       Enumeration<FileInputStream> it = vector.elements();

       //创建一个序列流

       SequenceInputStream sequenceInputStream = new SequenceInputStream(it);

      

       //读取文件

       byte[] buf = new byte[1024];

       int length = 0 ;

       while((lengthsequenceInputStream.read(buf))!=-1){

           fileOutputStream.write(buf,0,length);

       }

       //关闭资源

       fileOutputStream.close();

       sequenceInputStream.close();

    }

 

对象的输入输出流

 

对象的输出流:对象的输出流主要是用于输出一个对象的信息到文件上。

    ObjectOutputStream

对象的输入流:对象的输入流主要是用于读取文件中的对象数据。

    ObjectInputStream

 

 

对象输入输出流要注意的事项:

1. 使用ObjectOutputStream 写对象的时候要注意,写出的对象所属的类必须要实现Serializable 接口才能写出。

2. Serializable接口是没有任何的方法的,这种接口我们称作为标识接口。

3. 对象被反序列化的时候创建的对象不会调用到构造方法的。

4. 一个对象在序列化的时候,jvm除了记录这个对象的信息以外,还记录了当前这个对象所属的类的class文件的id号(serialVersionUID)。

那么在反序列化的时候,jvm会算出本地的class文件 的id号,如果算出的id号文件中记录的class文件的id号不一致,那么反序列化失败。因为jvm认为这两个class文件不是同一个。

5. 如果是知道序列化与反序列化的时候可能这个类的成员会发生变化,那么你可以指定一个serialVersionUID给这个class文件,一旦你指定了一个serialVersionUID,

那么jvm就不会再计算你这个类的serialVersionUID了。 这样子就永久性保证这个类的class文件 id一致

5. 如果一个对象的某个属性不想被序列化出去,那么可以使用关键字transient修饰。

6. 如果一个类维护了另外一个类的对象的时候,那么另外一个类也必须要实现Serializable接口。

 

Properties

可以和流相关联的集合对象Properties.

Map

|--Hashtable

|--Properties

Properties:该集合不需要泛型,因为该集合中的键值对都是String类型。

1,存入键值对:setProperty(key,value);

2,获取指定键对应的值:value getProperty(key);

3,获取集合中所有键元素:

Enumeration  propertyNames();

在jdk1.6版本给该类提供一个新的方法。

Set<String> stringPropertyNames();

4,列出该集合中的所有键值对,可以通过参数打印流指定列出到的目的地。

list(PrintStream);

list(PrintWriter);

例:list(System.out):将集合中的键值对打印到控制台。

list(new PrintStream("prop.txt")):将集合中的键值对存储到prop.txt文件中。

5,可以将流中的规则数据加载进行集合,并称为键值对。

load(InputStream):

jdk1.6版本。提供了新的方法。

load(Reader):

注意:流中的数据要是"键=值" 的规则数据。

6,可以将集合中的数据进行指定目的的存储。

store(OutputStram,String comment)方法。

jdk1.6版本。提供了新的方法。

store(Writer ,String comment):

使用该方法存储时,会带着当时存储的时间。

注意:

Properties只加载key=value这样的键值对,与文件名无关,注释使用#

 

Properties类与配置文件

Map

    |--Hashtable

       |--Properties

注意:是一个Map集合,该集合中的键值对都是字符串。该集合通常用于对键值对形式的配置文件进行操作.

配置文件:将软件中可变的部分数据可以定义到一个文件中,方便以后更改,该文件称之为配置文件。

优势: 提高代码的维护性。

Properties:  该类是一个Map的子类,提供了可以快速操作配置文件的方法

load()  :    将文件设备数据装载为Map集合数据

get(key):    获取Map中的数据

getProperty()获取Map中的数据特有方法

 

打印流

打印的特点:

1.打印流可以打印任何类型的数据,打印任何类型的数据之前,都会把数据转换成字符串再打印。

2 printStream创建对象的时候可以直接传入一个对象,而不用存入一个输出流。

 

注意:system.setOut(printStream)可以修改System.out.println()的输出方式(默认的标准流是向控制台输出。,

 

在项目中的应用:一般用来收集程序的异常。Try()Catch块收集到的用printStackTrac()方法默认向控制台输出,可以printStackTrac(printStream )这样做,把异常输出到文件。

 

编码和解码:

编码:从字符转化为码值。

解码:从码值转化为字符。

 

编码与解码要注意的事项:

 

1 一般我们使用什么码表编码就使用什么码表去解码。否则容易出现乱码。

码表有两个部分码值和对应的字符

 

Unicode 是一个码表规范,而不是一张码表。一般平台上的Unicode码表是UTF-16码表

中国汉字常用码表是GBK,一个汉字使用两个字节表示,一个英文用一个字节表示

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

8859-1码表 拉丁码表,用一个字节的8为表示。它一ascii为基础,在空置的0xA0-0xff的范围内加入192个字母及符号。

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

UTF-16 现在Unicode默认使用码表,融合了多种文字,所有文字都用两个字节来表示。

              使用UTF-16输出的内容首位置会有-2-1的标志。

注意:1.英文在所有的码表中对应的码值都是一致的。

     2.在String新建对象的时候可以根据需要选择码表

转换流

把输入字节流转换成输入字符流:  

InputStreamReader是字节流通向字符流的桥梁

 

把输出字节流转换成输出字符流

OutputStreamWriter

 

转换流的作用:

    1. 把字节流转换成字符流去使用。

    2. 如果你需要指定码表进行读取文件的 数据,这时候也需要使用转换流。

   

    FileReader  gbk 

    FileWriter

 

public class Demo8 {

 

    public static void main(String[] args) throws Exception {

//     testInput();

//     testOutPut();

//     writeFile();

       readFile();

    }

    public static void  readFile() throws Exception{

       //找到目标文件

       File file = new File("F:\\c.txt");

       //建立数据的输入通道

       FileInputStream fileInputStream = new FileInputStream(file);

       //建立输入字节流的转换流

       InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");

      

       char[] buf = new char[1024];

       int length = 0 ;

       length = inputStreamReader.read(buf);

       System.out.println("内容:"+ new String(buf,0,length));

    }

   

    //使用输出字符流的转换流指定码表写出数据

    public static void writeFile() throws IOException{

       //找到目标文件

       File file = new File("F:\\c.txt");

       //建立数据的输出通道

       FileOutputStream fileOutputStream = new FileOutputStream(file);

       //创建一个转换流对象

       OutputStreamWriter streamWriter = new OutputStreamWriter(fileOutputStream,"utf-8");  //指定码表把内容写出。。

       streamWriter.write("快下课了");

      

       //关闭资源

       streamWriter.close();

    }

    public static void testOutPut() throws IOException{

       //找到目标文件

       File file = new File("F:\\a.txt");

       //输出流

       FileOutputStream fileOutputStream = new FileOutputStream(file);

       //把输出字节流转换成字符流

       OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);

       //写出数据

       outputStreamWriter.write("大家好!!");

      

       outputStreamWriter.close();

    }

   

    //输入字节流转换输入字符流

    public static void  testInput() throws IOException{

       InputStream in = System.in//获取到了标准的输入流  

       //需要把输入字节流转换输入字符流

       InputStreamReader inputStreamReader = new InputStreamReader(in);

      

       BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

      

       String line = null;

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

           System.out.println("读到的内容:"+ line);

       }

    }

}

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值