Java IO原理

I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读写文件,网络通讯等。

Java程序中,对于数据的输入/输出操作以“流(Stream)”的方式进行。

java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,通过标准的方法输入过输出数据

输入input:读取外部数据(磁盘,光盘等外部存储设备)到程序(内存)中。

输出output:将程序(内存)中的数据输出到磁盘,光盘等存储设备中。

流的分类

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

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

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

    抽象基类  字节流     字符流

    输入流  InputStream   Reader

    输出流  OutputStream   Writer

1、java的IO流共涉及40 多个类,实际上非常规则,收拾从如下4个抽象基类派生的。

2、由这四个类派生出的子类名称都是以其父类名称作为子类名的后缀。

 

 

IO流的常用类体系

 FileReader、FileWriter流案例

package chario;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.CharArrayWriter;
import java.io.File;
public class FileReaderWriterTest {

    public static void main(String[] args) throws IOException {
        
        FileWriterTest();
        FileReaderTest();
    }
    
    /**
     * 文件写入
     */
    public static void FileWriterTest() {
        FileWriter fw=null;
        try {
            //1实例化文件对象
            File file = new File("chat/record.txt");
            //2提供写入流   参数1:文件对象 参数2:是否追加(默认为:false)
            fw = new FileWriter(file, true);
            String str = "I Love You!";
            fw.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //关闭流
                if(fw!=null) fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }    
    }
    
    /**
     * 文件读取
     */
    public static void FileReaderTest() {
        
        FileReader fr = null;
        CharArrayWriter caw = null;
        try {
            //实例化文件对象
            File file = new File("chat/record.txt");
            //提供具体的流
            fr = new FileReader(file);
            //增加缓冲数组
            char[] cbuf = new char[5];
            caw = new CharArrayWriter();
            int len = 0;
            
            //读入数据
            //read():返回读入的一个字符,如果达到文件末尾,返回-1 
            while((len=fr.read(cbuf))!=-1) {
                caw.write(cbuf);
            }
            
            System.out.println(caw.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //关闭流操作
                if(fr!=null) fr.close();
                //数组缓冲流是否有close操作,作用不大。关闭此流后不影响该流继续调用;
                if(caw!=null) caw.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

FileInputStream、FileOutputStream案例

 1 package byteio;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.File;
 5 import java.io.FileInputStream;
 6 import java.io.FileNotFoundException;
 7 import java.io.FileOutputStream;
 8 import java.io.IOException;
 9 public class FileInOutStream {
10 
11     public static void FileOutput() {
12         //2创建文件输出流
13         FileOutputStream fos = null;
14         try {
15             //1创建文件对象
16             File file = new File("p1.jpg");
17             fos = new FileOutputStream(file);
18             String str = "孔融让梨";
19             //3写入文件内容
20             fos.write(str.getBytes());
21         } catch (FileNotFoundException e) {
22             // TODO Auto-generated catch block
23             e.printStackTrace();
24         } catch (IOException e) {
25             // TODO Auto-generated catch block
26             e.printStackTrace();
27         } finally {
28             //4关闭流
29             try {
30                 fos.close();
31             } catch (IOException e) {
32                 // TODO Auto-generated catch block
33                 e.printStackTrace();
34             }
35             
36         }
37         
38     }
39     
40     public static void FileInput() {
41         
42         //2创建文件输入流
43         FileInputStream fis=null;
44         FileOutputStream fos = null;
45         ByteArrayOutputStream baos = null;
46         try {
47             //1创建文件对象
48             File file = new File("img/p1.jpg");
49             File file2 = new File("img/p11.jpg");
50             fis = new FileInputStream(file);
51             fos = new FileOutputStream(file2);
52             baos = new ByteArrayOutputStream();
53             //3创建缓冲数组
54             byte[] buffer = new byte[20];
55             //4定义传入数组中数据量
56             int len=0;
57             while((len=fis.read(buffer))!=-1) {
58                 //String(byte[], offer, length)  
59                 //此方法是将字节数组从offer开始到length结束的数据转换成string类型 
60 //                String str = new String(buffer, 0, len);
61 //                System.out.println(str);
62                 fos.write(buffer);
63             }
64             
65         } catch (Exception e) {
66             // TODO Auto-generated catch block
67             e.printStackTrace();
68         } finally {
69             //关闭流
70             try {
71                 if(fis!=null) fis.close();
72             }catch(IOException e) {
73                 e.printStackTrace();
74             }
75         }
76     }
77     
78     public static void main(String[] args) {
79         
80 //        FileOutput();
81         FileInput();
82         
83     }
84 }

 

缓冲流案例

package stream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 处理流之一:缓冲流
 * 1、缓冲流:
 * BufferedInputStream
 * BufferedOutputStream
 * BufferedRreader
 * BufferedWriter
 * 
 * 2、提高流的读取速度 
 * 提高读写速度的原因:内部提供了一个缓冲区
******************************************************用System.currentTimeMills测试时间时,用于测试的
******************************************************文本文件建议在10k以上,否则可能见不到Buffered的提速效果 *
@author Gary * @time 2019年8月6日 */ public class Buffer { /** * 缓冲流实现复制文件 * @throws IOException */ public static void CopyBuffer() { //造流 //首先创建节点流 FileInputStream fis=null; FileOutputStream fos=null; //装备处理流 BufferedInputStream bis=null; BufferedOutputStream bos=null; try { //创建文件对象 File file = new File("img/p2.jpg"); File filenew = new File("img/p22.jpg"); fis = new FileInputStream(file); fos = new FileOutputStream(filenew); bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); //复制数据 //创建byte[]数组 byte[] buffer = new byte[20]; int len = 0; while ((len = bis.read(buffer)) != -1) { //缓冲流接受数据 bos.write(buffer, 0, len); } } catch (Exception e) { // TODO: handle exception } finally { //关闭流 //要求1:先关外再关内,需要先将处理流关闭后再将节点流关闭 try { if(bis!=null)bis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(bos!=null)bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // //提示:将外层流关闭后虚拟机会将内层流自动关闭 // fis.close(); // fos.close(); } } /** * 不适用缓冲流复制 */ public static void CopyNoBuffer() { //构造流 FileInputStream fis=null; FileOutputStream fos=null; try { //创建文件对象 File file1 = new File("img/p2.jpg"); File file2 = new File("img/p222.jpg"); fis = new FileInputStream(file1); fos = new FileOutputStream(file2); //复制数据 //构造byte数组 byte[] buffer = new byte[20]; int len=0; while((len = fis.read(buffer))!=-1) { fos.write(buffer, 0, len); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //关闭流 try { if(fis!=null) fis.close(); if(fos!=null) fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { //获得从1970年1月1日到现在的毫秒数 //当前时间与协调世界时 1970 年 1 月 1 日午夜之间的时间差(以毫秒为单位测量)。 long start1 = System.currentTimeMillis(); CopyBuffer(); long end1 = System.currentTimeMillis(); long start2 = System.currentTimeMillis(); CopyNoBuffer(); long end2 = System.currentTimeMillis(); System.out.println("CopyBuffer RunningTime: "+(end1-start1)); System.out.println("CopyNoBuffer RunningTime: "+(end2-start1)); } }
package stream;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharBuffered {

    /**
     * 文本文件复制(缓冲流)
     * @throws IOException 
     */
    public static void CharBufferCopy() {//RunningTime:2


        
        //创建文件和相应的流
        BufferedReader br=null;
        BufferedWriter bw=null;
        try {
            br = new BufferedReader(new FileReader(new File("chat/rmy.txt")));
            bw = new BufferedWriter(new FileWriter(new File("chat/rmy1.txt")));
            
            //复制文件
            //创建数组
//            char[] cbuf = new char[2048];
//            int len=0;
//            
//            while((len=br.read(cbuf))!=-1) {
//                bw.write(cbuf, 0, len);
//                bw.flush();
//            }
            
            //方式二:使用String
            String str;
            while((str = br.readLine())!=null) {
                bw.write(str);
                bw.newLine();
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            
            try {
                //关闭流
                if(br!=null) br.close();
                if(bw!=null) bw.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 无缓冲流进行文本文件复制
     * @throws IOException 
     */
    public static void CharNoBufferCopy() { //RunningTime:4
        
        //构造相应的文件对象和流
        FileReader fr=null;
        FileWriter fw=null;
        try {
            fr = new FileReader(new File("chat/rmy.txt"));
            fw = new FileWriter(new File("chat/rmy1.txt"));
            
            //复制文件
            char[] cbuf = new char[2048];
            int len=0;
            
            //方式一:
            while((len=fr.read(cbuf))!=-1) {
                fw.write(cbuf, 0, len);
                fw.flush();
            }
            
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            
            try {
                //关闭流
                if(fw!=null) fw.close();
                if(fr!=null) fr.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
        
    }
    
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        CharBufferCopy();
        long end = System.currentTimeMillis();
        
        System.out.println("RunningTime:"+(end-start));
    }
}

 

花絮片段:字符编码

○编码表的由来

  计算机只能识别二进制数据,早期由来是电信号,为了方便应用计算机,让它可以识别各个国家的文字。即将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。

○常见的编码表

ASCII:没过标准信息交换码

  ·用一个字节的7位可以表示。

ISO8859-1:拉丁码表。欧洲表

  ·有一个字节8位可以表示。

GBK2312:中国的中文编码表,最多两个字节编码所有字符。

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

Unicode:国际标准码。融合了目前人类使用的所有字符,为每个字符分配唯一的字符码,所有文字都用两个字节来表示。

UTF-8:边长的编码方式,可以用1-4个字节来表示一个字符。

  Unicode不完美;它存在着三个问题:

    一、英文字母用一个字节表示就足够了;

    二、如何才能区别Unicode和ASCII;计算机怎么知道两个字节表示一个字符还是一个字节表示一个字符;

    三、如果采用和GBK等一样的双字节编码,用最高位是1或0来表示两个字节或一个字节,那么将很多符号将无法表示出来。

    因此Unicode在很长的一段时间内无法推广使用,知道互联网的出现;

  面向传输的众多UTF(UCS Transfer Format)标准出现,顾名思义,UTF-8就是每次8位传输数据,UTF-16就是每次16位传输数据。这是为了传输而设计的编码,并使编码无国界,这样就可以显示世界上所有的文字字符了;

    Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储成什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-8或UTF-16。

 

交换流案例

package stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

/**
 * 处理流二: 转换流
 * 1、转换流:属于字符流
 * InputStreamReader 将一个字节输入流流转换成字符流输入流
 * OutputStreamWriter 将一个字符流输出流转换成字节输出流
 * 
 * 2、作用:提供字节流与字符流之间的转换
 * 
 * 3、 解码:字节、字节数组      ----> 字符数组、字符串
 *          编码:字符数组、字符串  ----> 字节、字节数组
 * 
 * 4、字符集
 * 
 * @author Gary
 * @time 2019年8月6日
 */
public class Conversion {

    public static void main(String[] args) {
        IntReaderTest();
    }
    /**
     * 字节输入转字符输入操作
     * @throws IOException 
     */
    public static void IntReaderTest() {
        
        InputStreamReader isr = null;
        OutputStreamWriter  osr = null;
        try {
            
            isr = new InputStreamReader(new FileInputStream("chat/error.txt"), "UTF-8");
            osr = new OutputStreamWriter(new FileOutputStream("chat/error2.txt"), "gbk");
            
            char[] cbuf = new char[20];
            int len=0;
            while((len=isr.read(cbuf))!=-1) {
//                for(int i=0; i<len; i++) {
//                    System.out.print(cbuf[i]);
//                }
//                System.out.println();
                osr.write(cbuf, 0, len);
            }
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if(isr!=null) isr.close();
                if(osr!=null) osr.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

标准输入输出流案例

package stream;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 其他流的使用
 * 1、标准的输入、输出流
 * 2、打印流
 * 3、数据流
 * @author Gary
 * @time 2019年8月6日
 */
public class OtherTest {

    /**
     * 1标准输入、输出流
     * 1.1
     * System.in 标准输入流,默认从键盘读入
     * System.out 标准输出流, 默认从控制台输出
     * 1.2
     * System类的setIn()/setOut() 方法重新指定输入和输出流
     *     使用Scanner方法    next()方法
     *     使用System.in实现控制台输入  readLine()方法   System.in ----->  BufferedReaderde readLine();
     */
    
    public static void test1() {
        //BufferedReader 处理流需要建立在节点流上 BufferedReader(Reader r);  InputStreamReader(InputStream is)构造方法需要有参数为InputStream
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(System.in));
            
            while(true) {
                System.out.println("请输入字符串:");
                String str = br.readLine();
                if("e".equalsIgnoreCase(str)||"exit".equalsIgnoreCase(str)) {
                    break;
                }
                str = str.toUpperCase();
                System.out.println(str);
                
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if(br!=null) br.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        test1();
    }
}

 

打印流案例

package stream;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

/**
 * 处理流之四: 打印流
 * PrintStream PrintWriter
 * 1、PrintStream和PrintWriter 不会抛IOException异常
 * 2、PrintStream PrintWriter 有自动flush功能
 * 3、PrintStream打印所有字符都是用平台默认的字符编码转换成字节
 * 在需要写入字符面不是写入字节的情况下应该使用PrintWriter
 * 4、System.out返回PrintStream的事例
 * @author Gary
 * @time 2019年8月7日
 */
public class PrintTest {

    public static void main(String[] args) {
        
        //构造打印流
        PrintStream ps=null;
        try {
            FileOutputStream fos = new FileOutputStream("dat/1.dat");
            ps = new PrintStream(fos, true);
            if(ps!=null) {
                System.setOut(ps);
            }
            for(int i=0; i<=50; i++) {
                System.out.print(i+"\t");
                if(i%10==0) {
                    System.out.println();
                }
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            //注意:PrintStream PrintWriter不会抛IOException异常
            if(ps!=null) ps.close();
        }
        
        
    }
}

 

对象流 ObjectInputStream ObjectOutputStream

用于存储和读取基本数据类型或对象的处理流。它的强大之处就是可以吧java中的对象写入到数据源中,也能把对象从数据源中还原回来。

* 处理流之六:对象流
 * 1、对象的序列化与反序列化:
 *         序列化:将java虚拟机中的对象转换成与平台无关的二进制流,从而
 *               允许把这种二进制流持久的保存在磁盘上,或者通过网络将这种
 *              二进制流传输到另一个网络节点。
 *         反序列化:当需要用到这种二进制流是,java虚拟机能够将其恢复成java对象
 *
 * 2、序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,
 *       使其在保存和传输是可被还原。
 * 3、序列化是RMI(Remote Method Invoke-远程方法调用)过程的参数和返回值都必须实现的机制,
 *      而RMI是Java EE 的基础,因此序列化机制是javaEE平台的基础。
 * 4、如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类可序列化,
 *         改类必须实现如下两个接口 之一,否则,会抛NotSerializableException异常
 *         Serializable
 *         Externalizable

* 对象序列化的条件 

* 1、实现Serializable或Externalizable接口
 * 2、对象的类的属性必须是可序列化的
 * 3、需要有seriaVersionUID序列版本号
 *         private static final long serialVersionUID;
 *
 * 说明:
 *     凡是实现Serializable接口的类都有一个序列化版本标识符的静态常量:
 *     private static final long serialVersionUID;
 *         *serialVersionUID用来表明类的不同版本间的兼容性。简而言之,其目的是以序列化对象
 *         进行版本控制,有关个版本反序列化时是否兼容。
 *         *如果类没有显示的定义静态常量,它的值是java运行环境根据类的内部细节自动生成的。
 *            若类的实例变量做了修改,serialVersionUID可能发生变化;发生变化后反序列化
 *          就会产生InvalClassException异常。故建议,显示声明;
 *    
 *    简单来说,Java的序列化机制是通过在运行是判断类的serialVersionUID来验证版本一致性的。
 *    在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID
 *    进行比较,如果相同就认为一致,可以进行反序列化,否则就会出现序列化版本不一致的异常(InvalidCastException)
 *

案例

package stream;

import java.io.Serializable;
/**
 * 狗类
 * 
 * 对象序列化的条件
 * 1、实现Serializable或Externalizable接口
 * 2、对象的类的属性必须是可序列化的
 * 3、需要有seriaVersionUID序列版本号 
 *         private static final long serialVersionUID;
 * 
 * 说明:
 *     凡是实现Serializable接口的类都有一个序列化版本标识符的静态常量:
 *     private static final long serialVersionUID;
 *         *serialVersionUID用来表明类的不同版本间的兼容性。简而言之,其目的是以序列化对象
 *         进行版本控制,有关个版本反序列化时是否兼容。
 *         *如果类没有显示的定义静态常量,它的值是java运行环境根据类的内部细节自动生成的。
 *            若类的实例变量做了修改,serialVersionUID可能发生变化;发生变化后反序列化
 *          就会产生InvalClassException异常。故建议,显示声明;
 *    
 *    简单来说,Java的序列化机制是通过在运行是判断类的serialVersionUID来验证版本一致性的。
 *    在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID
 *    进行比较,如果相同就认为一致,可以进行反序列化,否则就会出现序列化版本不一致的异常(InvalidCastException)
 *          
 * 
 * @author Gary
 * @time 2019年8月7日
 */
public class Dog implements Serializable{

    //序列化版本号
    private static final long serialVersionUID = 565165413618L; 
    
    private String name;
    private int age;
    
    
    
    public String getName() {
        return name;
    }



    public void setName(String name) {
        this.name = name;
    }



    public int getAge() {
        return age;
    }



    public void setAge(int age) {
        this.age = age;
    }



    public Dog(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }



    @Override
    public String toString() {
        return "Dog [name=" + name + ", age=" + age + "]";
    }
    
    
}
package stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 处理流之六:对象流
 * 1、对象的序列化与反序列化:
 *         序列化:将java虚拟机中的对象转换成与平台无关的二进制流,从而
 *               允许把这种二进制流持久的保存在磁盘上,或者通过网络将这种
 *              二进制流传输到另一个网络节点。
 *         反序列化:当需要用到这种二进制流是,java虚拟机能够将其恢复成java对象
 * 
 * 2、序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,
 *       使其在保存和传输是可被还原。
 * 3、序列化是RMI(Remote Method Invoke-远程方法调用)过程的参数和返回值都必须实现的机制,
 *      而RMI是Java EE 的基础,因此序列化机制是javaEE平台的基础。
 * 4、如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类可序列化,
 *         改类必须实现如下两个接口 之一,否则,会抛NotSerializableException异常
 *         Serializable
 *         Externalizable
 * 
 * 对象流的使用
 * 1、ObjectInputStream和ObjectOutputStream
 * 
 * @author Gary
 * @time 2019年8月7日
 */
public class ObjectTest {
    
    
    public static void main(String[] args) {
        ObjOutput();
        ObjInput();
    }
    
    /**
     * 序列化
     */
    public static void ObjOutput() {
        
        ObjectOutputStream oos=null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("dat/obj.dat"));
            
            oos.writeObject(new Dog("小黑", 5));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if(oos!=null) oos.close();
                
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
        
    }
    
    /**
     * 反序列化
     */
    public static void ObjInput() {
        
        ObjectInputStream ois=null;
        try {
            ois = new ObjectInputStream(new FileInputStream("dat/obj.dat"));
            
            Dog dog = (Dog)ois.readObject();
            System.out.println(dog);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                
                if(ois!=null)ois.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
        
        
    }

}

 

RandomAccessFile流  一个特殊的流 即是输出流(男)又是输入流(女)***____***

package stream;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * RandomAccessFile类
 * 随机文件存取流(任意文件存取流)此翻译更为恰当
 *     RandomAccessFile声明字java.io包下,但直接继承于java.lang.Object类。
 * 并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以是读也可以是写
 *     RandomAccessFile类支持“随机访问”的方式,程序可以直接跳到文件任意地方来读、写文件
 *         支持只访问文件的部分内容
 *         可以向已存在的文件后追加内容
 *     RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。
 *     RandomAccessFile 类对象可以自由移动记录指针:
 *         long getFilePointer(); 获得文件记录指针当前位置
 *         void seek(long pos); 将文件记录指针定位到pos位置
 * 
 * RandomAccessFile的使用
 *     如果RandomAccessFile作为输出流时,写出到的文件不存在,则在执行过程中自动创建;
 *     如果写出到的文件存在,则会对源文件的内容进行覆盖;
 * 
 * 值含意
 * "r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。  
 * "rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。  
 * "rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。  
 * "rwd"   打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。  
 * "rws" 和 "rwd" 模式的工作方式极其类似 FileChannel 类的 force(boolean) 方法,分别传递 true 和 false 参数,除非它们始终应用于每个 I/O 操作,并因此通常更为高效。如果该文件位于本地存储设备上,那么当返回此类的一个方法的调用时,可以保证由该调用对此文件所做的所有更改均被写入该设备。这对确保在系统崩溃时不会丢失重要信息特别有用。如果该文件不在本地设备上,则无法提供这样的保证。 
 * "rwd" 模式可用于减少执行的 I/O 操作数量。使用 "rwd" 仅要求更新要写入存储的文件的内容;使用 "rws" 要求更新要写入的文件内容及其元数据,这通常要求至少一个以上的低级别 I/O 操作。

 * @author Gary
 * @time 2019年8月7日
 */
public class RandomAccessFileTest {
    
    public static void main(String[] args) {
        
        writeTest2();
        readTest();
    }
    
    /**
     * 写入操作
     */
    public static void writeTest() {
        
        RandomAccessFile raf1=null;
        try {
            raf1 = new RandomAccessFile("chat/record.txt", "rw");
            raf1.seek(new File("chat/record.txt").length());
            raf1.write("year".getBytes());
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                
                if(raf1!=null)raf1.close();
                
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
        
    }
    
    /**
     * 读文件
     */
    public static void readTest() {
        
        RandomAccessFile raf=null;
        try {
            raf = new RandomAccessFile("chat/record.txt", "r");
            
            byte[] buffer = new byte[1024];
            int len=0;
            while((len=raf.read(buffer))!=-1) {
                System.out.println(new String(buffer, 0, len));
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                
                if(raf!=null) raf.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }    
    }
    
    public static void writeTest2() {
        RandomAccessFile raf=null;
        try {
            raf = new RandomAccessFile("chat/record.txt", "rw");
            
            raf.write("xyz".getBytes());
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                
                if(raf!=null)raf.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
        
    }

}

 

-------第三方jar包,在企业级的开发中使用第三方API可以很好的提高工作效率

如Apache Commons;

若有需要,可以自行在官网下载,http://commons.apache.org/

下载教程------------

1、用浏览器打开该网站

2、如图选择Releases

 

3、在DownLoads下找到IO 点击

 

4、找到BinAries下的 commons-io-2.6-bin.tar.gz 点击下载

 

 5、下载完成后解压 点击commons-io-2.6.jar复制

-----------如何导入到eclipse中

1、打开eclipse

2、选择一个项目

3、右击选择new 新建一个文件夹一般将其命名为lib

 

6、然后将下载commons教程中第5步复制的jar包复制到lib文件中

7、右击lib文件夹选择build path-->Configure build path

 

8、选择上方的Libraries然后点击Add Jar

9、找到你刚刚建的文件夹,选择复制过去的jar包(我的已经导入过了,所以拿了另一个jar做案例你的应该是commons-io-2.6.jar)

10、点ok 然后点Applyandclose

11、完成导报,这样就可以使用包中的类了

 

----------感谢阅读   欢迎指错--------

 

posted on 2019-08-05 12:44  Gary757  阅读(185)  评论(0编辑  收藏  举报