面试题:JavaIO流分类详解与常用流用法实例

Java流概念:

Java把所有的有序数据都抽象成流模型,简化了输入输出,理解了流模型就理解了Java IO。可以把流想象成水流,里面的水滴有序的朝某一方向流动。水滴就是数据,且代表着最小的数据流动单位,在字节流中,水滴就是一字节(byte),在字符流中,水滴就是一字符(char)。

Java流的分类方法大致分为以下几种:

1、按流向划分,分为输入流、输出流

请注意,这里的流向是以程序的运行时内存为参照的。 
输入流类名中包含关键字InputStream或Reader,输出流类名中包含关键字OutputStream或Writer。

2、按操作的数据单元类型划分,分为字节流、字符流

字节流操作的数据单元是8位的字节(byte),字符流操作的是16位的字符。 
字节流类名中包含关键字InputStream或OutputStream,字符流类名中包含关键字Reader或Writer。 
请注意,系统输入输出(System.in与System.out)都为字节流。

3、按流的角色来划分,分为节点流与处理流

节点流是指程序可以向一个特定的节点读写数据,直接连接数据源; 
这个节点最常见的是文件,类名中包含关键字File;还可以是数组、管道、字符串,关键字分别为ByteArray/CharArray,Piped,String。

处理流并不直接连接数据源,它大多情况是对已存在的节点流进行包装,是一种典型的装饰器设计模式。使用处理流主要是为了更方便的执行输入输出工作,如PrintStream,输出功能很强大,推荐输出时都使用处理流包装。

注意:一个IO流可以即是输入流又是字节流又或是以其他方式分类的流类型,是不冲突的。比如FileInputStream,它既是输入流又是字节流还是文件节点流。

4、一些特别的的流类型

转换流,转换流只有字节流转换为字符流,因为字符流使用起来更方便,我们只会向更方便使用的方向转化。如:InputStreamReader与OutputStreamWriter。

缓冲流,有关键字Buffered,也是一种处理流,为其包装的流增加了缓存功能,提高了输入输出的效率,增加缓冲功能后需要使用flush()才能将缓冲区中内容写入到实际的物理节点。但是,在现在版本的Java中,只需记得关闭输出流(调用close()方法),就会自动执行输出流的flush()方法,可以保证将缓冲区中内容写入。

对象流,有关键字Object,主要用于将目标对象保存到磁盘中或允许在网络中直接传输对象时使用(对象序列化),具体可参看博客Java序列化与反序列化

推回输入流,有关键字PushBack,当程序调用推回输入流的unread()方法时,系统回把指定数组内容的内容推回到一个推回缓冲区中,在调用read()方法读入内容时,就先从推回缓冲区中读取,直到读完推回缓冲区中内容后才会从原输入流中读取。

必须要掌握的流用法实例: 
1、FileInputStream\FileOutputStream\FileReader\FileWriter(使用方法类似)

//文件字节输入流FileInputStream用法
public class TestFileIO1 {
    public static void main(String[] args)throws IOException{
        //此处路径可以使用相对路径与绝对路径
        FileInputStream fileInputStream = new FileInputStream("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO1.java");
        //一个字节数组作为缓冲,意为每次读取1024个字节,提高效率
        byte[] buffer = new byte[1024];
        //记录读取的字节数
        int hasRead = 0;
        //调用read()方法,返回实际读取的字节数
        while((hasRead = fileInputStream.read(buffer)) > 0){
            System.out.print(new String(buffer, 0, hasRead));
        }
        //关闭流
        fileInputStream.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
//文件字符输入流FileReader用法
public class TestFileIO2 {
    public static void main(String[] args)throws IOException{
        FileReader fileReader = new FileReader("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO2.java");
        char[] buffer = new char[32];
        int hasRead = 0;
        while((hasRead = fileReader.read(buffer)) > 0){
            System.out.print(new String(buffer, 0, hasRead));
        }
        fileReader.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
//文件字节输入流FileInputStream与文件字节输出流FileOutputStream结合
public class TestFileIO3 {
    public static void main(String[] args)throws IOException{
        File result = new File("output.txt");
        FileInputStream fileInputStream = new FileInputStream("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO3.java");
        FileOutputStream fileOutputStream = new FileOutputStream(result);
        byte[] buffer = new byte[1024];
        int hasRead = 0;
        while((hasRead  = fileInputStream.read(buffer)) > 0){
            fileOutputStream.write(buffer, 0, hasRead);
        }
        System.out.println(result.getAbsolutePath());
        fileInputStream.close();
        fileOutputStream.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
//文件字符输出流FileWriter用法
public class TestFileIO4 {
    public static void main(String[] args)throws IOException{
        File result = new File("output.txt");
        FileWriter fileWriter = new FileWriter(result);
        fileWriter.write("飞流直下三千尺,\r\n");
        fileWriter.write("疑是银河落九天.\r\n");
        fileWriter.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2、输出处理流PrintStream用法

public class TestFileIO5 {
    public static void main(String[] args)throws IOException{
            File result = new File("output.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(result);
        //PrintStream处理流功能极其强大,所有字节输出流都应使用PrintStream包装
        PrintStream printStream = new PrintStream(fileOutputStream);
        printStream.println("床前明月光,");
        fileOutputStream.close();
        printStream.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3、转换流inputStreamReader与缓冲流BufferedReader用法

public class TestFileIO6 {
    public static void main(String[] args)throws IOException{
        //系统输入为System.in,默认为从键盘输入,是字节输入流InputStream类型
        //使用转换流将InputStream转换为Reader字符输入流对象
        InputStreamReader inputStreamReader = new InputStreamReader(System.in);
        //将Reader包装为字符缓存处理流BufferedReader对象
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        //定义缓存行
        String bufferString = null;
        //使用BufferedReader特色readLine()方法逐行读取输入
        while((bufferString = bufferedReader.readLine()) != null){
            //直到输入exit,停止程序
            if(bufferString.equals("exit")){
                System.exit(0);
            }
            //控制台输出输入内容
            System.out.println("输入内容为:" + bufferString);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4、推回输入流PushbackInputStream

//通过一个返回某个字符串之前的文件内容的demo,理解推回输入流的读取缓存机制
public class TestFileIO7 {
    public static void main(String[] args)throws IOException{
        //创建一个推回字节输入流对象,指定缓冲区为64
        PushbackReader pushbackInputStream = new PushbackReader(new FileReader("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO7.java"), 64);
        char[] buffer = new char[32];
        //记录上次读取的字符串
        String lastContent = "";
        int hasRead = 0;
        while((hasRead = pushbackInputStream.read(buffer)) > 0){
            //将读取的字符转换为字符串
            String content = new String(buffer, 0, hasRead);
            int targetIndex = 0;
            //将上次读取的字符串和本次读取的字符串拼接
            //查找拼接后的字符串是否包含"new PushbackReader"(文件为此段源代码),返回位置由targetIndex记录
            if((targetIndex = (lastContent + content).indexOf("targetIndex")) > 0){
                //将拼接后字符串转化成字符数组后推回缓冲区
                String newContent = lastContent + content;
                pushbackInputStream.unread(newContent.toCharArray());
                //定义一个长度为targetIndex的char数组,如果新大小大于32,则需要重新定义
                if(targetIndex > 32){
                    buffer = new char[targetIndex];
                }
                //再次读取targetIndex长度的内容,其实就是目标字符串之前的内容
                pushbackInputStream.read(buffer, 0, targetIndex);
                //输出结果
                System.out.println(new String(buffer, 0, targetIndex));
                //退出程序
                System.exit(0);
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

5、重定向标准输入\输入 
Java的标准输入为System.in默认为键盘输入,标准输入为System.out默认为屏幕输出。可通过setInt(InputStream in)方法与setOut(PrintStream out)方法修改(在这里,连标准输出的字节输出流都被包装成了PrintStream,我们在编程时有什么理由不适用输出流呢?)。

public class TestFileIO8 {
    public static void main(String[] args)throws IOException{
        FileInputStream fileInputStream = new FileInputStream("input.txt");
        //重定向默认输入
        System.setIn(fileInputStream);
        //一次性创建PrintStream输出流对象(先创建文件字节输出流对象,再包装)
        PrintStream printStream = new PrintStream(new FileOutputStream("output.txt"));
        //重定向默认输出
        System.setOut(printStream);
        //获取System.in(input.txt文件中)的输入
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()){
            //下面这段标准输出会输出在Output.txt中
            System.out.println("输入的内容为:" + scanner.next());
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

6、对象处理流ObjectInputStream\ObjectOutputStream 
对象要想保存在磁盘或在网络上传输,其实体类必须可序列化,它是将对象转化为字节序列,使其可以脱机运行。 
要想实现序列化,实体类必须实现java.io.serializable接口。

//创建一个可序列化的实体类
public class Person implements Serializable{

    private String username;
    private int age;
    public Person(String username, int age){
        this.username = username;
        this.age = age;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class TestObjectIO {
    public static void main(String[] args) throws Exception{
        //ObjectOutputStream是一个处理流,必须建立在节点流上才能工作
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("output.txt"));
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("output.txt"));
        objectOutputStream.writeObject(new Person("Leeon", 21));
        Person person = (Person)objectInputStream.readObject();
        System.out.println(person.getUsername() + person.getAge());
        objectInputStream.close();
        objectOutputStream.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangliangzi/article/details/51226652

原文地址:https://www.cnblogs.com/shan1393/p/8996965.html

时间: 2024-10-05 23:26:57

面试题:JavaIO流分类详解与常用流用法实例的相关文章

java虚拟机启动参数分类详解

官方文档见: http://docs.sun.com/source/819-0084/pt_tuningjava.html java启动参数共分为三类:其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容:其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容:其三是非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用: 一.标准参数中比较有用的: verbose -verbo

(转)dp动态规划分类详解

dp动态规划分类详解 转自:http://blog.csdn.NET/cc_again/article/details/25866971 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少,多元性强,主要考察思维能力.建模抽象能力.灵活度. ****************************************************************************************** 动态规划(英语:Dynamic programm

c/c++面试题(6)运算符重载详解

1.操作符函数: 在特定条件下,编译器有能力把一个由操作数和操作符共同组成的表达式,解释为对 一个全局或成员函数的调用,该全局或成员函数被称为操作符函数.该全局或成员函数 被称为操作符函数.通过定义操作符函数,可以实现针对自定义类型的运算法则,并使之 与内置类型一样参与各种表达式运算. 2.首先我们先介绍下左值和右值,因为我们在运用运算符的时候要尽量和内置类型的一致性. 左值:有名的可以直接取地址的我们称之为左值,左值的特性是可以修改的. 右值:右值主要是一些临时变量,匿名变量,字符串字面值常量

H264码流处理详解

码流(Data Rate)是指视频文件在单位时间内使用的数据流量,也叫码率,是视频编码中画面质量控制中最重要的部分.同样分辨率下,视频文件的码流越大,压缩比就越小,画面质量就越好. 一.简介 H.264的主要目标:1.高的视频压缩比 2.良好的网络亲和性 解决方案: (1)VCL video coding layer 视频编码层 (2)NAL network abstraction layer 网络提取层 (3)VCL:核心算法引擎,块,宏块及片的语法级别的定义 (4)NAL:片级以上的语法级别

详解 内存操作流

目录 内存操作流: 字节内存操作流: 字符内存操作流: (请观看本人博文--<详解 I/O流>) 内存操作流 与之前所讲的几个流有很大的差别 容本人在这里卖个关子,相信同学们在之后的讲解中就会明白本人为何说初此话了. 那么,话不多说,开始本篇博文主题的讲解吧: 内存操作流: 概念: 此流之所以被叫做内存操作流的原因是: 此流是在内存中建立缓冲区以实现数据操作的流 正因为此原因,close()方法是无效的. 而且此流并没有将数据存入硬盘中,而是存入了内存中的一个缓冲区(即:数组)中 那么,现在,

详解 随机访问流

(请观看本人博文--<详解 I/O流>) RandomAccessFile 类 (随机访问流) 概述: RandomAccessFile 类 的实例支持对随机访问文件的读取和写入. 随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组. 存在指向该隐含数组的光标或索引,称为文件指针: 输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针.如果随机访问文件以读取/写入模式创建,则输出操作也可用: 输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针.写入隐

mybatis 详解(三)------入门实例(基于注解)

1.创建MySQL数据库:mybatisDemo和表:user 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 2.建立一个Java工程,并导入相应的jar包,具体目录如下 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 3.在 MyBatisTest 工程中添加数据库配置文件 mybatis-configuration.xml 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 4.定义表所对应的实体类 详情

IOS---UICOLLECTIONVIEW详解和常用API翻译

IOS---UICOLLECTIONVIEW详解和常用API翻译 UICollectionView 1.必须要设置布局参数 2.注册cell 用法类似于UITableView 类.自动实现重用,必须注册初始化. 使用UICollectionView必须实现UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout这三个协议. Collection View的构成,我们能看到的有三个部

实例详解C#抽象类及其用法(转)

今天学习抽象类和方法,对应该什么时候使用大伤脑筋,百度文库中找到一篇<实例详解C#抽象类及其用法>,觉得该例子通俗易懂,很好地解释了为什么要使用.如何使用抽象类和抽象方法,遂复制过来留存. 假如现在要开发一个模拟CS的游戏.要求如下: 1.游戏中要有恐怖分子,一个恐怖分子一次只能持有一支枪 2.游戏中有多种枪支 3.恐怖分子可以选择枪支使用 4.恐怖分子可以开枪杀人仅此4条,为了使程序足够简单,能说明我们主要目标就行,所以我们用控制台程序来模拟实现. 方法1我们先来看第一种实现情况,假设,游戏