`
wangjie2013
  • 浏览: 168671 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java IO(Input Output)流总结

    博客分类:
  • JAVA
阅读更多

 

       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();
	}
}

 

 

 

 

 

 

 

1
4
分享到:
评论
1 楼 黑眼睛用来翻白眼 2013-08-01  
内容很不错,实用

相关推荐

    java_io详解

    关于java io技术的详解:IO(Input/Output)是计算机输出/输出的接口。Java的核心库java.io提供了全面的IO接口,包括:文件读写,标准设备输出等等。Java中IO是以流为基础进行输入输出的,所有数据被串行化写入输出...

    JAVA IO-(FileBuffered的InputOutputStream的基本操作)

    JAVA IO---(FileBuffered的InputOutputStream的基本操作)

    java中的IO操作总结(一)

    所谓IO,也就是Input与Output的缩写。在java中,IO涉及的范围比较大,这里主要讨论针对文件内容的读写 其他知识点将放置后续章节(我想,文章太长了,谁都没耐心翻到最后) 对于文件内容的操作主要分为两大类 分别...

    Java IO输入输出流

    ①,按照数据流向的不同分为:输入流(input)和输出流(output) –输入流:读取外部数据导入程序中(将持久化文件数据加载到内存) –输出流:将程序中的数据输出到磁盘或保存到磁盘(将内存中的数据持久化到磁盘...

    java中的Io(input与output)操作总结(四)

    前面已经把java io的主要操作讲完了,这一节我们来说说关于java io的其他内容:Serializable序列化/DataOutputStream和DataInputStream类/管道流等等,感兴趣的朋友可以了解下

    Java IO, NIO and NIO.2

    Input/output (I/O) is not a sexy subject, but it’s an important part of non-trivial applications. This book introduces you to most of Java’s I/O capabilities as of Java 8 update 51.

    完整版Java全套入门培训课件 Java基础 07-IO(共29页).pptx

    IO(Input Output)流 IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Java用于操作流的对象都在IO包中 流按操作数据分为两种:字节流与字符流 。 流按流向分为:输入流,输出流。

    java中的Io(input与output)操作总结(一)

    所谓IO,也就是Input与Output的缩写。在java中,IO涉及的范围比较大,这里主要讨论针对文件内容的读写,感兴趣的朋友可以了解下

    Java中的IO流

    一、 什么是IO流 一般情况下是按照当前程序使用的内存为参照物来考虑数据的走向问题。 以文件操作为例 从内存中保存数据到硬盘 output 从硬盘中读取数据到内存 input 看视频,缓冲 使用缓冲可以让用户体验提高,相对...

    Java数据流发送或接收数据高级IO流.ppt

    Java语言中数据流是发送或接收数据的管道...流的单向性:源端点和目的端点分别叫做input stream(输入流)和output stream(输出流)。 你可以从输入流读,但你不能对它写;同样,你可以向输出流写,但不能从输出流读。

    java中的Io(input与output)操作总结(三)

    一节我们来讲Scanner类和PrintWriter类的用法,感兴趣的朋友可以了解下

    java中的Io(input与output)操作总结(二)

    一节我们来讨论关于文件自身的操作包括:创建文件对象、创建和删除文件、文件的判断和测试、创建目录、获取文件信息、列出文件系统的根目录、列出目录下的所有文件,等等,感兴趣的朋友可以了解下

    Java IO, NIO and NIO.2 原版pdf by Friesen

    Input/output (I/O) is not a sexy subject, but it’s an important part of non-trivial applications. This book introduces you to most of Java’s I/O capabilities as of Java 8 update 51. Chapter 1 ...

    基础深化和提高-IO流技术学习大全

    Java的I/O流(Input/Output Stream)技术是Java编程中用于处理输入和输出的重要部分。它提供了一种灵活而统一的方式来与文件、网络连接、内存等进行数据交换。 I/O流主要分为两种类型:字节流和字符流。 字节流: ...

    Java中那些我不明白的小知识(六)–IO流(上)

    什么是IO流? I:input 输入流;read 读取数据 O:output 输出流;write 写入数据 一般情况下都是按照道歉程序使用的内存作为参照物来考虑数据的走向问题。 以文件操作为例: 从内存中保存数据到硬盘 output 从硬盘...

    Java高级程序设计:第9章-IO.pptx

    import java.io.*; public class BufferedWriterDemo { public static void main(String[] args) throws IOException{ FileWriter fw = new FileWriter("D:/a.txt"); BufferedWriter bw = new BufferedWr

    第14章 IO流1

    第14章 I/OI/O是输入/输出(Input/Output) 的缩写, I/O技术是非常实用的技术,如读/写文件,网络通讯等等。Java的IO支持通过java

    第13章 IO流1

    第13章 I/OI/O是输入/输出(Input/Output) 的缩写, I/O技术是非常实用的技术,如读/写文件,网络通讯等等。Java的IO支持通过java

    详细解读Java编程中的IO系统

    一. Input和Output  1. stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源。在Java的IO中,所有的stream(包括Input和Out stream)都包括两种类型:

    Java的输入与输出.ppt )

    流一般分为输入流(Input Stream)和输出流(Output Stream)两类。流和物理文件是有区别的,流是一个动态的概念。比如一个文件,当向其中写数据时,它就是一个输出流;当从其中读取数据时,它就是一个输入流。当然...

Global site tag (gtag.js) - Google Analytics