Java之IO技术详解以及所遇到的问题

IO操作是我们在开发中所需要的必不可少的技能。因此能够完整的认识和使用IO流对我们开发有着巨大的帮助。
首先我们要知道什么是IO流:IO即输入输出,而要达到这一目的,在Java中我们需要一种机制来帮助我们完全,这种机制就是"流"、或者叫"数据流"。
接下来我们来看一下IO流的分类

IO流的分类

按传输的数据单位来分:

  • 字节流:InputStream、OutpurStream
  • 字符流:Writer、Reader
    按照传输方向来分:
  • 输入流:…input、…reader
  • 输出流:…output、…writer
    按照流的处理功能来分:
  • 节点流:FileInputStream等
  • 处理流:BufferedInputStream等

节点流

Java中流基本都继承自四大节点流:InputStream、OutpurStream、Writer、Reader。这四个流属于抽象类,我们分别以InputStream和Reader为例。
我们来看一下InputStream的基本方法
InputStream

public abstract int read() throws IOException;
//一次读取一个字节的数据,返回读取的数据
public int read(byte[] b) throws IOException;
//一次读取一个字节数组的数据,读入的数据保存在字节数组里,返回值为实际读取的长度
public int read(byte[] b,int off,int len)throws IOExecption;
//一次读取字节数组中的指定位置的指定长度的数据,返回值同样是实际读取的长度

Reader

public int read()throws IOExecption;
//一次性读一个字符,因为char和int可以互相转换,所以返回int类型
public int read(char[] cbuf)throws IOExecption;
//一次性读取一个字符数组,返回值为实际读取的长度
public int read(char[] cbuf,int off,int len)throws IOExecption;
//一次性读取指定字符数组指定位置指定长度的数据,返回值为实际读取的长度.

了解完InputStream和Reader,剩下的两个抽象类的操作方法和他们一一对应。因为上述四个类是流的基类,所以我们具体进行操作需要使用他们的子类完成动作。
FileInputStream与FileOutputStream继承自InputStream和OutputStream,是对于文件进行输入输出的标准类,但是缺点是不管是输入输出都需要通过字节数据或者字节数组来完成。
FileReader与FileWriter继承自InputStreamReader和inputStreamWriter,这两个流是转换流,完成了将字节流转换成字符流的操作,所以从某种意义上来说FileReader与FileWriter也可以视为是一种转换流,因为实际上字符流是对字节流的一种特殊处理。
这里有一个需要注意的地方:因为字符输出流FileOutputStream在输出的时候使用了缓冲区,所以在输出操作时需要调用flush方法或者必须关闭流,不然可能导致数据输出不能达到想要的效果。

内存流

正常的时候我们的都是程序和磁盘数据交互时使用IO流,输入和输出都是从文件中来的,当然,也可将输出的位置设置在内存上,这就需要ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream:将内容写入到内存中,
ByteArrayOutputStream:将内存中数据输出
此时的操作应该以内存为操作点。
因为这和其他IO流的传输方向有些许不同所我们需要特殊注意下该类的构造方法。

public ByteArrayInputStream(byte[] buf)
//该类在创建时就已经将指定的字节数组的数据保存到了内存中

同时我们需要注意下ByteArrayOutputStream提供了一些特殊的方法。

void write(byte[] b, int off, int len) ;
//我们可以将内存中已经存入的数据写入指定字节数组的指定位置和大小的文件
public byte[] toByteArray();
//因为内存中已经存入了数据,所以我们可以直接将内存中的数据以一个字节数组的方式返回
public String toString();
//这个方法时内存流中比较特殊的方法,有了这个方法我们在进行某些操作的时候
//可以一步步的将数据先写入内存中,最后统一通过toString方法拿出。
 

看完了内存流,除了程序和内存之间的输入输出操作意外,不同的线程之间当没有公共的存储区域时,需要进行线程间 的数据交互就可以使用到管道流。
PipedInputStream和PipedOutputStream,这两个类的基本操作和上面的操作方法并无不同,唯一需要注意的时因为时两个线程之间进行的IO操作,所以两个线程之间的输入输出流需要进行绑定,通过构造方法和connect方法都可以达到目的,我们这里以PipedInputStream为例。

//在创建对象时可以进行连接
public PipedInputStream(PipedOutputStream src)throws IOException
//可以通过调用connec方法进行连接
public void connect(PipedOutputStream src) throws IOException

最后我们需要说一个特殊的“流”随机文件访问流RandomAccessFile,严格意义上来说这个并不是一个真正的流,但是它完成了某些流的功能。并且我们需要注意,我们需要正常操作这个流,他的输入输出数据的格式一般都需要指定格式,下面我们来看一下这个类中的一些操作。

//构造方法
RandomAccessFile(File file, String mode)//这里需要注意的时需要传入一个指定模式的字符串,用来代表你创建的这个流可以对文件进行哪些操作
//常用的模式有两个“r”代表只读,“rw”代表可读可写。
public void seek(long pos) throws IOException;
//随机文件访问流中具有一个字节指针,改方法是将这个字节指针回调到指定位置
public int skipBytes(int n)throws IOEXecption;
//该方法是将这个字节指针跳过指定字节

处理流

看完了字节流我们来看一下处理流,处理流是基于字节流的基础上进行操作的,是对字节流的一种包装处理,采用了装饰者模式。常用的处理流有打印流PrintStream、BufferedInputStream、BufferedReader等
PrintStream
我们注意到标准的输出流中都需要基于字节数组或字符数组进行操作,因此在开发过程中使用起来很不方便,因此对标准输入输出流进行了一些包装操作,因而产生了打印流。接下来我们来看下PrintSteam的基本结构。

//因为处理流是建立在节点流之上,所以操作时需要传入节点流
PrintStream(OutputStream out) Creates a new print stream.
//我们熟悉的System.out就是一个标准打印流里面提供了各种打印方法

因此我们在进行向文件中写入数据的时候,使用打印流是非常方便的。
BufferedReader
因为缓冲流在进行输入输出的时候使用到了缓冲区,所以它的传输速度是要快于标准输入输出流的,同时该流中还有一个特殊的方法。

//该类刚开始是为了解决键盘输入问题而解决的,而该类的构造方法只能够接
//Reader及其子类,而系统提供的键盘输入流只有System.in所以我们在创建
//缓冲流解决键盘输入时需要进行以下操作
new BufferedReader(new InputStreamReader(System.in));
//该方法可以一次读取对应的一行数据
public String readLine();

总结与问题

基本认识完以上的类,相信你对IO已经有一定的认识,博主也是在IT路上不断奋斗的青年,毕竟才疏学浅难免漏洞百出,如有朋友发现问题请及时指出。同时我在进行IO测试时也遇到一个问题迟迟找不出问题的答案,若有朋友知道,麻烦不吝赐教。
问题如下:我在进行对象序列化与反序列化时,发现如果先执行①的操作,将对象写入内存,然后将①处代码注释,执行②处代码,会报出Exception in thread “main” java.io.EOFException,但是如果将创建对象输出流的代码注释掉,则不会出现此异常。


public class SerializableTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("E:"+ File.separator+"Object"));
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("E:"+ File.separator+"Object"));
        out.writeObject(new Person("张三",20));// ①
        out.close();// ①
        System.out.println(in.readObject());// ②
        

        //System.out.println(o);

    }
}
class Person implements Serializable{
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值