1.处理设备之间的数据传输
2.JAVA对数据的操作通过流的方式
3. JAVA操作流的对象都在IO包中
4.按操作数据分为字节流和字符流(字节流是byte,用于传输数据,字符流是word,用于传输文本,字符流底层封装了字节流,并处理了字节数据,将之每两个用字符集进行一次处理)
5.按流向分为输入流和输出流
->以此为基础的四大IO流抽象基类(ctor属性为protected,不可直接创建对象,必须使用其具体子类创建对象):
Reader
Writer
InputStream
OutputStream
一、常用字符流类型
Writer
(一)Writer使用步骤(未处理IO异常)
import java.io.*;
FileWriter fout=new FileWriter(“test.txt”);
char[] cbuf=”abcde”.getBytes();
String str=”fghij”;
fout.write(97);
fout.write(‘a’);
fout.write(cbuf);
fout.write(cbuf,1,3);
fout.write(str);
fout.write(str,3,2);
fout.flush();
fout.close();
(二)处理IO异常
简单处理方法:抛出:invoker抛出,在函数上 throws IOException
具体处理步骤:
//创建对象(但不实例化)应当在try外进行。
try{
/*需要处理的代码,通常是涉及底层操作的操作,包括
1.实例化IO对象
2.进行读写操作
3.刷新流
4.关闭流*/
}catch(IOExcepiton e){
}finally{
/*必须进行的操作,比如关闭资源
因为finally是一定会进行的操作,而对象实例化可能失败,
所以关闭资源前应当判断下对象是否不为null*/
}
(三)方法
1.ctor
a.IO流没有空参数的ctor,必须给流一个输入或者输出的对象。
b.默认是覆盖文件(即将原文件内容清空再写入)。可以通过设置model为true变为append在末尾添加
2.write()//write不可在close()之后,关闭流后不可以再读写。
单个字符
1)int ch
字符数组
2)char[] buf
3)char[] buf,int offset,int length
字符串
4)String str
5)String str,int offset,int length
3.flush()//刷新流对象的缓冲中的数据,将之传输到dst中
4.close()//关闭流对象,但是会刷新一次,关闭后不可再进行write操作
Reader
(一)使用步骤(未处理IO异常/简单处理: invoker在函数上throws IOException)
//import
FileReader fin=new FileReader(“test.txt”);
int ch;
char[]buf=new char[1024];
int cnt=0;
ch=fin.read();
cnt=fin.read(buf);
String tmp=new String(buf,0,cnt);
fin.close();
(二)方法
1.ctor必须有src
2.read()//不可在close()之后
无参数返回单个字符,若读到文件尾则返回-1
ch=fin.read()
字符数组做参数返回读取字符个数
cnt=fin.read(buf);
3.close()
//简单文本文件复制
import java.io.*;
public class test2 {
public static void main(String[] args) throws IOException
{
FileReader fin=new FileReader("test2.txt");
FileWriter fout=new FileWriter("test2_copy.txt");
char[] cbuf=new char[1024];
int cnt=0;
while(-1!=(cnt=fin.read(cbuf)))
{
fout.write(cbuf, 0, cnt);
fout.flush();
}
fin.close();
fout.close();
}
}
缓冲区输入输出流(装饰类)
BufferedReader/BufferedWriter/BufferedInputStream/BufferedOutputStream
(一)概述
1.缓冲区概念/缓冲区原理:内部封装了数组
2.BUF提高了对数据的读写效率
3.BUF要结合流才可以使用。
4.增强了流的功能
(二)方法
1.ctor必须带参数,参数为流对象
2.read/write()
3.flush()//使用缓冲区必须记得刷新
4.close()//直接对缓冲区流对象使用close()即可,不需要再另外对缓冲区目标的流对象进行关闭操作
5.newLine()//换行可以使用newLine()替代换行符,此方法可以跨平台
6.readLine()//读取一行,当读到换行符时结束本次读取。返回的内容不包含换行符,如果需要必须手动添加。读到文件尾则返回null。
LineNumberReader/LineNumberInputStream
跟踪行号的缓冲字符输入流
1.readLine()
2.getLineNumber()//获取当前行号
3.setLineNumber()//设置当前行号
InputStreamReader/OutputStreamWriter
字符与字节间的转换流
输入转换流InputStreamReader System.in in是public staticfinal InputStream in,若想接收成字符需要转换为InputStreamReader,即
new InputStreamReader(System.in)
输出转换流OutputStreamWriter System.out out是PrintStream out,若想输出字符需要转换为OutputStreamWriter,即
new OutputStreamWriter(System.out)
还可以再用缓冲区的字符流对转换流继续进行装饰newBufferedReader(new InputStreamReader(System.in))
转换流可以设置字符集比如:InputStreamReader(InputStreamin,String charSet)
二、流操作的基本规律
1.明确源和目的
src:输入流InputStream Reader
dst:输出流OutputStream Writer
2.操作的数据是否为文本 是-字符流 否-字节流
3.要使用的具体对象 源设备内存 硬盘 键盘
修改默认输入输出设备:
System.setIn()/System.setOut()
应用:
1.将错误信息保存到文本文件中:
catch(Exception e){
System.setOut(new PrintStream(“a.txt”));
e.printStackTrace(System.out);
}
2.打印系统信息Properties类
Properties prop=new Properties();
System.setOut(new PrintStream(“a.txt”));
prop.list(System.out);//prop.list(new PrintStream(“b.txt”));
三、装饰类设计模式
当想对已有的对象进行功能增强时,可以定义一个类,将已有对象封装。基于已有功能,提供加强功能。
装饰类与继承:
装饰类是增强已有对象,具备的功能和已有相同,只是功能更强。
装饰类与被装饰类通常都属于一个体系。
降低了类与类之间的关系。
继承:自定义,覆盖父类方法。类之间联系紧密
四、字节流
输入流InputStream/输出流OutputStream
字节流的写入方法write()因为不需要处理字节数据转换为字符,不需要刷新,可以直接写入。
字节流的读取方法read()使用同字符流相同。
available()//获取可获取的字节的个数,适用于较小的字节流,在构建缓冲区时直接读取。
byte[] buf=newbyte[in.available()];
字节流缓冲区BufferedInputStream/BufferedOutputStream
模拟字节输入流缓冲区时需要注意有一个强转的问题。
在InputStream的read方法中,一次读取1byte ,8个字节,而java没有unsigned类型,所以如果字节数据内容为1xxxxxxx时,则会表示成负数。
为了避免这种情况发生,所以返回值为int,通过提升类型来扩展。得到返回值后将结果与0xff相与,则得到前24位为0后八位为所需的字节数据。避免了误认为负数的情况发生。
五、File类
(一)概述
1.描述文件/文件夹 将两者封装成对象。
2.方便对两者的属性信息进行操作
3.File对象可以作为参数传递给流的ctor
4.流只能操作数据,而操作数据所封装成的文件的信息,必须用File对象
5.File类是文件和目录路径名的抽象表示形式
(二)创建一个File对象
不论文件是否已存在都可以创建文件对象。
字段static String separator 目录分隔符:与系统有关的默认名称分隔符,被表示为一个字符串。”c:\\windows” 中“\\”就是分隔符。
0 Filef0=new File(“z.txt”);//使用相对路径直接在当前目录下创建文件对象
1 Filef1=new File(“c:\\abc\\a.txt”);//使用绝对路径创建文件对象
2 Filef2=new File(“c:\\abc”,”b.txt”);//两个参数,第一个是目录的路径,第二个是文件名
3 Filefdir=new File(“c:\\abc”); Filef3=new File(fdir,”c.txt”);//和上一个相比较,第一个参数是将字符串形式的目录路径封装成File对象
4 Filef4=new File(“c:”+File.separator+”abc”+File.separator+”d.txt”);//使用目录分隔符字段来创建对象
创建对象时使用的是相对/绝对路径,使用print方法打印出来的就是什么类型的路径
(三)方法
创建:boolean createNewFile()//1.若文件不存在则建立并返回true,已存在则返回false 2.throws IOException
static File createTempFile(Stringprefix,String suffix)//当前目录下用指定前后缀创建临时文件
boolean mkdir()//创建对象所示路径的目录。
boolean mkdirs()//如果目录尚不存在则创建。
删除:boolean delete()//删除File对象所代表的文件/目录,若是目录则必须目录下文件已清空,才可以删除
deleteOnExit()//通知JVM退出时删除文件不需要抛出异常,通常用于临时文件
判断:canExecute()//能否运行 canRead()//是否可读 canWrite()//是否可写
isDirectory()//是否为目录 isHidden()//是否为隐藏 isFile()//是否是文件 isAbsolute()//是否是绝对路径
boolean exists()//判断文件对象是否已存在
int compareTo(File pathName)// 按字母顺序比较两个抽象路径名。
查询:getName() getPath() getParent getAbsoluteFile getAbsolutePath
long lastModified()//返回最后修改时间 long length()//返回文件大小
重命名:boolean renameTo(Filedest)//若重命名已存在则false
文件列表:
1 静态方法:File[] files=File.listRoots()//返回系统所有盘符
2 String[]list()//列出当前目录下的文件以及目录,包含隐藏文件
3 String[]list(FileFilter filter)//FileFilter是一个接口,有抽象方法accept,使用过滤器需要自己实现接口:
f.list(newFileFilter(){
public booleanaccept(File dir,String name){
returnname.endWith(“.zip”);
}
});
4 File[] listFiles()//与2/3不同,返回的是File对象的数组
5 File[]listFiles(FileFilter filter)
六、打印输出流PrintStream/PrintWriter
有许多方便打印的功能:
1.println()方法,比起write方法不需要手动换行
2.boolean autoFlush 标志可以控制是否自动刷新
3.可以将各种数据类型按照原样打印
4.可以直接操作File对象
new PrintWriter(new File(“a.txt”));
创建PrintWriter的ctor可以使用四种参数:
1.直接操作File对象
2.String path
3.OutputStream
4.Writer
PrintWriter pout=new PrintWriter(newBufferedReader(new FileWriter(“b.txt”)),true);
===============================
150527 add:
PrintWriter和PrintStream不会抛出IO异常
PrintStream也可以直接用文件对象和文件路径字符串创建对象。
七、Properties类
Properties类-HashTable类的子类。
1有Map集合的特点,键值都是String
2是集合中和IO技术相结合的集合容器
3特点:可用于键值对形式的配置文件(java的配置文件的类型就是properties)
方法:
1 setProperty(<key>,<value>);//写入一个键值对
2 getProperty(<key>);//通过键名读取值
3 set<String>stringPropertyName()返回键名集合
4 voidload(Reader/InputStreamin)//从输入流读取所有键值对配置
5 voidstore(Writer/OutputStreamout,String comment)//向输出流输出所有键值对配置,使用完后需要flush()/close()
File f=new File(“config.ini”);
if(!f.exists()){f.createNewFile();}
Properties prop=new Properties();
prop.load(new FileInputStream(f));
int cnt=0;
String times=prop.getProperty(“times”);
if(null!=times){
<span style="white-space:pre"> </span>if(times>max){throw new RuntimeException(“max use times!”);}
cnt=Integer.praseInt(times);
}
prop.setProperty(“times”,++cnt);
prop.store(new FileOutputStream(f),null);
八、合并流
SequenceInputStream
使用步骤:
1.创建各个输入流
2.创建集合(Vector)按顺序存入各个输入流
3.转换成枚举类型
4.以枚举类型的对象为参数创建SequenceInputStream
5.创建输出流
6.将SequenceInputStream和输出流作为IO的输入输出进行使用
创建枚举类型的方法:
1.Vector
Vector<FileInputStream> v=newVector<FileInputStream>();
v.add(new FileInputStream(“a.txt”));
v.add(new FileInputStream(“b.txt”));
v.add(new FileInputStream(“c.txt”));
Enumeration<FileInputStream> e=v.elements();
SequenceInputStream sis=new SequenceInputStream(e);
2.匿名内部类
ArrayList<FileInputStream> al=newArrayList<FileInputStream>();
//al.add(…);
Iterator<FileInputStream>itor=al.iterator();
SequenceInputStream sis=newSequenceInputStream(new Enumeration<FileInputStream>(){
publicboolean hasMoreElements(){ return itor.hasNext();}
publicFileInputStream nextElement(){return itor.next();}
});
切割文件:使用缓冲区数组的大小作为切割的依据。
九、对象流
直接操作对象的流ObjectInputStream/ObjectOutputStream//将堆中的对象保存到硬盘
被操作的对象须要实现标记接口Serialize
方法:
1 ctor ObjectInputStream(InputStream in)//须要传入一个输入流作为参数
2 写入方法 write(…)//写入的是8bit的字节数据
writeInt(…)//写入的是一个32位的int值
writeObject()//写入一个对象
3 读取方法 read(…)//读取8bit的字节数据
readInt()//读取一个32位的int值
readObject()//读取一个对象//须处理一个ClassNotFoundException的异常
在使用writeObject时:
1.不修改类,只修改对象的属性值,则使用writeObject方法后将覆盖原对象
2.修改类后,使用writeObject会新写入一个对象,而不是覆盖原有对象
判断类是否被修改的依据:类的uid - 类的所有对象的序列号
如果想将修改后的类强制固定为原来的类。则可以通过自定义UID来实现:
任意修饰符 static finallongserialVersionUID=42L;
注意静态成员不会被序列化,若不想让某个非静态成员被序列化,则使用修饰符transient
若想从流中循环读取对象,不会正常结尾,须要通过捕获EOPException来结束循环
十、管道流
PipedInputStream/PipedOutputStream
注意连接的顺序,应当是输出作为参数传递给输入:
new PipedInputStream(PipedOutputStreampout)
通常通过多线程使用。数据由某个线程从PipedInputStream读取,并由其他线程写入到相应的PipedOutputStream中,
管道输入流包含一个buf,可以在buf的范围内将rw操作分开。
若向PipedInputStream提供输出的线程不再存在,则认为管道损坏。
线程启动的先后顺序不重要,因为read是阻塞式方法。
十一、基本数据和数组的流
操作基本数据类型的流DataInputStream/DataOutputStream
操作数组的流(内存)ByteArrayInputStream…
这类流的特点:
1不涉及底层操作
2不会抛出IO异常
3关闭无效
4关闭后仍可以使用
操作数组的流:
输入流需要一个字节数组作为输入的源ctorByteArrayInputStream(byte[] buf)
而输出流不需要,内部封装了一个可变长度的数组,其缓冲区会随着写入内容的增加而增大。
若想获取输出流缓冲区的内容不是使用flush()
而是使用toByteArray()/toString()来获取。
类似的流:CharArrayReader/CharArrayWriter
StringReader/StringWriter