Java中的IO框架流三
1 IO(三)No20
【
Properties属性集,主要用于操作配置属性,
是以键值对的方式来保存属性,并且都是String类型
继承自Hashtable类,所以是一个Map集合,具有Map接口中的所有方法,但是在保存和读取数据的时候不建议使用put和get方法,因为有可能会出现异常,建议使用Properties中特有的方法进行数据的存储
常用方法:
1、添加、获取
setProperty(String key,String value):添加键值对
getProperty(String key):通过键获取值《getProperty(Stringkey)
getProperty(Stringkey,StringdefaultValue)》如果键不存在返回默认值
2、保存、加载(配合IO流使用)
store():将数据通过输出流写到指定文件中
《store(OutputStreamout,Stringcomments)
store(Writerwriter,Stringcomments)参数二:代表注释》
load():通过输入流读取指定文件中的数据
《load(InputStreaminStream)load(Readerreader)》
3、遍历数据
list():将集合中的所有数据输出到指定的流中(一般用于调试)
《list(PrintStreamout)list(PrintWriterout)》
stringPropertyNames():获取集合中键的集合(键的类型是String类型)
】
【
publicclass Demo {
public static void main(String[] args)throws IOException {
Properties prop = newProperties();
/*
* Properties类继承于Hashtable类,所以可以使用put方法添加键值对,
* 但是Properties类中的数据要求应该都是String类型,使用put方法返回可能会出问题
* 官方建议使用setProperty()方法添加键值对
*/
// prop.put("textsize",18);
// prop.get("textsize");
//保存值
prop.setProperty("textsize","18");
prop.setProperty("textcolor","red");
//获取值
String size =prop.getProperty("textsize");
String color=prop.getProperty("textcolor");
System.out.println(size);
System.out.println(color);
//将属性保存到磁盘上
//Properties的作用是将数据持久化保存,实际上就是将数据保存在磁盘上
// prop.save(out, comments);
FileOutputStream fos = new FileOutputStream("prop.properties");
prop.store(fos, "注释");
//从磁盘上读取属性数据
Properties prop2 = newProperties();
FileInputStream fis = newFileInputStream("prop.properties");
prop2.load(fis);
System.out.println(prop2);
//遍历Properties集合(是Map集合)
//list方法一般是用于调试用的
prop2.list(System.out);
//传统的遍历Map集合的方式,通过keyset方法获取键的集合,但是元素都是Object类型
// prop2.keySet();
Set keyset = prop2.stringPropertyNames();
for (String key : keyset) {
String value =prop2.getProperty(key);
System.out.println(key+"..........."+value);
}
}
}
实例:写一个程序,要求用户只能打开5次,在第6次打开的时候就抛出异常提示“打开失败”
publicclass Ex {
public static void main(String[] args){
System.out.println("程序开启.......");
//检测使用的次数
check();
System.out.println("程序正常运行.......");
System.out.println("程序结束.......");
}
private static void check() {
/*
* 思路:记录用户打开程序的次数,每次打开的时候都记一次,将次数保存在配置文件中,
* 每次打开的时候读取上一次记录的次数,如果超出上限,就提示用户
*/
//
FileInputStream fis =null;
FileOutputStream fos = null;
try {
Properties prop =new Properties();
File file = newFile("prop_ex.properties");
//要保证文件存在
if(!file.exists()){
file.createNewFile();
}
fis = new FileInputStream(file);
//从文件中加载数据到Properties集合中
prop.load(fis);
//通过键获取值,如果键值对不存在,就返回指定的默认值
int count=Integer.parseInt(prop.getProperty("count","0"));
count ++;
//判断打开的次数是否已经超过了上限
if(count>5){
throw newRuntimeException("适用用次数已经超过5次上限,请续费!.......");
}else{
//如果没有超过
fos = newFileOutputStream(file);
prop.setProperty("count",String.valueOf(count));
prop.store(fos,"open count");
}
} catch (IOException e) {
// TODO: handleexception
}finally{
if(fos != null){
try {
fos.close();
fos= null;
} catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
fis= null;
} catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
】
【
数组流
】
【
byte[] bytes ={97,98,99,100,101};//源字节数组
ByteArrayInputStream bais =//在源数组上创建一个内存输入流
newByteArrayInputStream(bytes);
int n=0;
byte[] buf = new byte[4];
//读4个字节放到缓冲buf中,返回有效读取数
while((n=bais.read(buf))!=-1){
for(int i=0;i
System.out.println(buf[i]); //打印
}
}
}
//不需要关闭
//创建一个内存输出流,可以通过它向内置的字节数组中写字节
ByteArrayOutputStream baos=new ByteArrayOutputStream();
baos.write(65);//往内置字节数组中写一个字节
baos.write(66);
baos.write(67);
//从中拿出之前写的字节生成的数组
byte[] array =baos.toByteArray();
for(byte b : array){//遍历打印,用于验证
System.out.println(b);
}
//源文件流
FileInputStream fis = newFileInputStream("g:/output.txt");
//目标内存输出流
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int n=0;
byte[] buf = new byte[4];//缓冲数组创建
//每次从文件读4个字节方法缓冲中,有效字节数赋给n,和-1比较判断是否读完
while((n=fis.read(buf))!=-1){
baos.write(buf,0,n); //没有读完就将有效字节写到内存输出流
}
fis.close();//需要关闭
// baos.close();//不需要关闭
byte[]array=baos.toByteArray(); //获取字节数组
for (byte b : array) {//遍历,验证
System.out.println((char)b);
}
FileInputStream fis =new FileInputStream(
"g:/MySQL-connector-Java-5.1.7-bin.jar");
ByteArrayOutputStream baos =new ByteArrayOutputStream();
int n = 0;
byte[] buf = newbyte[1024];//缓冲
while ((n = fis.read(buf)) !=-1) {//从文件读1024字节,有效字节数赋值给n,和-1比较判断是否结束
baos.write(buf, 0,n);//把有效字节写到内存输出流
}
fis.close();
byte[] array =baos.toByteArray(); //用写进的字节生成数组
//准备从这个字节数组中读字节
ByteArrayInputStream bais =new ByteArrayInputStream(array);
FileOutputStream fos = newFileOutputStream("g:/copy.jar");
while ((n = bais.read(buf))!= -1) {//从数组读1024字节,有效字节数赋给n,和-1比较
fos.write(buf, 0,n); //把有效字节写到copy.jar
}
fos.close();
FileInputStream fis = newFileInputStream("g:/mysql-connector-java-5.1.7-bin.jar");
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int n= 0;
byte[] buf = new byte[1024];
while((n=fis.read(buf))!=-1){//读源文件只进行一次
baos.write(buf,0,n);
}
fis.close();
byte[] array =baos.toByteArray();
//把文件放到内存中,这些动作不重复进行,这些动作包含了对磁盘的操作
//把内存中的内容拷贝到文件,重复进行
for(int i=1;i<=100;i++){
ByteArrayInputStreambais = new ByteArrayInputStream(array);
FileOutputStream fos= new FileOutputStream("g:/100/"+i+".jar");
//这里也要读100次,但是每次都是读内存数组,所以效率大大提高
while((n=bais.read(buf))!=-1){
fos.write(buf,0,n);
}
fos.close();
}
】
内存流(字节数组)节点流、字节流
ByteArrayInputStream
ByteArrayOutputStream
构造方法:
ByteArrayInputStream(byte[]bytes)创建一个内存流,可以从参数字节数组中读取字节
常用方法:
int read()
int read(byte[] buf)
不需要调用close()方法
构造方法:
ByteArrayOutputStream()创建一个内存输出流,无参数,可以往内置的字节数组中写字节
常用方法:
write(int b)
write(byte[] buf,intoff,int len)
不需要调用close()方法
toByteArray()获得字节数组(之前写到其中的字节组成的字节数组)
在文件小且不经常变更的情况下,可以用内存流先进行缓存,避免反复磁盘操作
实例:
【
public static void main(String[] args)throws IOException {
//字节数组输出流
//是以数组作为数据源,将数据写到数组中
//当数组输出流被创建的时候内部会自动创建一个数组
ByteArrayOutputStream baso =new ByteArrayOutputStream();
//将数据写出到数组流内部的数组(内存)中
baso.write("强风125".getBytes());
//取出流中的字节数组
byte[]buf =baso.toByteArray();
System.out.println(newString(buf));
//在这里因为操作的是内存,所以不需要释放存放
// baso.close();
//使用场景:从网上下载图片并显示在界面上
//从内存数组中去数据
ByteArrayInputStream bais =new ByteArrayInputStream(buf);
byte[] cubf = new byte[1024];
bais.read(cubf);
System.out.println(newString(cubf));
//如果一个数组中的数据比较多,需要分批读取,那么使用数组流能简化我们的代码
//比如:现在有一个字节数组大小为1000,每次读取300个字节,自到将数据读完
}
】
对象流是一种处理流、字节流
【
对象流
ObjectInputStream
readObject()
ObjectOutputStream
writeObject()
注意事项:
1、被对象流操作的对象必须先进行序列化(实现Serializable接口)
1)需要在类中定义一个静态常量(序列值,static final longserialVersionUID)
2)在数据序列化的时候不会对静态字段(static )和瞬态字段(transient)进行序列化
2、一个文件只能存储一个对象
】
实例:
【
publicclass Demo {
public static void main(String[] args)throws IOException, ClassNotFoundException {
// test1();
// writeObj();
readObj();
}
private static void readObj() throwsIOException, ClassNotFoundException {
FileInputStream fis = newFileInputStream("objdemo.object");
ObjectInputStream ois = new ObjectInputStream(fis);
//内部自动进行了反序列化
Student stu =(Student)ois.readObject();
System.out.println(stu);
}
private static void writeObj() throwsIOException {
Student stu = new Student("小强", "男", 18);
//对象流,用于直接操作对象
FileOutputStream fos = newFileOutputStream("objdemo.object");
ObjectOutputStream oos = newObjectOutputStream(fos);
//将对象写出到指定设备
//注意:对象流操作的对象必须进行序列化
//序列化:只需要实现Serializable
oos.writeObject(stu);
oos.close();
}
private static void test1() throwsIOException, FileNotFoundException {
Student stu = newStudent("小强","男", 18);
FileWriter fw = newFileWriter("object.txt");
fw.write(stu.name+"|");
fw.write(stu.gender+"|");
fw.write(stu.age +"");
fw.close();
//从磁盘上读取对象的数据并生成对象
BufferedReader br = new BufferedReader(newFileReader("object.txt"));
String line = br.readLine();
String[] strs = line.split("\\|");
String name = strs[0];
String gender = strs[1];
int age = Integer.parseInt(strs[2]);
Student stu2 = new Student(name, gender, age);
System.out.println(stu2);
}
}
classStudent implements Serializable/*标记接口*/{
/**
* 序列值,用于标记类的唯一性
* 如果没有指定序列值,那么编译器会自动根据类中的成员来自动生成一个序列值
* 建议:在序列化的时候最好要写上序列值
*/
private static final long serialVersionUID= 10000L;
/**
* static 修饰的类成员不会被序列化
*/
String name;
String gender;
transient int age; //瞬态的(不会进行序列化)
public Student(String name, Stringgender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
@Override
public String toString() {
return "Student[name=" + name + ", gender=" + gender + ", age=" + age
+"]";
}
}
】
【
//文件的文件输出流
FileOutputStream fos = newFileOutputStream("g:/obj");
//用对象输出流去处理、装饰fos文件输出流
ObjectOutputStream oos = newObjectOutputStream(fos);
oos.writeObject("1000phone");//写一个字符串对象到流中
oos.close();
//对象流装饰文件流
ObjectOutputStream oos = newObjectOutputStream(
newFileOutputStream("g:/elephant"));
//初始化对象
Elephant mike = newElephant("Mike", 1000);
oos.writeObject(mike); //把大象塞进去
oos.close();
】
构造方法:ObjectOutputStream(OutputStream os)参数是它要处理、装饰的流,增加了写对象的功能
writeObject(Objectobj)
【
ObjectInputStream ois= //用对象流装饰文件流
newObjectInputStream(new FileInputStream("g:/obj"));
String str =(String)ois.readObject(); //读一个对象
System.out.println("从obj文件中拿出来了:"+str);
ois.close();
ObjectInputStream ois= new ObjectInputStream(
newFileInputStream("g:/elephant"));
//把大象从流中拖出来,拿到的是Object类型,强转为大象类型
Elephant e =(Elephant)ois.readObject();
System.out.println(e.getName()+" "+e.getWeight());
ois.close();
】
构造方法:ObjectInputStream(InputStream is)参数是它要处理、装饰的流,增加了读对象的功能
Object readObject()
对象流读写,写的和读的类型一定要一致。
对象流读写的对象必须要可序列化,必须实现Serializable接口,这个接口无抽象方法。
用途:信息的存储、信息在网络上的传递、信息在组件间传递
【
PrintWriterpw = new PrintWriter(
newFileOutputStream("g:/answer.txt",true));
//由于构造方法第二个参数为true ,println会自动刷缓存
pw.println("1000phone");//打印1000phone到文件中并换行
pw.println("Android");//打印android到文件中并换行
pw.println("java");//打印java到文件中并换行
pw.close();
】
PrintWriter输出流、字符流、处理流
构造方法:
PrintWriter(OutputStreamos,boolean autoFlush)第一个参数是所要装饰的字节输出流,第二个参数是表示是否自动刷缓存
PrintWriter(Writerwriter,boolean autoFlush)装饰字符流
PrintWriter(Stringpath,String csn)在以第一个参数为路径的文件上建立打印流,字符集由第二个参数指定
println()打印并且换行,在autoFlush为true时,会自动刷缓存
PrintStream用法和PrintWriter差不多,构造方法少一点
实例
【
publicstatic void main(String[] args) throws IOException {
// 打印流(只有输出流)PrintStream(字节打印流) PrintWriter (字符打印流)
// PrintStream ps = new PrintStream(newFileOutputStream("print.txt"));
PrintStream ps = newPrintStream("print.txt");
/*ps.print(true);
ps.print("中");
ps.print("f");*/
ps.print(18); //编码
ps.write(97); //字面值
ps.close();
}
】
【
DataOutputStream dos= //用数据流装饰文件流
newDataOutputStream(new FileOutputStream("g:/answer.txt"));
dos.writeInt(101);//向数据流中写100
dos.writeInt(100);
dos.writeInt(70);
dos.writeInt(66);
dos.close();//关闭处理会自动关闭所装饰的流
DataInputStream dis =new DataInputStream(
new FileInputStream("g:/answer.txt"));
int a=dis.readInt();//用数据流装饰文件流
System.out.println(a);
System.out.println(dis.readInt());//打印读出的int数据
System.out.println(dis.readInt());
System.out.println(dis.readInt());
dis.close();
】
DataOutputStream数据输出流,字节流、处理流
DataOutputStream(OutputStreamos)构造方法参数为它所装饰的字节输出流,添加了写基本类型数据的功能
writeInt(int i)
writeXXX(xxx i)
DataInputStream数据输入流
DataInputStream(InputStreamis)构造方法参数为它所装饰的字节输入流,添加了读基本数据类型的功能
int readInt()
xxx readXXX()
实例:
【
publicstatic void main(String[] args) throws IOException {
//数据流(过滤流)
FileOutputStream fos = newFileOutputStream("data.txt");
DataOutputStream oos = newDataOutputStream(fos);
oos.writeByte(100);
oos.writeChar('中');
oos.writeShort(1000);
oos.writeInt(1022);
oos.writeLong(12025);
oos.writeFloat(12.2f);
oos.writeDouble(15.4524);
oos.writeBoolean(true);
oos.close();
//读取数据
FileInputStream fis = new FileInputStream("data.txt");
DataInputStream dis = new DataInputStream(fis);
System.out.println(dis.readByte());
System.out.println(dis.readChar());
System.out.println(dis.readShort());
System.out.println(dis.readInt());
System.out.println(dis.readLong());
System.out.println(dis.readFloat());
System.out.println(dis.readDouble());
dis.close();
}
】
装饰模式:
1、把被装饰者通过构造方法传入装饰者
2、被装饰者和装饰者具有相同的方法(方法名、返回、参数)、具有相同的接口或父类
3、被装饰者以属性的形式存在于装饰者中
【
RandomAccessFile raf= new RandomAccessFile("g:/answer.txt", "rw");
raf.write(65);//A|
raf.write(66);//AB|
raf.seek(0);//将游标一下子跳到第一个位置|AB
raf.write(67);
raf.write(68);
raf.close();
RandomAccessFile raf=new RandomAccessFile("g:/answer.txt", "r");
System.out.println(raf.read());
System.out.println(raf.read());
raf.seek(0); //游标放到最前
System.out.println(raf.read());
System.out.println(raf.read());
raf.close();
】
RandomAccessFile随机访问文件,不是InputStream、OutputStream、Reader、Writer中的任一个子类
RandomAcceessFile(Stringpath,String mode)
构造方法第一个参数表示文件路径,第二个参数打开模式,如果是"rw"表示可读可写,如果是"r"表示只读
seek(int pos)定位,游标可以随便向前向后跳,只要不超出范围(Stream、Reader、Writer只能往后不能往前)