`

IO系列文章之三:Java常用BIO实例总结

 
阅读更多

本文主要是对Java常用BIO(阻塞IO)操作的一个总结,整理一下分享出来,希望对看到的人有所帮助,同时也希望多多拍砖!酷

一、IO流

Java IO主要以流的方式操作,流就是数据传输,按传输方向分为输入流和输出流,按数据类型分为字符流和字节流。字节流以字节8bit为单位,字符流以字符为单位,处理多个字节。因此处理纯文本数据,就优先使用字符流,除此之外使用字节流。

字节流分别是InputStream、OutputStream的实现类。字符流分别是Reader、Writer的实现类。

二、数据读取

(此处记录的部分代码实例忽略了流关闭操作,使用时请自行添加)

1、FileReader

(1)日常经常会遇到文本文件读取的情况,由于文本中可能包含多种国家的语言,因此当然要使用字符流。

fileReader=new FileReader("test/FileReader.txt");
System.out.println("ready: "+fileReader.ready());
//FileReader不支持mark操作
System.out.println("markSupported: "+fileReader.markSupported());
int temp;
while((temp=fileReader.read())!=-1){
    System.out.print((char)temp);
}
//结束后继续read
temp=fileReader.read();
System.out.println("\nread eof:"+temp);

注,mark操作:标记流中的当前位置,对reset()的后续调用将尝试将该流重新定位到此点(FileReader不支持)。

上面程序中是一个字符一个字符的读取,当然如果觉得慢,可以使用BufferedReader类包装FileReader(装饰者模式),即可按行读取,后面会介绍。程序最后读到文件末尾会返回-1(EOF)。

(2)跳过一些字符:

fileReader=new FileReader("test/FileReader.txt");
long skip=fileReader.skip(3);
System.out.println("skip num: "+skip);
while((temp=fileReader.read())!=-1){
    System.out.print((char)temp);
}

上面的程序中,跳过了前3个字符,然后继续读取后面的。

(3)直接读入字符数组:

File file=new File("test/FileReader.txt"); 
fileReader=new FileReader(file);
//如果存储数组小于文件大小,会忽略文件后面的部分
char[] buff=new char[(int)file.length()];
fileReader.read(buff);
for(char c:buff){
    System.out.print(c);
}

2、BufferedReader

如果遇到需要按行读取的情况:

String tempStr="",content="";
//通过下列字符之一即可认为某行已终止:换行('\n')回车('\r')或回车后直接跟着换行.
while((tempStr=bufferedReader.readLine())!=null){
    content+=(tempStr+"\n");  //不包含任何行终止符和换行符.
}
System.out.println(content);

3、StringReader

当然有时不是文件从文件中读取,比如StringReader。

String str="abcdefghigklmn12345中文";
StringReader stringReader=new StringReader(str);
int temp;
try {
    while((temp=stringReader.read())!=-1){
	System.out.print((char)temp);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    stringReader.close();
}
4、LineNumberReader

LineNumberReader是BufferedReader的子类,除了支持按行读取外,还支持读取行号。

File file=new File("test/FileReader.txt");
FileReader fileReader = new FileReader(file);
LineNumberReader reader = new LineNumberReader(fileReader);
String content="";
while((content=reader.readLine())!=null){
    System.out.println(reader.getLineNumber()+":"+content);
}

5、ByteArrayInputStream

从字节数组中读取数据,使用ByteArrayInputStream,由于是按字节读取,所以中文不能正常显示。

bais=new ByteArrayInputStream(str.getBytes());
//返回可不发生阻塞地从此输入流读取的字节数.
System.out.println("available: "+bais.available());//一个汉字2个字节,一个\n一个字节.
System.out.println("markSupported: "+bais.markSupported());
//bais.mark(2);//mark(readAheadLimit).JDK_API注:readAheadLimit对于此类(ByteArrayInputStream)没有意义.
int tmp;
while((tmp=bais.read())!=-1){
    System.out.print((char)tmp);
}

直接读入另一个字节数组:

bais.reset();
byte[] buff=new byte[(int)file.length()];
bais.read(buff);
System.out.println(new String(buff));

6、BufferedInputStream

一个带有缓冲区的InputStream,并支持mark和reset的能力。

FileInputStream fis=new FileInputStream("test/abc.txt");
BufferedInputStream in = new BufferedInputStream(fis);
byte[] readbytes1=new byte[5];
byte[] readbytes2=new byte[7];
in.read(readbytes1);//从流中读5字节.
in.read(readbytes2);//继续从流中读7字节.
System.out.println("after read1:"+new String(readbytes1));
System.out.println("after read2:"+new String(readbytes2));
in.close();

7、DataInputStream

允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型。

bis=new BufferedInputStream(new FileInputStream(file));
dis=new DataInputStream(bis);
while(dis.available()!=0){
    char c=0;
    char[] strchar=new char[1024];
    int i=0;
    while((c=dis.readChar())!='\t'){
        strchar[i]=c;
	i++;
    }
    System.out.println(new String(strchar,0,i));
    System.out.print((char)dis.readChar()+" ");
    System.out.print(dis.readDouble()+" ");
    System.out.print(dis.readInt()+" ");
    System.out.print(dis.readChar());
    System.out.print(dis.readBoolean()+" ");
    System.out.print(dis.readUTF());
}

8、PushBackInputStream:

PushBackInputStream回退流。

public static void main(String[] args) throws IOException{
        String str = "hello,world!";
        PushbackInputStream push = null;
        ByteArrayInputStream bat = null;
        bat = new ByteArrayInputStream(str.getBytes());
        push = new PushbackInputStream(bat);
        int temp = 0;
        while((temp = push.read()) != -1){
            if(temp == ','){
                push.unread(temp);
                temp = push.read();
                System.out.print("(回退" + (char) temp + ") ");
            }else{
                System.out.print((char) temp);
            }
        }
}

三、数据输出

(此处记录的部分代码实示例忽略了流关闭操作,使用时请自行添加)

1、输出到文件

设置filewriter的追加模式为true,每次都写入文件末尾。

BufferedWriter bw = new BufferedWriter(new FileWriter(new File("test/FileWriter.txt"),true));
bw.write(test);
bw.newLine();
bw.write(test);
bw.close();

2、输出到字节数组

String testStr="abcdefghijklmnopqrstuvwxyz";
ByteArrayInputStream bais=new ByteArrayInputStream(testStr.getBytes());
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int nextBytes=0;
while((nextBytes=bais.read())!=-1){
    baos.write(nextBytes);
}
byte[] bytes=baos.toByteArray();//创建一个新分配数组,其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中。
System.out.println("bytes:"+new String(bytes));
baos.close();
bais.close();

3、以Java基础数据类型形式输出

bos=new BufferedOutputStream(new FileOutputStream(file));
dos=new DataOutputStream(bos);
dos.writeChars("中文数据1\t");
dos.writeChar('c');
dos.writeDouble(1234.5d);
dos.writeInt(111);
dos.writeChars("\n");
dos.writeBoolean(true);
dos.writeUTF("中文数据2");
bos.close();
dos.close();

4、合并文件输出:

SequenceInputStream主要用来将2个流合并在一起,比如将两个txt中的内容合并为另外一个txt。

public static void main(String[] args) throws IOException{
        File file1 = new File("d:" + File.separator + "hello1.txt");
        File file2 = new File("d:" + File.separator + "hello2.txt");
        File file3 = new File("d:" + File.separator + "hello.txt");
        InputStream input1 = new FileInputStream(file1);
        InputStream input2 = new FileInputStream(file2);
        OutputStream output = new FileOutputStream(file3);
        //合并流
        SequenceInputStream sis = new SequenceInputStream(input1, input2);
        int temp = 0;
        while((temp = sis.read()) != -1){
            output.write(temp);
        }
        input1.close();
        input2.close();
        output.close();
        sis.close();
}

四、字节流到字符流的转换

有时在进行输入时只能获得字节流,但是又需要通过字符流读取数据的情况:比如在使用第三方类库的情况下又无法修改其源码,这时可以使用IO类库提供的输入输出流适配器InputStreamReader和OutputStreamWriter。

InputStreamReader:InputStreamReader是字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符

OutputStreamWriter:OutputStreamWriter是字符流通向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节

注:从JDK文档中知道FileOutputStream是OutputStream 的直接子类,FileInputStream也是InputStream的直接子类,但是在字符流文件中的两个操作类却有一些特殊,FileWriter并不直接是Writer的子类,而是OutputStreamWriter的子类,而FileReader也不直接是Reader的子类,是InputStreamReader的子类,那么从这两个类的继承关系就可以清楚地发现,不管是使用字节流还是字符流实际上最终都是以字节的形式操作输入/输出流的,且最终全部是以字节的形式保存在文件中。

 

结束语

上文中介绍的都是Java IO类库中一些常见的输入输出操作,除了几个类之外,Java IO类库还提供了更丰富的API,请查阅文档。另外,Apache的开源项目commons-io也对一些常见的IO操作都进行了封装,使用起来很方便。

分享到:
评论
1 楼 yuanliangding 2016-08-20  
谢谢分享。可以在画一些继承图。我以前是画了图后才清晰了

相关推荐

    Java岗面试核心MCA版.pdf

    1. BIO、NIO、AIO的区别:BIO是阻塞式IO,NIO是非阻塞式IO,AIO是异步IO。 2. Files的常用方法:Files类提供了许多文件操作方法。 反射机制 1. 反射机制的优缺点:反射机制可以动态地调用类和方法,但也可能会...

    详解Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

    本篇文章主要介绍了 Java 网络IO编程总结,包括 BIO、NIO 和 AIO 三种模型,并提供了完整的实例代码。 BIO(Blocking I/O) BIO 是传统的同步阻塞模型,服务器端使用 ServerSocket 监听客户端的连接请求,客户端...

    java程序实例原版

    9. **IO/NIO/BIO**:Java提供不同的I/O模型,如传统的 Blocking I/O (BIO),NIO (New I/O) 和 NIO 2.0,学习它们的异同和应用场景能提升程序性能。 10. **网络编程**:Java的`java.net`包允许开发网络应用程序,如...

    Java三种IO模型原理实例详解

    "Java三种IO模型原理实例详解" Java中的IO模型可以分为三种:BIO(同步阻塞)、NIO(同步非阻塞)和AIO(异步非阻塞)。每种模型都有其特点和应用场景。 BIO(同步阻塞) BIO是最古老的IO模型,在JDK1.4之前都是...

    JavaGuide.pdf

    答:Java 中的 IO 模式有 BIO、NIO、AIO 等。 14. Java 中的 BIO、NIO、AIO 的区别是什么? 答:BIO 是阻塞式 IO,NIO 是非阻塞式 IO,AIO 是异步 IO。 Java 异常 15. Java 中的异常是什么? 答:Java 中的异常是...

    scalable-io-in-java-中文.pdf

    在深入探讨《Scalable IO in Java》的中文版内容之前,首先需要了解Java中的I/O模型发展历程及其在服务器编程中的重要性。在Java中,I/O处理经历了从传统的BIO(阻塞I/O),到NIO(非阻塞I/O),再到AIO(异步I/O)...

    scalaable java io

    Java NIO(New Input/Output)是Java标准库中提供的一种I/O模型,它在Java 1.4版本中被引入,替代了传统的Java IO(BIO)模型。NIO的核心在于非阻塞I/O和通道与缓冲区的使用,它提供了更高效、更灵活的数据读写方式...

    java面试八股文java基础知识总结.pdf

    ### Java基础知识总结 #### Java概述 - **何为编程**:编程是指通过编写代码来告诉计算机执行特定任务的过程。这包括定义数据结构、算法逻辑、输入输出操作等。 - **什么是Java**:Java是一种广泛使用的高级编程...

    Java 基础核心总结 +经典算法大全.rar

    《Java 基础核心总结》 Java 概述 什么是 Java2 Java 的特点Java 开发环境 JDK JRE Java 开发环境配置 Java 基本语法 数据类型基础语法运算符 Java 执行控制流程条件语句 if 条件语句 if...else 条件语句if...else ...

    面试精选+个人使用+msb

    Java中IO流分为BIO、NIO和AIO三种。Files类是Java中常用的IO流类。 反射机制: Java语言的反射机制是指在运行时检查和修改类的信息。反射机制的优点是可以在运行时动态地检查和修改类的信息。 String相关: Java...

    Java综合面试资料集

    1. BIO、NIO、AIO:BIO 是阻塞式 IO,NIO 是非阻塞式 IO,AIO 是异步 IO。 2. Files 的常用方法:Files 类提供了许多常用的 IO 方法,例如读取文件、写入文件等。 反射机制知识点: 1. 反射机制:反射机制是 Java ...

    Java AIO 实例(转)

    在Java中,BIO( Blocking I/O)模型是同步且阻塞的,当一个线程执行读写操作时,如果数据没有准备好,线程会一直等待,直到数据准备好。这种方式对于少量连接是可行的,但当面对大量的并发连接时,服务器可能会因为...

    Java通讯模型-BIO、NIO、AIO综合演练

    4. **应用实例**:Java的`java.io`包下的大多数类,如`Socket`、`ServerSocket`等。 **二、NIO(非阻塞I/O)** 1. **概念**:NIO是Java 1.4引入的新特性,它提供了一种非阻塞的I/O操作方式,通过选择器(Selector)...

    Backend_development:JAVA进阶代码实例&最新面试题(看完涨薪2k+)

    15.Java 中 IO 流分为几种? 16.BIO、NIO、AIO 有什么区别? 17.Files的常用方法都有哪些? 容器 18.Java 容器都有哪些? 19. Collection 和 Collections 有什么区别? 20. List、Set、Map 之间的区别是什么? 21....

    JAVA-NIO程序设计完整实例

    Java NIO(New IO)是Java 1.4引入的一个新特性,它为Java提供了非阻塞I/O操作的能力,使得Java在处理I/O时更加高效。NIO与传统的BIO(Blocking I/O)模型相比,其核心在于它允许程序同时处理多个输入和输出流,提高...

    200个Java经典面试题总结附带答案.docx

    Java经典面试题总结附带答案 以下是从给定文件中生成的相关知识点: Java基础 1. JDK 和 JRE 的区别是什么?(JDK 是 Java Development Kit,JRE 是 Java Runtime Environment) 2. `==` 和 `equals` 的区别是...

    Java岗面试核心MCA版

    - **Files的常用方法**:`Files`类提供了一系列静态方法用于文件和目录的操作,如读取、写入、创建、删除等。 #### 十三、反射机制 - **反射机制**:Java反射允许程序在运行时获取类的信息(如字段、方法等)并操纵...

    (2020最新)Java面试题.pdf

    Java是当前最流行的编程语言之一,它广泛应用于各种领域,如Android应用开发、Web应用开发、企业软件开发等。面试中,Java问题涵盖了从基础知识到框架、中间件、数据库等方面。下面是对Java面试题的知识点总结: ...

    01-VIP-BIO,NIO,AIO精讲1

    本篇文章将深入探讨三种主要的Java IO模型:BIO( Blocking IO)、NIO(Non-Blocking IO)和AIO(Asynchronous IO),并以代码实例解析它们的工作原理和优缺点。 首先,我们来看BIO,即同步阻塞IO模型。在BIO中,每...

    Java面试总结.pdf

    Java面试总结涉及Java基础知识和并发方面的面试题目和概念,包括JRE与JDK的区别、Java数据类型、集合类的使用、基本和引用类型的比较、hashcode()的作用,以及Java多线程的概念和相关问题。以下是详细的知识点: 1....

Global site tag (gtag.js) - Google Analytics