Last modified:2013-06-13 08:01:44
***********************************************
IO流总结一:
IO流是处理数据之间数据传输的。
Java对数据的操作是通过流的方式。
Java中用于操作IO流的对象都放在java.io包中。
流的分类:按照操作数据分为:字符流和字节流。
按照流向分为:输入流和输出流。
输入流: 输出流:
字符流:
Reader Writer
|--BufferedReader |-- BufferedWriter
|--inputStreamReader |--OutputStreamWriter
|--FileReader |--FileWriter
字节流:
InputStream OutputStream
|--FileInputStream |--FileOutputStream
InputStream OutputStream
|--FilterInputStream |--FilterOutputStream
|--BufferedInputStream |--BufferedOutputStream
在计算机中存储的都是1和0的序列。也就是二进制的有序序列,不论是文本、音乐或者是视频。
那么为什么要在流中定义字节流和字符流呢?
这个与我们的字符编码方式有关。我们都知道世界上有很多种的语言,比如:ASCII、GB2312、GBK、UTF-8和Unicode等。
如果一个文本文件使用GB2312编码的方式存储的,如果我们用Unicode的编码方式来读取,那么就会出现乱码。所以字符流是一种特殊的流,在java中就定义了专门处理字符的流对象。
当我们拿到一个API文档我们应该如何使用呢?
1,确定要使用的功能。
2,查阅API看有没有相关的功能类。
3,如果没有,就分析需要如何自定义一个出来,并且要使用到那些相关功能的类,这些类在API中有没有定义。
4,不论有或者没有需要自定义一个,我们都要先查阅相关功能类的根类,那么查阅一个API的时候我们要注意一些什么呢?
5,找到相关功能根类,先看一下它是一个类,还是接口,还是抽象类,如果是接口或者是抽象类我们就不能直接使用这个类,而要使用这个类的子类。
6,但是,我们不用急于先看它有哪些子类,我们先看一下它到底暴露了什么字段、构造函数和方法。
7,在查看暴露的信息时,我们要注意几点:
a. 如果是static修饰的,说明是静态的,我们不用new对象也可以直接使用。
b. 确定使用的方法返回数据的类型,是void呢、String呢、int呢、还是其他的。查找的时候就重点找返回这些类型的方法。(注意:如果我们使用的类是一个使用单例设计模式设计的,那么他就没有构造函数,我们就一般可以通过静态的getIstance()方法获取相应的对象,这时我们就要找返回值是对象类型的方法。)
8,如果在根类中找到了需要的方法,但是根类又不能创建对象,那么我们就看看,继承这个根类的子类有哪些,一般子类都继承了父类的方法,所以子类可以直接调用父类的方法,并且子类又定义了一些自身特别的方法。
9,找到需要的类创建对象,或者找到相关功能的对象自定义一个需要的类。
下面我们按照以上的方法来阐述IO流的学习:
字节流:
字节流的根类有:读取流(Reader)、写入流(Writer)
根类都是abstract(抽象)的,我们不能直接创建对象,但是我们可以看一看父类都定义了什么方法。
Reader:
int read()
读取单个字符。
int read(char[] cbuf)
将字符读入数组。
abstract int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。
int read(CharBuffer target)
试图将字符读入指定的字符缓冲区。
abstract void close()
关闭该流并释放与之关联的所有资源。
FileReader:Reader的子类,可以创建对象,专门用来操作字符数据流的。
Writer:
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(int c)
写入单个字符。
void write(String str)
写入字符串。
void write(String str, int off, int len)
写入字符串的某一部分。
abstract void close()
关闭此流,但要先刷新它。
abstract void flush()
刷新该流的缓冲。
写入流(Writer)在每次调用write()方法的时候都要flush()(刷新)一次,当然Writer也不能创建对象,我们可以使用他的子类FileWriter,FileWriter是专门处理字符写入流的类。
FileReader 和 FileWriter 为我们提供了操作字符数据流的一般方法,其中比较高效的就是自定义一个数组,用这个数组作为临时存储区,每次读取一块(装满数组)数据,然后再将这一块数据写入相应的目的地。这样就提高了效率,如果每次读取一个字符然后写入一个字符,就很低效,是不可取的。
自定一个数组为我们提高了效率,但是每次使用都要写很多代码,所以开发者就将这个数组封装为了一个特殊的对象。那就是缓冲区!BufferedReader(字符读取缓冲区)和BufferedWriter(字符写入缓冲区)。他是用的是装饰设计模式,是再不改变原来已定义类的基础上增强类的功能。
补充:BufferedReader的子类LineNumberReader,增加了int getLineNumber() :获得当前行号的功能,我们可以在使用缓冲区的同时读取行号。
装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。
字符流学习完了,那么如果要学习字节流就会简单很多,我们通过查阅API知道:很多方法都似曾相识。所以,总结一下就是下面几点:
A. 字节流分为:InputStream(读取流)和OutputStream(写入流)
B. 字节流和字符流的功能基本相同,只不过传入的参数由字符流中的字节char,变成了字节中的byte。
C. 字节流也具有缓冲区:
BufferedInputStream(字节读取缓冲区)和BufferedOutputStream(字节写入缓冲区)。方法与字符缓冲区相似。
下面自定义一个BufferedInputStream:
import java.io.*; class MyBufferedInputStream { private InputStream in; private byte[] buf = new byte[1024*4]; private int pos = 0,count = 0; MyBufferedInputStream(InputStream in) { this.in = in; } //一次读一个字节,从缓冲区(字节数组)获取。 public int myRead()throws IOException { //通过in对象读取硬盘上数据,并存储buf中。 if(count==0) { count = in.read(buf); if(count<0) return -1; pos = 0; byte b = buf[pos]; count--; pos++; return b&255; } else if(count>0) { byte b = buf[pos]; count--; pos++; return b&0xff; } return -1; } public void myClose()throws IOException { in.close(); } }
结论:
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
明白了BufferedReader类中特有方法readLine的原理后,
可以自定义一个类中包含一个功能和readLine一致的方法。
来模拟一下BufferedReader
import java.io.*; class MyBufferedReader extends Reader { private Reader r; MyBufferedReader(Reader r) { this.r = r; } //可以一次读一行数据的方法。 public String myReadLine()throws IOException { //定义一个临时容器。原BufferReader封装的是字符数组。 //为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。 StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=r.read())!=-1) { if(ch=='\r') continue; if(ch=='\n') return sb.toString(); else sb.append((char)ch); } if(sb.length()!=0) return sb.toString(); return null; } /* 覆盖Reader类中的抽象方法。 */ public int read(char[] cbuf, int off, int len) throws IOException { return r.read(cbuf,off,len) ; } public void close()throws IOException { r.close(); } public void myClose()throws IOException { r.close(); } } class MyBufferedReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("buf.txt"); MyBufferedReader myBuf = new MyBufferedReader(fr); String line = null; while((line=myBuf.myReadLine())!=null) { System.out.println(line); } myBuf.myClose(); } } import java.io.*; class MyLineNumberReader extends MyBufferedReader { private int lineNumber; MyLineNumberReader(Reader r) { super(r); } public String myReadLine()throws IOException { lineNumber++; return super.myReadLine(); } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public int getLineNumber() { return lineNumber; } } /* class MyLineNumberReader { private Reader r; private int lineNumber; MyLineNumberReader(Reader r) { this.r = r; } public String myReadLine()throws IOException { lineNumber++; StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=r.read())!=-1) { if(ch=='\r') continue; if(ch=='\n') return sb.toString(); else sb.append((char)ch); } if(sb.length()!=0) return sb.toString(); return null; } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public int getLineNumber() { return lineNumber; } public void myClose()throws IOException { r.close(); } } */ class MyLineNumberReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("copyTextByBuf.java"); MyLineNumberReader mylnr = new MyLineNumberReader(fr); String line = null; mylnr.setLineNumber(100); while((line=mylnr.myReadLine())!=null) { System.out.println(mylnr.getLineNumber()+"::"+line); } mylnr.myClose(); } }
io流有很多实例,那么在实际操作中如何确定使用哪个io流的实例呢?
1,
源:键盘录入。
目的:控制台。
2,需求:想把键盘录入的数据存储到一个文件中。
源:键盘。
目的:文件。
3,需求:想要将一个文件的数据打印在控制台上。
源:文件。
目的:控制台。
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个。
通过三个明确来完成。
1,明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer。
2,操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3,当体系明确后,在明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘。键盘
目的设备:内存,硬盘,控制台。
1,将一个文本文件中数据存储到另一个文件中。复制文件。
源:因为是源,所以使用读取流。InputStream Reader
是不是操作文本文件。
是!这时就可以选择Reader
这样体系就明确了。
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘。上一个文件。
Reader体系中可以操作文件的对象是 FileReader
是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的:OutputStream Writer
是否是纯文本。
是!Writer。
设备:硬盘,一个文件。
Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。
---------------------------------------
2,需求:将键盘录入的数据保存到一个文件中。
这个需求中有源和目的都存在。
那么分别分析
源:InputStream Reader
是不是纯文本?是!Reader
设备:键盘。对应的对象是System.in.
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
所以既然明确了Reader,那么就将System.in转换成Reader。
用了Reader体系中转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
**************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
但是FileWriter是使用的默认编码表。GBK.
但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter。
而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
需要高效吗?需要。
BufferedWriter bufw = new BufferedWriter(osw);
所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
需要用到转换流。
练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
class TransStreamDemo2 { public static void main(String[] args) throws IOException { System.setIn(new FileInputStream("PersonDemo.java")); System.setOut(new PrintStream("zzz.txt")); //键盘的最常见写法。 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out)); String line = null; while((line=bufr.readLine())!=null) { if("over".equals(line)) break; bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush(); } bufr.close(); } }
相关推荐
在这个大总结中,我们将深入探讨Java IO流的基本概念、分类、常用类以及实践应用。 1. **基本概念** - **流(Stream)**:在Java中,流是一个抽象的概念,代表数据的有序序列。它可以是字节流或字符流,流向可以是...
下面是对Java IO流的详细总结: 1. 流的概念: 流是一种抽象的数据传输方式,可以将数据从一个地方传输到另一个地方。Java中的流分为输入流和输出流,分别用于读取和写入数据。流按照处理数据的不同类型,又可以...
JavaIO流详解归纳 Java 的核心库 java.io 提供了全面的 IO 接口,包括文件读写、标准设备输出等。Java 中 IO 是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入。在项目开发中,IO 是非常...
在Java编程语言中,IO(Input/Output)是处理数据输入和输出的关键部分。Java IO系统分为两大类:字节流和字符流。字节流主要用于处理任何类型的原始数据,如图片、音频文件或者二进制文件,而字符流则专注于处理...
IO流在Java中分为两大类:输入流(Input Stream)和输出流(Output Stream)。输入流用于从源(如文件、网络连接等)读取数据,而输出流则用于向目的地(如磁盘、显示器、网络等)写入数据。根据处理的数据单位,流...
### Java IO流详解 #### 一、Input和Output Stream概览 在Java中,输入输出流(简称IO流)是用来处理文件读写的核心技术之一。它主要包括两类:以字节为导向的流和以字符为导向的流。 ##### 1.1 以字节为导向的流...
- **定义**:在Java中,IO流(Input/Output Streams)是用来处理输入输出的基本工具。流是一种有序的数据集合,通常涉及从源到目的地的数据传输过程。源可以是文件、键盘输入、网络连接等;而目的地则可能是屏幕显示...
总结,Java中的FileBuffered的InputOutputStream结合了基础的文件流和缓冲技术,为开发者提供了高效、易用的文件读写方案。理解并熟练掌握这些基本操作,对于编写高性能的Java IO程序至关重要。
在Java中,流(Stream)是IO系统的核心概念,它们可以被视为数据的序列,既可以读取(Input Stream)也可以写入(Output Stream)。 1. 输入流(Input Stream) - InputStream:所有输入流的基类,用于读取原始...
Java 的 IO 体系分 Input/Output 和 Reader/Writer 两类,区别在于 Reader/Writer 在读写文本时能自动转换内码。基本上,所有的 IO 类都是配对的,即有 XxxInput 就有一个对应的 XxxOutput。 Java 的输入/输出...
在Java编程语言中,IO(Input/Output)流是一组用于处理输入输出操作的类和接口,它们构成了Java IO API。这些类使得程序能够读取数据(输入)、写入数据(输出),并进行文件和网络之间的数据传输。本文将深入探讨...
IO流可以分为两大部分:输入流(Input Stream)和输出流(Output Stream)。它们分别用于从源获取数据和向目标发送数据。Java中的IO流按照数据类型又可划分为字节流(Byte Stream)和字符流(Character Stream),...
流可以分为两种基本类型:输入流(Input Stream)和输出流(Output Stream)。输入流用于从数据源读取数据,而输出流则用于向目标位置写入数据。 Java的I/O类库位于`java.io`包中,提供了一系列的类和接口,涵盖了...
Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的重要部分,涉及文件、网络、内存等数据传输。本文将深入探讨Java IO的基本概念、分类、选择流的策略以及常用的流类型。 首先,File类是Java IO的...
这两类流又各自分为输入流(Input Stream)和输出流(Output Stream),分别用于数据的读取和写入。 1. 字节流: - InputStream和OutputStream是所有字节输入流和输出流的基类。例如,FileInputStream和...
Java IO 流是 Java 语言中最重要的 Input/Output 机制之一,通过流我们可以自由地控制文件、内存、IO 设备等数据的流向。流机制是 Java 及 C++中的一个重要机制。 一、什么是流? 流是字节序列的抽象概念,能被...
Java IO(Input/Output)是Java编程语言中用于处理输入和输出操作的重要组成部分。它提供了丰富的类库,允许程序员在程序中实现数据的读写,无论是从硬盘、网络、内存,还是其他I/O设备。Java IO的核心在于其流的...
IO(Input/Output)流是Java提供的一种处理输入输出数据的方式,包括读取和写入文件。本篇文章将详细介绍如何使用Java的IO流来实现文件的复制。 首先,我们需要了解Java中的IO流体系。Java的IO库基于流的概念,流...
在Java中,IO流分为两大类:输入流(Input Stream)和输出流(Output Stream),它们分别用于数据的读取和写入。 **File类** File类是Java中用于处理文件和目录的基础类。它提供了平台无关的方法来创建、删除、...