黑马程序员技术交流社区
标题:
对io流的总结
[打印本页]
作者:
张玉建
时间:
2013-9-18 13:44
标题:
对io流的总结
我对io流的一些总结,
I/O流
流的概念:程序与数据来源之间的桥梁
流的分类:
按数据方向分:输入流和输出流
输入流: InputStream/Reader
输出流: OutputStream/Writer
按数据类型分:字节流和字符流
字节流:InputStream/OutputStream
字符流:Reader/Writer
按流的功能分:节点流和处理流
节点流用操作数据的来源。
处理流用来封装节点流,从而给节点流增加一个功能,不能独立存在,在关闭流时如果使用了处理流,只需关闭最外层的流就可以了。
区分节点流和处理流的小方法:
看构造器,节点流参数为数据来源,而处理流参数为其他流。
选择流的思路:
先考虑是输入流还是输出流,
输入流: InputStream/Reader
输出流: OutputStream/Writer
再考虑是字节流还是字符流,是否是纯文本
字节流:InputStream/OutputStream
字符流:Reader/Writer
最后考虑是节点流还是处理流。具体对象设备
源:内存,硬盘,键盘
目的:内存,硬盘,控制台。
读取文件的方式:
read()方法,一次读一个字符,而且自动向下读
在read()方法中可以一次读一个数据,
FileReader filereader = new FileReader("dome.txt");
FileWriter filewriter = new FileWriter("dome_copy.txt");
int ch =0;
while ((ch= filereader.read())!=-1)
{
filewriter.write((char)ch);
}
filereader.close();
filewriter.close();
也可以定义一个字符数组缓冲区,一次读取一行数据
FileReader filereader = new FileReader("dome.txt");
FileWriter filewriter = new FileWriter("dome_copy.txt");
char [] buf=new char[1024];
int ch =0;
while ((ch= filereader.read(buf))!=-1)
{
filewriter.write(char(buf,0,ch));
}
filereader.close();
filewriter.close();
读写流缓冲区: BufferedReader/BufferedWriter
以上两个都是过滤流,需要用其他的节点流来作参数构造对象。
BufferedReader的方法:readLine():String ,当他的返回值是null时,就表示读取完毕了。要注意,再写入时要注意写换行符,否则会出现阻塞。
BufferedWriter的方法:newLine() ,这个方法会写出一个换行符。
方法演示:
BufferedReader bufr = new BufferedReader(new FileReader("dome.java"));
BufferedWriter bufw= new BufferedWriter (new FileWriter("dome_copy.txt"));
String line= null;
while ((line= bufr.readLine())!=null)//readLine()只返回回车符之前的数据。
{
bufw.write(line);
bufw.newLine();//换行,为了实现跨平台性
}
bufr.close();
bufw.close();
对缓冲区技术:我们通过自己定义的缓存来解释内部原理
class myBufferedReader
{
private Reader r;
myBufferedReader(Reader r)
{
this.r= r;
}
//自定义一个ReadLine方法,
public String myReadLine()throws IOException
{
//定义一个临时容器,一个可变长度的字符串容器。
StringBuilder sb = new StringBuilder();
int ch = 0;
//调用reader中的read的方法,
while ((ch=r.read())!=-1 )
{
if(ch=='\r')//结束判断
continue;
if(ch=='\n')//结束判断,
return sb.toString();//结束判断成功,返回一行字符串,
else
sb.append((char)ch);//数据转成字符存入StringBuilder内
}
if((sb.length())!=0)//在最后结束判断不成功,对StringBuilder在次进行是否有内容判断
return sb.toString();
return null;
}
public void myClose()throws IOException//复写Reader中的close方法。
{
r.close();
}
——————这里自然就出现了一个装饰设计模式,在后面详细说明。
字符流:Reader和Writer所有字符流的父类型
Java技术使用Unicode来表示字符串和字符,而且提供16位版本的流,以便用类似的方法处理字符。
如果构造了一个连接到流的Reader和Writer,转换规则会在使用缺省平台所定义的字节编码和Unicode之间切换。
字节流: InputStream 和 OutputStream 是所有字节流的父类,
字节流使用来拷贝字节文件,例如:图片
它与字符流的用法基本相同,通过read()方法来读取数据,
字节流缓冲区 BufferedInputStream 和 BufferedOutputStream 应用中也较多应用read()方法,而不是readLine()方法。
BufferedInputStream bufin= new BufferedInputStream(new FileInputStream ("c:\\1.jpg"));//可以写成现对路径,也可是绝对路径,会抛出异常。
BufferedOutputStream bufout = new BufferedOutputStream (new FileOutputStream("c:\\2.bmp"));
int by=0;
while ((by= bufin.read())!=-1)
{
bufout.write(by);
}
bufin.close();
bufout.close();
第二种
byte [] buf= new byte[1024];//这里应该有一个功能,可以求出他的字节数多少,以便确定内存大小,以便减少浪费空间。
int by=0;
while ((by= bufin.read(buf))!=-1)
{
bufout.write(buf,o,by);
}
bufin.close();
bufout.close();
这里需要注意的是读取数据,和写入数据,是把数据读写入流中,必须通过flush()或close()来把数据刷到目的地中去,
键盘录入:1. BufferedReader buf = new BufferedReader( new InputStreamReader(System.in));//默认输入字符串,
2. Scanner ss= new Scanner(System.in)//可以输入任何数据类型。
一个用到正则表达式来解析基本数据类型和字符串类型的简单文本扫描器,多线程不安全
可以指定文件。输入流(字节流),源(读取源),字符串,扫描(常用)
扫描的基本数据类型有,byte,short,int,long,float,double,特别注意的是这样有String类型。
(a)基本方式:
Scanner sc = new Scanner(new File("myNumbers"));
while (sc.hasNextLong()) { //其中的hasNext()判断是否有所数据!
long aLong = sc.nextLong(); //next输出下一个数据,是什么数据类型就在next跟什么,例:nextLong,nextInt,
}
(b)自写例:
//定义存储数据数组,并定义范围,
int[] num=new int[5];
//读取键盘录入
Scanner s = new Scanner(System.in);
//遍历数组,把键盘录入数据存入数组。通过Scanner中的nextInt()方法
for (int x = 0;x < num.length; x++)
{
num[x]=s.nextInt(); //数据存入数组中
}
桥梁流:InputStreamReader和OutputStreamWriter(字节流转化成字符流的桥转换器)
这两个类不是用于直接输入输出的,他是将字节流转换成字符流的桥转换器,并可以指定编解码方式。
OutputStreamWriter outs= new OutputStreamWriter(new FileOutputStream("dome.txt"),"UTF-8");
打印流: 1.PrintStream 是为了其他的输出流提高了添加功能,为了打印各种数据值表现形式,提高了两个功能一个是不抛出异常,一个是自动刷新,
打印所有字符时自动根据平台上的编码表转成字节。字节打印流
这个不经让想到是:改变标准输入源输出目的,
1.file 对象 file;
2.字符串 String
3.字节输出流 OutputStream
System.setIn(new FileInputStream("dome.txt"));//改变输入源
System.setOut(new PrintStream("dome_copy.txt"));//改变目的
2.PrintWriter 字符打印流。
构造函数可以接受的参数类型
1.file 对象 file;
2.字符串 String
3.字节输出流 OutputStream
4.字符输出流 Writer
BufferedReader buf = new BufferedReader( new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new FileWriter("dome.txt"),true);//打印到一个文件中去,true表示可以自动刷新。
String line= null;
while ((line=out.readLine())!=null)
{
if ("over".equals(line))//定义一个结束标记
break;
out.println(line);//打印流中ln自动换行
//out.write(line);//newLine()是BufferedWriter中断方法。
//out.flush();
}
out.close();
buf.close();
作者:
张玉建
时间:
2013-9-18 13:46
管道流:连接输入流和输出流,在谁先执行方面用到多线程技术,一条线程负责管道输入流,一条线程负责管道输出流,有阻塞式方法,
PipedInputStream/PipedOutputStream
如何把输入流和输出流连接起来。
1.在构造方法 PipedInputStream(PipedOutputStream str)
2.建立对象后通过方法,connect();
传送输出流可以连接到传送输入流,以创建通信管道。传送输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。
注意:管道输出流和管道输入流需要对接。
class read implements Runnable
{
private PipedInputStream in;
read(PipedInputStream in)
{
this.in= in;
}
public void run()
{
try
{
byte buf = new byte[1024];
//1.没有数据阻塞
int len= in.read(buf);
//3.有数据,运行
String str = new String(buf,o,len);
System.out.println(str);
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
{ //2.写入数据
out.write("nihao ".getByte());
out.close();
}
catch (IOException e)
{
throw new RuntimeException("管道流写入失败");
}
}
}
class dome
{
public static void main(String[] args)
{
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();
}
}
数据流: DataInputStream 和 DataOutputStream 操作基本类
通过流来读写Java基本类,注意DataInputStream和DataOutputStream的方法是成对的。
支持直接输出输入各种数据类型。
一个读取数据,一个写入数据。
readInt(),readLong(),readShort(),readByte(),readBoolean(),readFloat(),readChar();readDobule(),写入数据。
注意:使用DataOutputStream/DataInputStream时,要注意写入顺序和读取顺序相同,否则会将没有分割写入的信息分割不正确而读取出错误的数据。
//readUTF()指定编码表写入读取数据,这样在构造时要传入流进来,
数组流: 键盘: System.in 硬盘: FileStream 内存:ArrayStream
控制台: System.out 硬盘: FileStream 内存: ArrayStream
内存就是数组流
ByteArrayInputStream ByteArrayOutputStream
//源
ByteArrayInputStream bis= new ByteArrayInputStream("abdcd".getBytes());
//目的
ByteArrayOutputStream bio= new ByteArrayOutputStream();
int by=0;
while ((by= bis.read())!=-1)
{
bio.write(by);
}
//不需要关,因为未调用底层资源。
System.out.println(bio.size());
Properties类:针对属性文件(*.properties,内容是name=value)进行操作,在java.util包下 //集合中涉及到io流对象。
load(InputStream inStream)
从输入流中读取属性列表(键和元素对)。
getProperty(String key)
用指定的键在此属性列表中搜索属性。设置使用次数。
配置系统文件,常见功能时
java编码方式:
编码:把字符转换成数字存储到计算机中,按ASCII将字母映射为整数。
解码:把数字从计算机转换成相应的字符的过程。
不同的国家有不同的编码,当编码方式和解码方式不统一时,产生乱码。
因为美国最早发展软件,所以每种的编码都向上兼容ASCII 所以英文没有乱码。
ASCII(英文) 1个字符占一个字节(所有的编码集都兼容ASCII)
ISO8859-1(拉丁文) 1个字符占一个字节
GB-2312/GBK 1个字符占两个字节(多用于中文)
Unicode 1个字符占两个字节(网络传输速度慢)
UTF-8 变长字节,对于英文一个字节,对于汉字两个或三个字节。
中文编码时出现乱码的情况:
用流操作文件。
网页(动态静态)。
网络传递消息。
解决乱码的方式:
String temp = 乱码的字符串
temp = new String(temp.getBytes("ISO8859-1") , "GBK")
将temp按照ISO8859-1的方式进行解码生成一个字节序列,然后在按照GBK的方式解码字节序列生成字符串。
作者:
张玉建
时间:
2013-9-18 13:46
File类:可表示文件或者目录
File下的方法是对磁盘上的文件进行磁盘操作,但是无法读写文件的内容。
构造器:
File(String pathname) //以文件的路径做参数
File类的方法:
创建:
boolean createNewFile()
创建一个新文件,如果文件已经存在,则不创建返回false,在输出流中,输出流对象一创建文件,如果文件已存在,会覆盖。
File createTempFile(String prefix, String suffix, File directory)
在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。会在前缀和后缀之间加一个随机数
boolean mkdir()
创建一个新目录(文件夹)
boolean mkdirs()
创建一个多级新目录(文件夹)
删除:
boolean delete()
删除文件,删除的是创建File对象时指定与之关联创建的那个文件。
void deleteOnExit()
在程序退出删除指定文件
判断:
boolean isDirectory()和boolean isFile()
判断究竟是目录还是文件。
boolean exists()
判断文件或文件夹是否存在。
获取:
String[] List()(重要)
返回当前File对象下所有显文件和目录名(相对路径)
File[] ListFiles()
返回当前File对象(必须是目录)下的所有File对象,可以用getName()来访问到文件名。
String getPath()
获得相对路径。
String getAbsolutePath()
获得文件的绝对路径
Long length()
获取文件路径的长度
String[]List(FilenameFilter filter)//文件过滤器,FilenameFilter是一个接口必须多态匿名内部类的形式复写方法。
注意:
File类的对象实施表示一个文件并不是真正的文件,只是一个代理而已,通过这个代理来操作文件
创建一个文件对象和创建一个文件在java中是两个不同的概念。前者是在虚拟机中创建了一个文件,但却并没有将它真正地创建到OS的文件系统中,随着虚拟机的关闭,这个创建的对象也就消失了。而创建一个文件才是在系统中真正地建立一个文件。
例如:
File f=new File(“11.txt”); //创建一个名为11.txt的文件对象
f.CreateNewFile(); //真正地创建文件
递归:函数自己调用自己,(要定义结束标记)(注意递归次数,递归方法在栈内不变开辟空间,注意内存溢出)
例如:
将一个指定目录下的java文件的绝对路径存储到一个文件中,建立一个java文件列表
思路:
1.对指定目录进行递归
2.获取递归过程中的java的文件
3.将路径存储到集合中来
4.将集合数据写入一个文件中去!
class dome
{
public static void main(String[] args)
{
File dir=new File("");
List<File> list= new ArrayList<File>();
fileToList(dir,list);
File file= new File(dir,"javalist.txt");
writeToFile(list,file.toString());
}
public static void fileToList(File dir,List<File> list)
{
File[] files = dir.listFiles();
for (File file :files)
{
if (file.isDirectory())
fileToList(dir,list);
else
{
if (file.getName().endsWith(".java"))
{
list.add(file);
}
}
}
}
public static void writeToFile(List<File> list,String javalistfile)
{
BufferedWriter bufw= null;
try
{
bufw = new BufferedWriter(new FileWriter(javalistfile));
for (File f: list )
{
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("数据写入文件中断");
}
finally
{
if(bufw!=null)
bufw.close();
}
}
}
RandomAccessFile:
允许随机访问文件,类支持直接输出输入各种数据类型。(自成一派)内部是一个byte数组。
原理:内部封装字节流,只能操作文件。
构造器:
RandomAccessFile(File file, String mode)
创建从中读取和向其中写入(可选)的随机存取文件流,该文件由 File 参数指定。
RandomAccessFile(String name, String mode)
创建从中读取和向其中写入(可选)的随机存取文件流,该文件具有指定名称。
mode( r:以只读方式打开 rw:可读可写,不存在则创建)
相关方法:
long getFilePointer()
返回文件指针的当前位置。
void seek(long pos)
设置文件指针到给定的绝对位置。
long length()
返回文件的长度。
对象流:ObjectInputStream和ObjectOutputStream(实现对象序列化)
对象流是过滤流,需要节点流作参数来构造对象,用于直接把对象写入文件和从文件中读取对象。
只有实现了Serializable接口的类型的对象才可以被读写,Serializable接口是个标记接口,其中没有定义方法。
对象会序列化成一个二进制代码,文件中保存对象的属性。
writeObject(o)、readObject()这两个是对象读写操作时用的方法。
Object o = new Object();
FileOutputStream fos=new FileOutputStream("Object.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(o);
oos.close();
FileInputStream fis =new FileInputStream(“Object.txt”);
ObjectInputStream ois =new ObjectInputStream(fis);
Object o = (Object)Ois.readObject();
ois.close();
一个类中有其他类型的对象,那么,这个类实现了Serializable接口,在对象序列化时,也同样要求这个类中属性都能够对象序列化(基本类型除外)。
public static final Long serialVersionUID = 42L; 指定ID
注意:
对于对象流的操作,在写对象时要一次写入完毕,如果使用追加模式写入,只会读取到上一次写入的对象,使用对象流写入时,会先写入一个头部,
然后写入数据,最后加上结束符号,如果使用追加方式写入的话,那就会在结束符号继续向下写入,但是在读取时只会读到结束符为止,以后再次写入的数据就会丢失。
异常处理:io流中有异常操作的特有方式。
以一个字节流复制文件为例!
class Test
{
public static void main(String[] args)
{
copy();
}
public static void copy()
{
//建立字节输出输入流缓冲区的引用;
//因为字节流缓冲区指向文件排出异常,需要try{}catch(){}处理,但为了缓存区作用在整个函数内,要在这建立并指向null;
BufferedInputStream bufi = null;
BufferedOutputStream bufo= null;
try
{
//缓冲区指向具体的对象文件,进行初始化
bufi= new BufferedInputStream(new FileInputStream("Test1.java"));
bufo= new BufferedOutputStream(new FileOutputStream("Test.txt"));
int in= 0;
while ((in=bufi.read())!=-1)//通过read方法把文件中的数据存入缓存区
{
bufo.write(in);//缓冲区内的数据写入文件
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
try
{
if (bufi!=null)//缓冲区建立初始化成功,关流
{
bufi.close();
}
}
catch (IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
try
{
if (bufo!=null)//缓冲区建立初始化成功,关流
{
bufo.close();
}
}
catch (IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
}
}
装饰设计模式:
对原有的功能的增强。
装饰类通过构造方法来接收被装饰的对象,并基于被装饰的对象提供更强的功能。
class myBufferedReader extends Reader//装饰Reader类
{
private Reader r;//构造方法
myBufferedReader( Reader r)
{
this.r= r;
}
//自定义一个ReadLine方法,
public String myReadLine()throws IOException
{
//定义一个临时容器,一个可变长度的字符串容器。
StringBuilder sb = new StringBuilder();
int ch = 0;
//调用reader中的read的方法,
while ((ch=r.read())!=-1 )
{
if(ch=='\r')//结束判断
continue;
if(ch=='\n')//结束判断,
return sb.toString();//结束判断成功,返回一行字符串,
else
sb.append((char)ch);//数据转成字符存入StringBuilder内
}
if((sb.length())!=0)//在最后结束判断不成功,对StringBuilder在次进行是否有内容判断
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//复写Reader中的close方法。
{
r.close();
}
}
装饰和继承的区别
装饰模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的耦合性,
装饰类因为增强已有对象,具备的功能和已有的相同功能,只不过提供了更强的功能,所以装饰类和被装饰类在一个体系中。
作者:
垂天云
时间:
2013-9-18 14:43
不错···顶一个!要是存成word附件就更好了!
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2