Java文件输入输出流及标准I/O流类知识总结

Java文件输入输出流及标准I/O流类知识总结

前几天参加了某企业的笔试,最后一道笔试题的题目大概是这样:

给定文件名filename以及一个字符串str,要求从文件中搜索该字符串,并且输出该字符串所在文件中的行数


背景

这道题考察的是对于文件输入输出流以及字符串的一道基本题目,可以算是比较基本的题目,但是由于太久没有复习,结果写的不是特别好,所以今天对文件输入输出流做一个复习和总结。


在这里插入图片描述
这是一张网上找的一张关于IO流操作的图片,这里我们可以看到I/O流分为字节流和字符流,从更加细致的划分,我们应该把IO流分为输入以及输出

编程语言的I/O类库中常使用这个抽象概念,它代表任何有呢你产出数据的数据源对象或者是有能力接收数据的接收端对象。它屏蔽了实际I/O设备中处理数据的细节。

通过上述类图,我们可以知道我们需要关心的5个类应该有File、OutputStream、InputStream、Writer、Reader;

InputStream

InputSream:通过名称我们可以知道,他的作用是从数据源中获取数据,一共有7种不同类型的输入流:

功能如何使用
ByteArrayInputStream允许将内存缓冲区当作InputStream需要配合FilterInputStream来使用
StrirgBufferInputStream将String转换为输入流需要配合StringBuffer来使用
FileInputStream从文件中读取信息后面详解
PipedInputStream写入与PipedOutputStream相关数据实现操作系统中“管道”概念的输入(多线程相关)
SequencedInputStream将多个InputStream转换成单一InputStream实现多个输入流
FilterInputStream抽象类,作为“装饰器”接口,为其他InputStream提供功能

OutputStream

功能如何使用
ByteArrayOutputStream允许将内存缓冲区当作OutputStream需要配合FilterInputStream来使用
FileOutputStream从文件中写入信息后面详解
PipedOutputStream写入与PipedOutputStream相关数据实现操作系统中“管道”概念的输入(多线程相关)
FilterOutputStream抽象类,作为“装饰器”接口,为其他OutputStream提供功能

在这里插入图片描述
InputStream实现了closeable接口,用来处理io流的关闭
实现的方法

从inputstream中读取下一个字节,返回值为从0-255.如果到达了输入流的结尾,那么方法返回值为-1。
这个方法会一直阻塞直至有可读的数据,当到达输入流结尾时,会抛出一个异常
public abstract int read() throws IOException;//抽象方法
从inputstream中读取n个字节到传入的byte数组中。会尝试一次读取len个长度的字节,但有可能读取
到<len个字节的数据,这个方法同样会阻塞,同时到达结尾时也会抛出异常。当len等于0时,不读取任何
字节并返回0.到达末尾时会返回0,否则至少一个字节的数据会被读取并传入b中。
第一个字节的输入被存入b[off]中,下一个字节存入b[off+1]的字节数组中,以此类推。读取的字节数
最多与len相等。k等于实际读取的字节数,此时b[off]到b[off+k-1]存储读取的字节数据
b[off+k]到b[off+len-1]不受影响
当读到最后一个字符时,或者输入流被关闭时,会抛出IOException 
public int read(byte b[], int off, int len) throws IOException//抽象方法
从输入流中读取所有剩余的字节,同样会阻塞;当读到最后一个字符时,继续调用该方法会返回一个空的
字节数组
当输入流被关闭时,会抛出IOException 
 public byte[] readAllBytes() throws IOException
从字节流中读取n个字节,调用了上面的read方法
 public byte[] readNBytes(int len) throws IOException
与上面的类似,不同点是将返回值传入byte数组b中,调用的同样是
public int readNBytes(byte[] b, int off, int len) throws IOException 
跳过输入流中的N个字节
public long skip(long n) throws IOException 
记录当前读到的位置
public synchronized void mark(int readlimit) {}
读取所有输入流中的数据并传输到输出流中
public long transferTo(OutputStream out) throws IOException
获取剩余可读字节数的估计值
public int available() throws IOException {
        return available0();
    }
private native int available0() throws IOException;

TODO:OutputStream

装饰者模式

在这里插入图片描述
I/O流的设计采用了装饰者模式,简单的来说就是为被装饰者添加新的功能,即加上一层“包装”,核心还是利用了java多态的性质,装饰者类和被装饰者都实现Component接口,同时装饰者内部持有被装饰者的引用,重写operation接口方法来实现对方法的增强。最后调用方法的时候,会按照装饰的顺序层层地来调用方法。
参考文章
在这里插入图片描述

Reader与Writer(字符输入流与输出流)

从上面的inputstream(outputstream也类似)我们可以知道其是将输入读取到一个字节数组中。但是在平时编程的情况中,我们很大一部分时间是在处理字符,因此字符输入流和输出流就提供了将字节流转化为字符流的功能:InputStreamReader可以把InputStream转化为Reader,而OutputStreamWriter可以把OutputStream转换为Writer
这里的处理运用到了适配器模式这里先不展开,以后有时间再做记录,适配器模式主要目的在于兼容

public InputStreamReader(InputStream in) {
        super(in);
        try {
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
        } catch (UnsupportedEncodingException e) {
            // The default encoding should always be available
            throw new Error(e);
        }
    }

这里是通过传入inputStream,通过StramDecoder也就是解码器来将输入流转化为字符串处理

所以一般输入输出的处理过程是:

输入流(inputstream)——>Reader——>Writer——>输出流(OutputStream)

处理流

  • 文 件 :FileInputStream 、 FileOutputStrean 、FileReader 、FileWriter
  • 数 组 :ByteArrayInputStream、 ByteArrayOutputStream、 CharArrayReader 、CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)
  • 字符串 :StringReader、 StringWriter 对字符串进行处理的节点流
  • 管 道 :PipedInputStream 、PipedOutputStream 、PipedReader 、PipedWriter 对管道进行处理的节点流

分别选取一个常见的Reader与Writer分析一下源码

BufferedReader

BufferedReader 是缓冲字符输入流。它继承于Reader。
BufferedReader 的作用是为其他字符输入流添加一些缓冲功能。
方法:
在这里插入图片描述

 	private Reader in;  
    private char cb[]; //字符缓冲区
    private int nChars, nextChar;
    //分别表示当前字符总数,下一个字符指针
    private static final int INVALIDATED = -2; 
    private static final int UNMARKED = -1;
    private int markedChar = UNMARKED;
    private int readAheadLimit = 0; /* 只有在markedChar > 0的时候生效 */
    /** 标志位,是否忽略换行符 */
    private boolean skipLF = false;
    /** The skipLF flag when the mark was set */
    private boolean markedSkipLF = false;
    //默认字符缓冲区大小
    private static int defaultCharBufferSize = 8192;
    //默认每一行的字符个数 
    private static int defaultExpectedLineLength = 80;
构造函数
public BufferedReader(Reader in, int sz) {
        super(in);
        if (sz <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
        this.in = in;
        cb = new char[sz];
        nextChar = nChars = 0;
    }
调用了父类的构造函数
protected Reader(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }   
//这里是初始化了一个字符数组,同时也是使用了装饰者模式,装饰传进来的reader对象。将传进来的reader对象当作锁,这里应该是在对reader进行操作的时候加锁,防止多线程情况下出现的线程同步问题

这里回到我们一开始提到的题目:给定文件名filename以及一个字符串str,要求从文件中搜索该字符串,并且输出该字符串所在文件中的行数 思路:
  • 构造InputStream
  • 利用Reader读取,放入缓冲区
  • 按行读取字符串
String str;
FileInputStream fileStream=new FileInputStream("/Users/wangzhiwang/fileName");//选定文件
    	InputStreamReader isr=new InputStreamReader(fileStream,"utf-8");//读入文件
    	BufferedReader br=new BufferedReader(isr);//将读入的文件放入缓冲区
    	String line;
    	int lineNum  = 0;
    	while((line=br.readLine())!=null)//在缓冲区中不断取出一行数据
    	{
    		lineNum++;
    		if(line.indexOf(str)!=-1){
    		System.out.println(lineNum+":"+str)
    		}
    		
    	}

参考文章:
Java IO流学习总结一:输入输出流
《java与设计模式》之装饰模式详解&Java IO中的装饰器模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默终止

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值