当前位置: 移动技术网 > IT编程>开发语言>Java > JavaIO流总结

JavaIO流总结

2019年10月19日  | 移动技术网IT编程  | 我要评论

天龙八部漫画,nakamichi摄像机,塔斯肯自曝显赫家世

1. file类的使用

  • java.io.file类:文件和文件目录路径的抽象表示形式,与平台无关;
  • file能新建、删除、重命名文件和目录,但file不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流;
  • 想要在java程序中表示一个真实存在的文件或目录,那么必须有一个file对象,但是java程序中的一个file对象,可能没有一个真实存在的文件或目录;
  • file对象可以作为参数传递给流的构造器。

1.1 file类的构造器

  • public file(string pathname)
    以pathname为路径创建file对象,可以是 绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
  • public file(string parent,string child)
    以parent为父路径,child为子路径创建file对象;
  • public file(file parent,string child)
    根据一个父file对象和子文件路径创建file对象 。

1.2 file类的常用方法

  • file类的获取功能

    • public string getabsolutepath():获取绝对路径
    • public string getpath() :获取路径
    • public string getname() :获取名称
    • public string getparent():获取上层文件目录路径。若无,返回null
    • public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
    • public long lastmodified() :获取最后一次的修改时间,毫秒值
    • public string[] list() :获取指定目录下的所有文件或者文件目录的名称数组
    • public file[] listfiles() :获取指定目录下的所有文件或者文件目录的file数组
  • file类的重命名功能

    • public boolean renameto(file dest):把文件重命名为指定的文件路径;

      比如:file1.renameto(file2)为例:
      要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。

  • file 类的判断功能

    • public boolean isdirectory():判断是否是文件目录
    • public boolean isfile() :判断是否是文件
    • public boolean exists() :判断是否存在
    • public boolean canread() :判断是否可读
    • public boolean canwrite() :判断是否可写
    • public boolean ishidden() :判断是否隐藏
  • file类的创建功能

    • public boolean createnewfile() :创建文件。若文件存在,则不创建,返回false

    • public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。

    • public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建

      注意事项:如果你创建文件或者 文件 目录没有 写 盘符路径 , 那么 , 默认在项目
      路径下 。

  • file 类的删除功能

    • public boolean delete():删除文件或者文件夹
      删除注意事项:
      java中的删除不走回收站。
      要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。

1.3 应用举例:文件过滤

判断指定目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称

import org.junit.test;
import java.io.file;
import java.io.filenamefilter;
/**
 * 判断指定目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称
 */
public class findjpgfiletest {
    @test
    public void test1(){
        file srcfile = new file("d:\\code");
        
        string[] filenames = srcfile.list();
        for(string filename : filenames){
            if(filename.endswith(".jpg")){
                system.out.println(filename);
            }
        }
    }
    @test
    public void test2(){
        file srcfile = new file("d:\\code");
        
        file[] listfiles = srcfile.listfiles();
        for(file file : listfiles){
            if(file.getname().endswith(".jpg")){
                system.out.println(file.getabsolutepath());
            }
        }
    }
    /*
     * file类提供了两个文件过滤器方法
     * public string[] list(filenamefilter filter)
     * public file[] listfiles(filefilter filter)
     */
    @test
    public void test3(){
        file srcfile = new file("d:\\code");
        
        file[] subfiles = srcfile.listfiles(new filenamefilter() {
            
            @override
            public boolean accept(file dir, string name) {
                return name.endswith(".jpg");
            }
        });
        
        for(file file : subfiles){
            system.out.println(file.getabsolutepath());
        }
    }
}

1.4 应用举例:遍历指定目录

import java.io.file;
/**
 * 遍历指定目录所有文件名称,包括子文件目录中的文件。
    拓展1:并计算指定目录占用空间的大小
    拓展2:删除指定文件目录及其下的所有文件
 */
public class listfilestest {

    public static void main(string[] args) {
        // 递归:文件目录
        /** 打印出指定目录所有文件名称,包括子文件目录中的文件 */

        // 1.创建目录对象
        file dir = new file("e:\\teach\\01_javase\\java编程语言\\3_软件");

        // 2.打印目录的子文件
        printsubfile(dir);
    }

    public static void printsubfile(file dir) {
        // 打印目录的子文件
        file[] subfiles = dir.listfiles();

        for (file f : subfiles) {
            if (f.isdirectory()) {// 文件目录
                printsubfile(f);
            } else {// 文件
                system.out.println(f.getabsolutepath());
            }
        }
    }

    // 方式二:循环实现
    // 列出file目录的下级内容,仅列出一级的话
    // 使用file类的string[] list()比较简单
    public void listsubfiles(file file) {
        if (file.isdirectory()) {
            string[] all = file.list();
            for (string s : all) {
                system.out.println(s);
            }
        } else {
            system.out.println(file + "是文件!");
        }
    }

    // 列出file目录的下级,如果它的下级还是目录,接着列出下级的下级,依次类推
    // 建议使用file类的file[] listfiles()
    public void listallsubfiles(file file) {
        if (file.isfile()) {
            system.out.println(file);
        } else {
            file[] all = file.listfiles();
            // 如果all[i]是文件,直接打印
            // 如果all[i]是目录,接着再获取它的下一级
            for (file f : all) {
                listallsubfiles(f);// 递归调用:自己调用自己就叫递归
            }
        }
    }

    // 拓展1:求指定目录所在空间的大小
    // 求任意一个目录的总大小
    public long getdirectorysize(file file) {
        // file是文件,那么直接返回file.length()
        // file是目录,把它的下一级的所有大小加起来就是它的总大小
        long size = 0;
        if (file.isfile()) {
            size += file.length();
        } else {
            file[] all = file.listfiles();// 获取file的下一级
            // 累加all[i]的大小
            for (file f : all) {
                size += getdirectorysize(f);// f的大小;
            }
        }
        return size;
    }

    // 拓展2:删除指定的目录
    public void deletedirectory(file file) {
        // 如果file是文件,直接delete
        // 如果file是目录,先把它的下一级干掉,然后删除自己
        if (file.isdirectory()) {
            file[] all = file.listfiles();
            // 循环删除的是file的下一级
            for (file f : all) {// f代表file的每一个下级
                deletedirectory(f);
            }
        }
        // 删除自己
        file.delete();
    }
}

2. io流的原理及分类

2.1 java io原理

  • i/o是input/output的缩写,i/o技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等;
  • java程序中,对于数据的输入/输出操以“流(stream)”的方式进行;
  • java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输出如或输出数据。

2.2 流的分类

  • 按操作数据单元不同分为:字节流(8bit),字符流(16bit);

  • 按数据流的流向不同分为:输入流、输出流;

  • 按流的角色的不同分为:节点流,处理流;

  • java的io流共涉及40多个类,实际上非常规则,都是从如下4个基类派生的。由这四个类派生出来的子类都是以其父类名作为后缀;

    (抽象基类) 字节流 字符流
    输入流 inputstream reader
    输出流 outputstream writer

流的分类

io流体系

2.3 节点流和处理流

  • 节点流:直接从数据源或者目的地读写数据;
  • 处理流:不直接连接到数据源或者目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

3. 节点流(或文件流)filereader和filewriter

package com.atguigu.java;

import org.junit.test;

import java.io.file;
import java.io.filereader;
import java.io.ioexception;

public class filereaderwritertest {
    public static void main(string[] args) {
        file file = new file("hello.txt");// 相较于当前功能
    }

    /*
    将day09下的hello.txt文件内容读入程序中,并输出到控制台
    说明点:
    1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
    2. 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
    3. 读入的文件一定要存在,否则就会报filenotfoundexception。
    */
    @test
    public void testfilereader() {
        filereader fr = null;
        try {
            // 1. 实例化file类对象,指明要操作的文件
            file file = new file("hello.txt"); // 相较于当前module
            // 2. 提供具体的流
            fr = new filereader(file);

            // 3. 数据的读入
            //read():返回读入的一个字符。如果达到文件末尾,返回-1
            //方式一:
//        int data = fr.read();
//        while(data != -1){
//            system.out.println((char)data);
//            data = fr.read();
//        }

            // 方式二:语法上针对方式一的修改
            int data;
            while((data = fr.read()) != -1){
                system.out.println((char)data);
            }
        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            try {
                // 4. 关闭流
                if(fr != null){
                    fr.close();
                }
            } catch (ioexception e) {
                e.printstacktrace();
            }

        }
    }

    //对read()操作升级:使用read的重载方法
    @test
    public void testfilereader1() {
        filereader fr = null;
        try {
            // 1. file类的实例化
            file file = new file("hello.txt");
            // 2. filereader流的实例化
            fr = new filereader(file);

            // 3. 读入的操作
            //read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
            char[] cbuf = new char[5];
            int len;
            while((len = fr.read(cbuf)) != -1){
                // 方式一:
                // 错误的写法
//                for(int i = 0; i < cbuf.length; i++){
//                    system.out.print(cbuf[i]);
//                }
                // 正确的写法:
//                for(int i = 0; i < len; i++){
//                    system.out.print(cbuf[i]);
//                }
                // 方式二:
                // 错误的写法:对应方式一的错误写法
//                string str = new string(cbuf);
//                system.out.print(str);
                // 正确的写法二:
                string str= new string(cbuf, 0, len);
                system.out.print(str);
            }
        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            if(fr != null){
                // 4. 资源的关闭
                try {
                    fr.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        }
    }
}
/*
    从内存中写出数据到硬盘的文件里。

    说明:
    1. 输出操作,对应的file可以不存在的。并不会报异常
    2.
         file对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
         file对应的硬盘中的文件如果存在:
           如果流使用的构造器是:filewriter(file,false) / filewriter(file):对原有文件的覆盖
           如果流使用的构造器是:filewriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容

     */
    @test
    public void testfilewriter() {
        filewriter fw = null;
        try {
            //1.提供file类的对象,指明写出到的文件
            file file = new file("hello1.txt");

            //2.提供filewriter的对象,用于数据的写出
            fw = new filewriter(file,false);

            //3.写出的操作
            fw.write("i have a dream!\n");
            fw.write("you need to have a dream!");
        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            //4.流资源的关闭
            if(fw != null){
                try {
                    fw.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        }
    }
  • 读写
@test
public void testfilereaderfilewriter() {
    filereader fr = null;
    filewriter fw = null;
    try {
        //1.创建file类的对象,指明读入和写出的文件
        file srcfile = new file("hello.txt");
        file destfile = new file("hello2.txt");

        //不能使用字符流来处理图片等字节数据
        //            file srcfile = new file("爱情与友情.jpg");
        //            file destfile = new file("爱情与友情1.jpg");

        //2.创建输入流和输出流的对象
        fr = new filereader(srcfile);
        fw = new filewriter(destfile);


        //3.数据的读入和写出操作
        char[] cbuf = new char[5];
        int len;//记录每次读入到cbuf数组中的字符的个数
        while((len = fr.read(cbuf)) != -1){
            //每次写出len个字符
            fw.write(cbuf,0,len);
        }
    } catch (ioexception e) {
        e.printstacktrace();
    } finally {
        //4.关闭流资源
        //方式一:
        //            try {
        //                if(fw != null)
        //                    fw.close();
        //            } catch (ioexception e) {
        //                e.printstacktrace();
        //            }finally{
        //                try {
        //                    if(fr != null)
        //                        fr.close();
        //                } catch (ioexception e) {
        //                    e.printstacktrace();
        //                }
        //            }
        //方式二:
        try {
            if(fw != null)
                fw.close();
        } catch (ioexception e) {
            e.printstacktrace();
        }

        try {
            if(fr != null)
                fr.close();
        } catch (ioexception e) {
            e.printstacktrace();
        }
    }
}

4. 节点流(或文件流)fileinputstream和fileoutputstream

  • 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
  • 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理
//使用字节流fileinputstream处理文本文件,可能出现乱码。
@test
public void testfileinputstream() {
    fileinputstream fis = null;
    try {
        //1. 造文件
        file file = new file("hello.txt");

        //2.造流
        fis = new fileinputstream(file);

        //3.读数据
        byte[] buffer = new byte[5];
        int len;//记录每次读取的字节的个数
        while((len = fis.read(buffer)) != -1){
            string str = new string(buffer,0,len);
            system.out.print(str);
        }
    } catch (ioexception e) {
        e.printstacktrace();
    } finally {
        if(fis != null){
            //4.关闭资源
            try {
                fis.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
    }
}

/*
    实现对图片的复制操作
     */
@test
public void testfileinputoutputstream()  {
    fileinputstream fis = null;
    fileoutputstream fos = null;
    try {
        file srcfile = new file("爱情与友情.jpg");
        file destfile = new file("爱情与友情2.jpg");
        
     
        fis = new fileinputstream(srcfile);
        fos = new fileoutputstream(destfile);

        //复制的过程
        byte[] buffer = new byte[5];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

    } catch (ioexception e) {
        e.printstacktrace();
    } finally {
        if(fos != null){
            try {
                fos.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
        if(fis != null){
            try {
                fis.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
    }
}

5. 处理流之缓冲流

  • 缓冲流:
    • bufferedinputstream
    • bufferedoutputstream
    • bufferedreader
    • bufferedwriter
  • 作用;
    • 提高流的读取、写入的速度
    • 提高读写速度的原因:内部提供了一个缓存区;
  • 处理流,就是“套接”在已有的流的基础上。

5. 1 字节型缓冲流实现非文本文件的复制操作

/*
实现非文本文件的复制
*/
@test
public void bufferedstreamtest() throws filenotfoundexception {
    bufferedinputstream bis = null;
    bufferedoutputstream bos = null;

    try {
        //1.造文件
        file srcfile = new file("爱情与友情.jpg");
        file destfile = new file("爱情与友情3.jpg");
        //2.造流
        //2.1 造节点流
        fileinputstream fis = new fileinputstream((srcfile));
        fileoutputstream fos = new fileoutputstream(destfile);
        //2.2 造缓冲流
        bis = new bufferedinputstream(fis);
        bos = new bufferedoutputstream(fos);

        //3.复制的细节:读取、写入
        byte[] buffer = new byte[10];
        int len;
        while((len = bis.read(buffer)) != -1){
            bos.write(buffer,0,len);

            //                bos.flush();//刷新缓冲区

        }
    } catch (ioexception e) {
        e.printstacktrace();
    } finally {
        //4.资源关闭
        //要求:先关闭外层的流,再关闭内层的流
        if(bos != null){
            try {
                bos.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }

        }
        if(bis != null){
            try {
                bis.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }

        }
        //说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
        //        fos.close();
        //        fis.close();
    }

5. 2 字符型缓冲流实现文本文件的复制操作

使用bufferedreader和bufferedwriter实现文本文件的复制

     */
    @test
    public void testbufferedreaderbufferedwriter(){
        bufferedreader br = null;
        bufferedwriter bw = null;
        try {
            //创建文件和相应的流
            br = new bufferedreader(new filereader(new file("dbcp.txt")));
            bw = new bufferedwriter(new filewriter(new file("dbcp1.txt")));

            //读写操作
            //方式一:使用char[]数组
//            char[] cbuf = new char[1024];
//            int len;
//            while((len = br.read(cbuf)) != -1){
//                bw.write(cbuf,0,len);
//    //            bw.flush();
//            }

            //方式二:使用string
            string data;
            while((data = br.readline()) != null){
                //方法一:
//                bw.write(data + "\n");//data中不包含换行符
                //方法二:
                bw.write(data);//data中不包含换行符
                bw.newline();//提供换行的操作

            }


        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            //关闭资源
            if(bw != null){

                try {
                    bw.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
            if(br != null){
                try {
                    br.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }

            }
        }

    }

6. 处理流之转换流

  • 转换流提供了在字节流和字符流之间的转换;
  • java api提供了两个转换流
    • inputstreamreder:将inputstream转换为reader;
    • outputstreamwriter:将writer转换为outputstream;
  • 字节流中数据都是字符时,转换成字符流操作更高效;
  • 很多时候我们使用转换流来处理文件乱码问题,实现编码和解码的功能;

转换流

  • 转换流实现文件的读入和写出
import org.junit.test;

import java.io.*;

/**
 * 处理流之二:转换流的使用
 * 1.转换流:属于字符流
 *   inputstreamreader:将一个字节的输入流转换为字符的输入流
 *   outputstreamwriter:将一个字符的输出流转换为字节的输出流
 *
 * 2.作用:提供字节流与字符流之间的转换
 *
 * 3. 解码:字节、字节数组  --->字符数组、字符串
 *    编码:字符数组、字符串 ---> 字节、字节数组
 *
 *
 * 4.字符集
 *ascii:美国标准信息交换码。
    用一个字节的7位可以表示。
 iso8859-1:拉丁码表。欧洲码表
    用一个字节的8位表示。
 gb2312:中国的中文编码表。最多两个字节编码所有字符
 gbk:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
 unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
 utf-8:变长的编码方式,可用1-4个字节来表示一个字符。

 */
public class inputstreamreadertest {

    /*
    此时处理异常的话,仍然应该使用try-catch-finally
    inputstreamreader的使用,实现字节的输入流到字符的输入流的转换
     */
    @test
    public void test1() throws ioexception {

        fileinputstream fis = new fileinputstream("dbcp.txt");
//        inputstreamreader isr = new inputstreamreader(fis);//使用系统默认的字符集
        //参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
        inputstreamreader isr = new inputstreamreader(fis,"utf-8");//使用系统默认的字符集

        char[] cbuf = new char[20];
        int len;
        while((len = isr.read(cbuf)) != -1){
            string str = new string(cbuf,0,len);
            system.out.print(str);
        }

        isr.close();

    }

    /*
    此时处理异常的话,仍然应该使用try-catch-finally

    综合使用inputstreamreader和outputstreamwriter
     */
    @test
    public void test2() throws exception {
        //1.造文件、造流
        file file1 = new file("dbcp.txt");
        file file2 = new file("dbcp_gbk.txt");

        fileinputstream fis = new fileinputstream(file1);
        fileoutputstream fos = new fileoutputstream(file2);

        inputstreamreader isr = new inputstreamreader(fis,"utf-8");
        outputstreamwriter osw = new outputstreamwriter(fos,"gbk");

        //2.读写过程
        char[] cbuf = new char[20];
        int len;
        while((len = isr.read(cbuf)) != -1){
            osw.write(cbuf,0,len);
        }

        //3.关闭资源
        isr.close();
        osw.close();
    }
}

7. 标准流、打印流、数据流

7.1 标准输入流和标准输出流

  • system.in和system.out分别代表了系统标准的输入和输出设备
  • 默认输入设备是:键盘,输出设备是:显示器
  • system.in的类型是inputstream
  • system.out的类型是printstream,其是outputstream的子类,filteroutputstream 的子类
  • 重定向:通过system类的setin,setout方法对默认设备进行改变。
    • public static void setin(inputstream in)
    • public static void setout(printstream out)
/*
    1.标准的输入、输出流
    1.1
    system.in:标准的输入流,默认从键盘输入
    system.out:标准的输出流,默认从控制台输出
    1.2
    system类的setin(inputstream is) / setout(printstream ps)方式重新指定输入和输出的流。

    1.3练习:
    从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,
    直至当输入“e”或者“exit”时,退出程序。

    方法一:使用scanner实现,调用next()返回一个字符串
    方法二:使用system.in实现。system.in  --->  转换流 ---> bufferedreader的readline()

     */
    public static void main(string[] args) {
        bufferedreader br = null;
        try {
            inputstreamreader isr = new inputstreamreader(system.in);
            br = new bufferedreader(isr);

            while (true) {
                system.out.println("请输入字符串:");
                string data = br.readline();
                if ("e".equalsignorecase(data) || "exit".equalsignorecase(data)) {
                    system.out.println("程序结束");
                    break;
                }

                string uppercase = data.touppercase();
                system.out.println(uppercase);

            }
        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }

            }
        }
    }

7.2 打印流

  • 实现将 基本数据类型的数据格式转化为 字符串输出
  • 打印流:printstream和printwriter
    • 提供了一系列重载的print()和println()方法,用于多种数据类型的输出
    • printstream和printwriter的输出不会抛出ioexception异常
    • printstream和printwriter有自动flush功能
    • printstream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 printwriter 类。
    • system.out返回的是printstream的实例
/*
    2. 打印流:printstream 和printwriter

    2.1 提供了一系列重载的print() 和 println()
    2.2 练习:



     */

    @test
    public void test2() {
        printstream ps = null;
        try {
            fileoutputstream fos = new fileoutputstream(new file("d:\\io\\text.txt"));
            // 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
            ps = new printstream(fos, true);
            if (ps != null) {// 把标准输出流(控制台输出)改成文件
                system.setout(ps);
            }


            for (int i = 0; i <= 255; i++) { // 输出ascii字符
                system.out.print((char) i);
                if (i % 50 == 0) { // 每50个数据一行
                    system.out.println(); // 换行
                }
            }


        } catch (filenotfoundexception e) {
            e.printstacktrace();
        } finally {
            if (ps != null) {
                ps.close();
            }
        }

    }

7.3 数据流

  • 为了方便地操作java语言的基本数据类型和string的数据,可以使用数据流。
  • 数据流有两个类:(用于读取和写出基本数据类型、string类的数据)
    • datainputstream 和 dataoutputstream
    • 在 分别“套接”在 inputstream 和 和 outputstream子类的流 上
  • datainputstream 中的方法
    • boolean readboolean() byte readbyte()
    • char readchar() float readfloat()
    • dou ble readdouble() short readshort()
    • long readlong() int readint()
    • string readutf() void readfully(byte[] b)
  • dataoutputstream 中的方法
    • 将上述的方法的read改为相应的write即可。
    /*
    3. 数据流
    3.1 datainputstream 和 dataoutputstream
    3.2 作用:用于读取或写出基本数据类型的变量或字符串
    练习:将内存中的字符串、基本数据类型的变量写出到文件中。
    注意:处理异常的话,仍然应该使用try-catch-finally.
     */
    @test
    public void test3() throws ioexception {
        dataoutputstream dos = new dataoutputstream(new fileoutputstream("data.txt"));
        dos.writeutf("刘建辰");
        dos.flush();//刷新操作,将内存中的数据写入文件
        dos.writeint(23);
        dos.flush();
        dos.writeboolean(true);
        dos.flush();
        dos.close();
    }
    /*
    将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。

    注意点:读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!

     */
    @test
    public void test4() throws ioexception {
        //1.
        datainputstream dis = new datainputstream(new fileinputstream("data.txt"));
        //2.
        string name = dis.readutf();
        int age = dis.readint();
        boolean ismale = dis.readboolean();

        system.out.println("name = " + name);
        system.out.println("age = " + age);
        system.out.println("ismale = " + ismale);

        //3.
        dis.close();

    }

8. 对象流

8.1 对象流

  • objectinputstream 和ojbectoutputsteam
    • 用于存储和读取 基本数据类型数据或 对象的处理流。它的强大之处就是可以把java中的对象写入到数据源中,也能把对象从数据源中还原回来;
  • 序列化:用objectoutputstream类 保存基本类型数据或对象的机制;
  • 反序列化:用objectinputstream类 读取基本类型数据或对象的机制;
  • objectoutputstream和objectinputstream不能序列化static和transient修饰的成员变量。
import java.io.*;
/**
 * 对象流的使用
 * 1.objectinputstream 和 objectoutputstream
 * 2.作用:用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把java中的对象写入到数据源中,也能把对象从数据源中还原回来。

 */
public class objectinputoutputstreamtest {

    /*
    序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
    使用objectoutputstream实现
     */
    @test
    public void testobjectoutputstream(){
        objectoutputstream oos = null;

        try {
            oos = new objectoutputstream(new fileoutputstream("object.dat"));
            oos.writeobject(new string("我爱北京天安门"));
            oos.flush();//刷新操作
            oos.writeobject(new person("王铭",23));
            oos.flush();
            oos.writeobject(new person("张学良",23,1001,new account(5000)));
            oos.flush();

        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            if(oos != null){
                try {
                    oos.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        }
    }

    /*
    反序列化:将磁盘文件中的对象还原为内存中的一个java对象
    使用objectinputstream来实现
     */
    @test
    public void testobjectinputstream(){
        objectinputstream ois = null;
        try {
            ois = new objectinputstream(new fileinputstream("object.dat"));

            object obj = ois.readobject();
            string str = (string) obj;

            person p = (person) ois.readobject();
            person p1 = (person) ois.readobject();

            system.out.println(str);
            system.out.println(p);
            system.out.println(p1);

        } catch (ioexception e) {
            e.printstacktrace();
        } catch (classnotfoundexception e) {
            e.printstacktrace();
        } finally {
            if(ois != null){
                try {
                    ois.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        }
    }
}

person需要满足如下的要求,方可序列化:

1.需要实现接口:serializable

2.当前类提供一个全局常量:serialversionuid

3.除了当前person类需要实现serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)。

8.2 对象的序列化

  • 对象序列化机制允许把内存中的java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原
    来的java对象;
  • 序列化的好处在于可将任何实现了serializable接口的对象转化为 字节数据,使其在保存和传输时可被还原;
  • 序列化是 rmi(remote method invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 rmi 是 javaee 的基础。因此序列化机制是javaee 平台的基础;
  • 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。否则,会抛出notserializableexception异常
    • serializable
    • externalizable
  • 凡是实现serializable接口的类都有一个表示序列化版本标识符的静态变量:
    • private static final long serialversionuid;
    • serialversionuid用来表明类的不同版本间的兼容性。 简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
    • 如果类没有显示定义这个静态常量,它的值是java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialversionuid 可能发生变化。故建议,显式声明。
  • 简单来说,java的序列化机制是通过在运行时判断类的serialversionuid来验证版本一致性的。在进行反序列化时,jvm会把传来的字节流中的serialversionuid与本地相应实体类的serialversionuid进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(invalidcastex ception)

8.3 面试题

谈谈你对java.io.serializable 接口的理解,我们知道它用于序列化,是空方法接口,还有其它认识吗?

实现了serializable 接口的对象,可将它们转换成一系列字节,并可在以后完全恢复回原来的样子。 这一过程亦可通过网络进行。这意味着序列化机制能自动补偿操作系统间的差异。在 换句话说,可以先在windows 机器上创建一个对象,对其序列化,然后通过网络发给一台unix 机器,然后在那里准确无误地重新“装配”。不必关心数据在不同机器上如何表示,也不必关心字节的顺序或者其他任何细节。
由于大部分作为参数的类如string 、integer 等都实现了java.io.serializable 的接口,也可以利用多态的性质,作为参数使接口更灵活。


9. 随机存取文件流randomaccessfile 类

  • randomaccessfile 声明在java.io包下,但直接继承于java.lang.object类。并且它实现了datainput、dataoutput这两个接口,也就意味着这个类既可以读也可以写。
  • randomaccessfile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来 读、写文件
    • 支持只访问文件的部分内容
    • 可以向已存在的文件后追加内容
  • randomaccessfile 对象包含一个记录指针,用以标示当前读写处的位置。randomaccessfile 类对象可以自由移动记录指针:
    • long getfilepointer():获取文件记录指针的当前位置
    • void seek(long pos):将文件记录指针定位到 pos 位置
  • 构造器
    • public randomaccessfile(file file, string mode)
    • public randomaccessfile(string name, string mode)
  • 创建 randomaccessfile 类实例需要指定一个 mode 参数,该参数指定 randomaccessfile 的访问模式:
    • r: 以只读方式打开
    • rw :打开以便读取和写入
    • rwd: 打开以便读取和 写入;同步文件内容的更新
    • rws: 打开以便读取和 写入; 同步文件内容和元数据 的 更新
  • 如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件,如果读取的文件不存在则会出现异常。 如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。
import org.junit.test;
import java.io.file;
import java.io.ioexception;
import java.io.randomaccessfile;

/**
 * randomaccessfile的使用
 * 1.randomaccessfile直接继承于java.lang.object类,实现了datainput和dataoutput接口
 * 2.randomaccessfile既可以作为一个输入流,又可以作为一个输出流
 *
 * 3.如果randomaccessfile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
 *   如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
 *
 * 4. 可以通过相关的操作,实现randomaccessfile“插入”数据的效果
 */
public class randomaccessfiletest {

    @test
    public void test1() {

        randomaccessfile raf1 = null;
        randomaccessfile raf2 = null;
        try {
            //1.
            raf1 = new randomaccessfile(new file("爱情与友情.jpg"),"r");
            raf2 = new randomaccessfile(new file("爱情与友情1.jpg"),"rw");
            //2.
            byte[] buffer = new byte[1024];
            int len;
            while((len = raf1.read(buffer)) != -1){
                raf2.write(buffer,0,len);
            }
        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            //3.
            if(raf1 != null){
                try {
                    raf1.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }

            }
            if(raf2 != null){
                try {
                    raf2.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        }
    }

    @test
    public void test2() throws ioexception {
        randomaccessfile raf1 = new randomaccessfile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        raf1.write("xyz".getbytes());//

        raf1.close();

    }
    /*
    使用randomaccessfile实现数据的插入效果
     */
    @test
    public void test3() throws ioexception {

        randomaccessfile raf1 = new randomaccessfile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        //保存指针3后面的所有数据到stringbuilder中
        stringbuilder builder = new stringbuilder((int) new file("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1){
            builder.append(new string(buffer,0,len)) ;
        }
        //调回指针,写入“xyz”
        raf1.seek(3);
        raf1.write("xyz".getbytes());

        //将stringbuilder中的数据写入到文件中
        raf1.write(builder.tostring().getbytes());

        raf1.close();
    }
}

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网