黑马程序员---IO流(2)

[align=center]-------[url]http://www.itheima.com[/url]java培训、android培训期待与您交流!------- [/align]

接着学习,,,,,
四、Properties
1、概述
Properties 是集合中和IO技术相结合的集合容器。
可用于键值对形式的配置文件
加载数据时,需要数据有固定格式,即键=值。
因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty 方法。
2、获取

import java.io.*;
import java.util.*;
class PropertiesDemo
{
public static void main(String[] args)
{
//创建对象
Properties prop = new Properties();

//设置属性,以键值的形式设置
prop.setProperty("wangwu","20");
prop.setProperty("lisi","30");

//以键值对的形式打印
System.out.println(prop);

//通过键取值
String value = prop.getProperty("wangwu");
System.out.println(value);

//先将map转化成set集合,再获取
Set<String> names = prop.stringPropertyNames();

for (String s : names )
{
//若只打印 s ,只是获取的是姓名
System.out.println(s+"----"+prop.getProperty(s));
}


}
}


3、
用于记录应用程序运行次数 如果使用次数已到,那么给出注册提示信息。那么就要用计数器记录运行的次数,但是在程序结束后,会在内存中消失,此时就需要将其存入到文件中,
所以需要一个配置文件,用于记录该软件使用的次数。下次程序启动时会先加载该计数器的值并加以后重新存储。Map+IO=Properties
import java.util.*;  
import java.io.*;

class RunCount
{
public static void main(String [] args)throws IOException
{
//创建一个Properties对象,集合和io的结合
Properties pop = new Properties();
//创建一个文件对象,用于操作文件
File file = new File("count.ini");
//先判断文件是否存在,如果不存在就创建一个
if(!file.exists())
file.createNewFile();

//创建读取流对象,读取文件中的信息
FileInputStream fis = new FileInputStream(file);
//将流中的文件信息存入集合中
pop.load(fis);

//定义计数器
int count = 0;
//获取文件中键所对应的值
String value = pop.getProperty("time");
//判断值是否为null,不为空就将值传给计数器
if(value!=null)
{
count = Integer.parseInt(value);
//判断计数器是否为到达次数
if(count>=5)
{
System.out.println("次数已到,请注册");
return ;
}
}
count++;
//将获得的键值设置后存入集合中
pop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(file);
pop.store(fos,"");
fos.close();
fis.close();
}
}


五、IO包中的其他流
1、打印流
打印流提供了打印方法,可将各种数据类型的数据都原样打印。

(1)字节打印流:PrintStream
构造函数可接收的参数类型:
File对象 File
字符串路径 String
字节输出流 OutputStream
(2)字符打印流:PrintWriter,这是web开发常用的。
构造函数可接收的参数类型:
File对象 File
字符串路径 String
字节输出流 OutputStream
字符输出流 Writer

import java.io.*;   
class PrintDemo
{
public static void main(String[] args) throws IOException
{
//键盘录入,创建读取流对象
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//使用打印流,将文件输出
//输出到屏幕
//PrintWriter(Writer out, boolean autoFlush) 这里的autoFlush设置为true
//则不用刷新缓冲区,
PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
out.println(line.toUpperCase());
//out.flush();
}
bufr.close();
out.close();
}
}

2、合并流
将多个输入流合并到一个流中。
import java.io.*;
class SequenceInputStreamDemo
{
public static void sequenceFile()throws IOException
{
//合并流对象
FileOutputStream fos = null;
SequenceInputStream sis = null;
try
{
//创建集合,存储多个文件
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int i=1;i<=3;i++)
{
al.add(new FileInputStream(i+".part"));
}
//匿名内部类访问局部变量要final
final Iterator<FileInputStream> it = al.iterator();
//创建Enumeration匿名对象
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
//合并流对象,将集合元素加入。
sis = new SequenceInputStream(en);
//创建写入流对象,FileOutputStream
fos = new FileOutputStream("7.bmp");
byte[] b = new byte[1024*1024];
int len = 0;
//循环,将数据写入流资源
while((len=sis.read(b))!=-1)
{
fos.write(b);
}

}
catch (IOException e)
{
throw new RuntimeException("文件操作失败");
}
//关闭流资源
finally
{
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("关闭流资源操作失败");
}
try
{
if(sis!=null)
sis.close();
}
catch (IOException e)
{
throw new RuntimeException("关闭流资源操作失败");
}
}
}
}

3、切割文件

import java.io.*;
class SplitFile
{
//切割流对象
public static void splitFile()throws IOException
{
//创建全局变量
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
//创建文件读取流
fis = new FileInputStream("0.bmp");
//创建数组
byte[] b = new byte[1024*1024];
int len = 0;
//计数器
int count = 1;
//循环写入数据
while((len=fis.read(b))!=-1)
{
//每次创建一个新写入流,写入后关闭流资源
fos = new FileOutputStream((count++)+".part");
fos.write(b,0,len);
fos.close();
}
}
catch (IOException e)
{
throw new RuntimeException("关闭流资源操作失败");
}
//关闭流资源
finally
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("关闭流资源操作失败");
}
}

}
}

}

4、对象的序列化
将对象中的数据(信息,如姓名、年龄等)存储到指定的文件(硬盘)中,就叫对象的序列化或对象的持久化存储。可以说,存储的文件是一个可以长久存储对象的介质。
需要注意的是,
静态不能被序列化,因为静态在方法区中存储,而序列化的是内存中的信息数据。
被transient关键字修饰的不能被序列化(即不能被存储到文件中)。
//创建Person类,实现序列化  
class Person implements Serializable{
//定义自身的序列化方式
public static final long serialVersionUID = 42L;
//定义私有属性
private String name;
private int age;
//该属性被transient修饰,故id不能被序列化
transient String id;
//该属性被被static修饰,故"cn"不能被序列化
static String country = "cn";
//构造Person类
Person(String name,int age,String id,String country){
this.name = name;
this.age = age;
this.id = id;
this.country = country;
}
//覆写toString方法
public String toString(){
return name+ ":" + age + ":" + id + ":" + country;
}
}
//对象序列化测试
class ObjectStreamDemo{
public static void main(String[] args){
//对象写入流
writeObj();
//对象读取流
readObj();
}
//定义对象读取流
public static void readObj(){
ObjectInputStream ois = null;
try{
//创建对象读取流
ois = new ObjectInputStream(new FileInputStream("obj.txt"));
//通过读取文件数据,返回对象
Person p = (Person)ois.readObject();
System.out.println(p);
}catch (Exception e){
throw new RuntimeException("写入文件失败");
}
//最终关闭流对象
finally{
try{
if(ois!=null)
ois.close();
}catch (IOException e){
throw new RuntimeException("写入流关闭失败");
}
}
}
//定义对象写入流
public static void writeObj(){
ObjectOutputStream oos = null;
try{
//创建对象写入流
oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
//写入对象数据
oos.writeObject(new Person("lisi",25,"01","cn"));
}catch (Exception e){
throw new RuntimeException("写入文件失败");
}
//关闭流资源
finally{
try{
if(oos!=null)
oos.close();
}catch (IOException e){
throw new RuntimeException("写入流关闭失败");
}
}
}
}

5、管道流
PipedOutputStream
PipedInputStream
输入和输出可直接进行连接,结合线程使用
import java.io.*;
class PipedStream
{
public static void main(String[] args)throws Exception
{
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();

}
}

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("管道流创建成功".getBytes());
out.close();
}
catch (IOException ioe)
{
throw new RuntimeException("管道s输出流失败");
}
}
}

6、RandomAccessFile
RandomAccessFile类是随机访问文件类,他并不是io体系中的子类,
而是直接继承Object。
但他是IO包中的成员,因为他既能读取数据也可写入数据。
他的内部封装了一个数组么热切通过指正对数组的元素进行操作,
getFilePointer() 获取指针位置
seek() 改变指针位置

其完成读写原理是:内部封装了字节输入流和输出流。
通过构造函数,该类只能操作文件,且操作的文件还有模式。
RandomAccessFile(String name, String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

r: 只读模式,即对该文件的操作只能是读取已存在文件的数据,
不会创建文件,,若该文件不存在,会出现异常
rw: 可读可写,即对该文件的操作可以是读取也可以是写入数据,
如果要操作的文件不存在,则会在当前目录下自动创建,
若该文件存在不会讲该文件中的内容覆盖。
import java.io.*;
class RandomAccessFileDemo
{
public static void main(String[] args) throws IOException
{
writeFile();
//writeFile_2();
readFile();

}
public static void readFile()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("random.txt","r");

//调整对象中指针,获取该指针位置的数据信息 u获取的信息不一样8*0 8*1
//raf.seek(8*1);

//跳过指定的子节数,跳过8个字节,获取8个字节后的数据信息
//该方法只能向后跳,不能向前跳(回跳)
raf.skipBytes(8);

byte[] buf = new byte[4];

/*
raf.write("你好".getBytes());
Exception in thread "main" java.io.IOException: 拒绝访问。
若设定的文件操作模式为只读,则不能再对其进行写入操作
*/


raf.read(buf);

//将姓名打印在控制台
String name = new String(buf);
//获取年龄,此处要使用获取整数数据的方法
int age = raf.readInt();

System.out.println(name);
System.out.println(age);

raf.close();

}
public static void writeFile_2()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
//将第一个指针处的数据信息 李四a 修改掉,变为周六
raf.seek(8*0);
raf.write("周六".getBytes());
raf.writeInt(113);
raf.close();
}
public static void writeFile()throws IOException
{
//创建随机访问文件的对象,并关联一文件,指定模式类型
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
/*
raf.write(97);
存储数据的结果为:李四a

raf.write(258);存储结果为:李四
查表 数据丢失
//打印结果: 100000010 将最低8位写出 数据丢失
System.out.println(Integer.toBinaryString(258));

*/
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);
raf.close();
}
}

7、DataInputStream/DataOutputStream,可直接操作基本数据类型。
写入的是什么顺序,就按照什么顺序读取。

import java.io.*;
class DataStream
{
public static void main(String[] args) throws IOException
{
//writeData();
//readData();
//writeUTF();
readUTF();
}

public static void readUTF()throws IOException
{
//若使用readUTF方法读取gbk编码的数据文件会报异常,
//所以写入的是什么编码的数据就使用哪种读取的方法读取
DataInputStream dis = new DataInputStream(new FileInputStream("dataUTF.txt"));

String s = dis.readUTF();
System.out.println(s);
dis.close();
}
public static void writeUTF() throws IOException
{
/*
该文件4字节大小
*/
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("GBK.txt"),"GBK");
osw.write("你好");
osw.close();

/*
该文件大小为6字节

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("dataUTF.txt"),"UTF-8");
osw.write("你好");
osw.close();
*/

/*
该文件大小8字节

DataOutputStream dos =
new DataOutputStream(new FileOutputStream("dataUTF.txt"));

//默认是写入的是UTF修改版的编码
dos.writeUTF("你好");

dos.close();
*/


}
public static void readData()throws IOException
{
//创建数据输入流对象,并接收一个文件输入流,指定读取数据的来源
DataInputStream dis =
new DataInputStream(new FileInputStream("data.txt"));

//对文件进行读取操作,一定要按照写入的顺序读取,否则读取的数据不对
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();


System.out.println("num=="+num);
System.out.println("b=="+b);
System.out.println("d=="+d);

dis.close();

}
public static void writeData() throws IOException
{
//创建数据输出流对象,并在一初始化就关联一个文件输出流
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("data.txt"));

//将指定基本数据类型的数据写入,写入的数据大小为8个字节
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(3223.123);

//关闭数据输出流资源
dos.close();

}
}


8、ByteArrayInputStream/ByteArrayOutputStream
(1)不涉及调用底层资源,所以不用关流。不产生任何IOException。
(2)输出流中缓冲区随着数据的不断写入而自动增长。
(3)操作的是数组,即目的地是数组
import java.io.*;  
class ArrayStreamDemo
{
public static void main(String[] args)
{
//数据源
ByteArrayInputStream bais = new ByteArrayInputStream("ABCDEFF".getBytes());
//数据目的
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int by = 0;
//读取和写入数据
while((by=bais.read())!=-1)
{
baos.write(by);
}
System.out.println(baos.size());

System.out.println(baos.toString());

try
{
//方法,此处抛异常,所以上面需要抛出去
baos.writeTo(new FileOutputStream("a.txt"));
}
catch (IOException e)
{
throw new RuntimeException("写入文件失败");
}

}
}

9、转换流的字符编码
可传入编码表的有:
(1)转换流:InuputStreamReader和OutputStreamWriter
2)打印流:PrintStream和PrintWriter,只有输出流
字符编码/解码
(1)编码:字符串变成字节数组
(2) 解码:字节数组变成字符串
2、转换:
(1)默认字符集:
String ---> byte[] :srt.getBytes()
byte[] ---> String :new String(byte[])
2)指定字符集:
String ---> byte[] :srt.getBytes(charsetName)
byte[] ---> String :new String(byte[],charsetName)
字符编码--联通
12、练习
需求:
有5个学生,3门成绩,
从键盘输入学生数据,
格式为:zhangsan,78,98,96
学生的属性有姓名,3门课程的名称,
计算出学生3门课程的总成绩,并按照从高到底的顺序将总成绩排序。
并将该信息存储到一个文件中:studentInfor.txt

描述学生对象,
定义学生信息工具类,

分析:
1、定义一学生类,属性有:name,3门课程:math chinese english ,总成绩sum
复写hashCode()和equals()方法,(可能将数据存储到hashMap表中)
使学生具有比较性,实现Comparable接口,复写compareTo()方法,自定义比较方法
复写toString()方法,获得信息:name,math chinese english

2、定义一工具类,用于向集合中存储数据信息 TreeSet(要存储的信息有顺序)
将信息通过键盘录入写入到studentInfor.txt文件中
import java.util.*;
import java.io.*;
class Student implements Comparable<Student>
{
private String name;
private int math;
private int chinese;
private int english;
private int sum;
Student(String name,int chinese,int english )
{
this.name = name;
this.math = math;
this.chinese = chinese;
this.english = english;
sum = math + chinese + english;
}

//复写hashCode方法,自定义比较方式
public int hashCode()
{
//判断对象属性的姓名的哈希值
return name.hashCode()+sum*5;
}
//复写equals方法,将
public boolean equals(Object obj)
{
//判断传递进来的数据是否是Student类型,如果不是,抛出异常
if (!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
//如果是,将传递进来的数据强转为Student类型
Student stu = (Student)obj;

return this.name.equals(s.name) && this.sum == s.sum;
}
//复写Comparable接口的compareTo方法,
public int compareTo(Student s)
{
int num = new Integer(this.sum).compareTo(new Integer(s.sum));
if (num ==0)
return this.name.compareTo(s.name);
return num;

}
//定义方法,获取姓名和总成绩
public String getName()
{
return name;
}
public int getSum()
{
return sum;
}
public String toString()
{
return name+ math+ chinese + english;
}

}
class StudentInforTool
{
public static Set<Student> getStudnets()
{
return getStudents(null);
}
//定义一个带有比较器的学生集合
public static Set<Student> getStudnets()
{
//读取键盘录入
BufferedReader bufr = null;

Set<Student> stus = null;
try
{
//创建读取流对象缓冲区,键盘录入
bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
//选择集合是否有比较器
if(cmp==null)
stus = new TreeSet<Student>();
else
stus = new TreeSet<Student>(cmp);
//循环读取键盘录入的数据
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
//对读取的数据进行分割并存入集合
String[] info = line.split(",");
Student stu = new Student(info[0],Integer.parseInt(info[1]),
Integer.parseInt(info[2]),
Integer.parseInt(info[3]));
stus.add(stu);
}
}
catch (IOException e)
{
throw new RuntimeException("学生信息读取失败");
}
//关闭流资源
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
return stus;
}
}
//将数据写入指定文件
public static void write2File(Set<Student> stus,String fileName)
{
BufferedWriter bufw = null;
try
{
//创建写入流对象
bufw = new BufferedWriter(new FileWriter(fileName));
//循环写入数据
for(Student stu : stus)
{
bufw.write(stu.toString() + "\t");
bufw.write(stu.getSum() + "");
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
//关闭流资源
finally
{
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
}
}
}

class StudentInfoTest
{
public static void main(String[] args)
{
//反转比较器,将成绩从大到小排
Comparator<Student> cmp = Collections.reverseOrder();
//将录入的学生信息存入集合
Set<Student> stus = StudentInfoTool.getStudents(cmp);
//将信息写入指定文件中
StudentInfoTool.write2File(stus,"sudentinfo.txt");
}
}



[align=center]
-------[url]http://www.itheima.com[/url]java培训、android培训期待与您交流!------- [/align]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值