黑马程序员_IO流知识总结



------------------------------------------------android培训java培训期待与您交流!-----------------------------------------------

流的总体框架

❶字符流的抽象基类:
Reader其子类有(
BufferedReader,CharArrayReader,FilterReader,InputStreamReader,PipedReader,StringReader),

Writer其子类有(BufferedWriter,CharArrayWriter,FilterWriter,OutputStreamWriter,PipedWriter,PrintWriter,StringWriter

❷字节流的抽象基类:

InputStream 其常见子类有(ByteArrayInputStream,FileInputStreamObjectInputStream,PipedInputStream

,SequenceInputStream,StringBufferInputStream

OutputStream其常见子类有(ByteArrayOutputStream,FileOutputStream,FilterOutputStream,

ObjectOutputStream,OutputStream,PipedOutputStream

常见字符流:

❶为什么要有字符流:字符流对象里面揉合了字符码表可以方便我们操作数据

❷字符流读写文件的类FileReader和FileWriter

①FileReader,FileWriter涉及编码转换 (采用操作系统默认编码 )

②flush()方法:刷新流对象中的缓冲中的数据,将数据刷到目的地中。

③close和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭

❸转换流:InputStreamReader和OutputStreamWriter

①字节流转换为字符流然后再加缓冲

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

②字符流转换为字节流然后再加缓冲
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

③这两个流构造方法都可以指定特定的字符编码

❹为了提高字符流的操作效率而出现BufferedReader,BufferedWriter

①BufferedReader中readLine方法特点:该方法一次读一行方便于对文本数据的获取,当返回null时,表示读到文件末尾;该方法返回的时候只返回回车符之前的数据内容,并不返回回车符

②BufferedWriter提供了一个newLine()方法里面是跨平台的换行符

③调用缓冲区的关闭,也就关闭缓冲区了的流对象

④自定义的MyBufferedReader:

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')//如果是r那么结束本次循环
				continue;
			if(ch=='\n')//如果是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();
	}

⑤由自定义BufferedReader联想到装饰设计模式:

装饰类的自我理解:自定义的类,将已有对象通过构造方法传入,基于被装饰已有的功能,并提供其方法的加强功能

装饰模式和继承的区别:装饰模式比继承要灵活,避免了继承体系臃肿,降低了类与类之间的关系,装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能,装饰类和被装饰类通常是都属于一个体系中的。

常见字节流:

❶以字节流方式读写文件的流FileInputStream和FileOutputStream

❷为了提高字节流的操作效率而出现BufferedInputStream和BufferedOutputStream

❸操作基本数据类型的数据的流对象DataInputStream与DataOutputStream

DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(234);//指定特定的数据类型
dos.writeBoolean(true);
dos.writeDouble(9887.543);
dos.close();

❹ObjectInputStream和ObjectOutputStream

这两种流出现的目的是把内存中的对象写入文件,之后在把文件中的对象重新读出来

ObjectInputStream与ObjectOutputStream类所读写的对象必须实现Serializable接口

对象中的transient和static类型成员变量不会被读取和写入

其他常见流

❶PipedOutputStream和PipedInputStream对象

PipedInputStream类与PipedOutputStream类用于在应用程序中创建管道通信.一个PipedInputStream实例对象必须和一个PipedOutputStream实例对象进行连接而产生一个通信管道.PipedOutputStream可以向管道中写入数据,PipedIntputStream可以读取PipedOutputStream向管道中写入的数据.这两个类主要用来完成线程之间的通信.一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据.

import java.io.*;

class Read implements Runnable
{
	private PipedInputStream in;
	Read(PipedInputStream in)
	{
		this.in = in;
	}
	public void run()
	{
		try
		{
			byte[] buf = new byte[1024];
			System.out.println("读取前。。没有数据阻塞");
			int len = in.read(buf);
			System.out.println("读到数据。。阻塞结束");
			String s= new String(buf,0,len);
			System.out.println(s);
			in.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道读取流失败");
		}
	}
}

class Write implements Runnable
{
	private PipedOutputStream out;
	Write(PipedOutputStream out)
	{
		this.out = out;
	}
	public void run()
	{
		try
		{
			System.out.println("开始写入数据,等待6秒后。");
			Thread.sleep(6000);
			out.write("piped lai la".getBytes());
			out.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException("管道输出流失败");
		}
	}
}

class  PipedStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream();
		in.connect(out);
		Read r = new Read(in);
		Write w = new Write(out);
		new Thread(r).start();
		new Thread(w).start();
	}
}

❷RandomAccessFile

该类不是算是IO体系中子类,而是直接继承自Object,但是它是IO包中成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置,其实完成读写的原理就是内部封装了字节输入流和输出流。通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等,如果模式为只读 r,不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常,如果模式rw,操作的文件不存在,会自动创建,如果存则不会覆盖。

❸暂存在内存的流
操作字节数组
  ByteArrayInputStream 与ByteArrayOutputStream

class ByteArrayStream 
{
	public static void main(String[] args) 
	{
		//数据源。
		ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());
		//数据目的
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		int by = 0;
		while((by=bis.read())!=-1)
		{
			bos.write(by);
		}
		System.out.println(bos.size());
		System.out.println(bos.toString());
	//	bos.writeTo(new FileOutputStream("a.txt"));
	}
}

操作字符数组
 CharArrayWrite与CharArrayReader
操作字符串
 StringReader 与StringWriter

❹SequenceInputStream

SequenceInputStream会将与之相连接的流集组合成一个输入流并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末 尾为止。 合并流的作用是将多个源合并合一个源

Vector<FileInputStream> v = new Vector<FileInputStream>();

v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));

Enumeration<FileInputStream> en = v.elements();

SequenceInputStream sis = new SequenceInputStream(en);

一道关于输入输出流的需求分析

需求:将键盘录入的数据保存到一个文件中。
源: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,而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");

File类常见方法:

❶创建
 boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。

 和输出流不一样,输出流对象一建立创建文件,而且文件已经存在会覆盖。

boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
❷删除
 boolean delete():删除失败返回false,如果文件正在被使用,则删除不了返回falsel。
 void deleteOnExit();在程序退出时删除指定文件。
❸判断
 boolean exists() :文件是否存在.
 isFile():
 isDirectory();
 isHidden();
 isAbsolute();

❹获取信息
 getName():
 getPath():
 getParent():该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。如果相对路径中有上一层目录那么该目录就是返回结果。

getAbsolutePath()
 long lastModified()
 long length()
f1.renameTo(f2):如果f1和f2在同一目录那么就改变名字,否则把f2文件移动到f1处去
❺列表
File.listRoots()获取出系统盘符

字节流的读一个字节的read方法为什么返回值类型不是byte,而是int

因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1,那么就会数据还没有读完,就结束的情况,
因为我们判断读取结束是通过结尾标记-1来确定的,所以为了避免这种情况将读到的字节进行int类型的提升,
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值

UTF-8解码规律
单个字节第一位数为0
两个字节的话第一个字节大头为110,第二个字节为10
三个字节的话第一个字节以1110打头,第二个和第三个字节都以10打头


而联通这个字符以GBK编码的时候编出来的码符合UTF-8的规律所以就出现乱码的情况
byte[] b1 = s.getBytes("GBK");
System.out.println(Arrays.toString(b1));
String s1 = new String(b1,"utf-8");
System.out.println("s1="+s1);
对s1进行iso8859-1编码。
byte[] b2 = s1.getBytes("utf-8");
System.out.println(Arrays.toString(b2));
String s2 = new String(b2,"gbk");

列举出文件中以bmp结尾的文件
		File dir = new File("d:\\java1223\\day18");
		String[] arr = dir.list(new FilenameFilter()
		{
			public boolean accept(File dir,String name)
			{
				return name.endsWith(".bmp");

			}
		});
		for(String name : arr)
		{
			System.out.println(name);
		}


----------------------------------------- android培训java培训、java学习型技术博客、期待与您交流! --------------------------


详情请查看:http://edu.csdn.net/heima







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值