引言
在上一篇中提到了IO流中的字节流和字符流的相关概念,那么,在这个部分,主要说明其它相关IO流的知识。
LineNumberReader类:
跟踪行号的缓冲字符输入流,此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
String readLine():读取一行
做一个简单的案例进行理解:
案例:读取文件,每次读取一行打印并且加上行号
package com.stu_02;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
/*
案例:读取文件,每次读取一行打印并且加上行号
*/
public class LineNumberReaderStu {
public static void main(String[] args) throws IOException {
//创建跟踪行号的字符缓冲输入流
LineNumberReader lnr = new LineNumberReader(new FileReader("prop1.txt"));
// public void setLineNumber(int lineNumber):设置起始行号
lnr.setLineNumber(10);
String line;
//遍历
while ((line=lnr.readLine())!=null) {
//获取行号和内容
System.out.println(lnr.getLineNumber()+" "+line);
}
//关流
lnr.close();
}
}
编译运行结果如下:
11 #Sat May 13 16:41:42 CST 2017
12 zhangsan=10
13 lisi=100
14 wangwu=4
操作基本数据类型的流
可以操作基本类型的流对象。
DataInputStream:读数据
DataOutputStream:写数据
注意:
读写顺序必须一致,否则数据有问题。
内存操作流:
解决临时数据存储的问题。
操作字节数组
ByteArrayInputStream
ByteArrayOutputStream
byte[] toByteArray() 将之前写入内存的流转换成字节数组
操作字符数组
CharArrayReader
CharArrayWrite
操作字符串
StringReader
StringWriter
将数据写到流中保存在内存,并且读取,在这里,用一个操作字符数组做一解释说明:
package com.stu_04;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.IOException;
/*
* 操作字符数组
CharArrayReader
CharArrayWrite
*/
public class CharArrayReaderStu {
public static void main(String[] args) throws IOException {
//给内存中写数据
CharArrayWriter caw = new CharArrayWriter();
caw.write(99);
//将内存中的数据读出来
char[] ch=caw.toCharArray();
int len;
CharArrayReader car = new CharArrayReader(ch);
while ((len=car.read())!=-1) {
System.out.println((char)len);
}
//关流
caw.close();
car.close();
}
}
编译运行结果如下:
c
打印流
字节打印流 PrintStream
字符打印流 PrintWriter
特点:
A:只能操作目的地,不能操作数据源
B:可以操作任意类型的数据
C:如果启动了自动刷新,能够自动刷新
D:可以操作文件的流
注意:什么流可以直接操作文件?
看流对象的API,如果其构造方法同时有File和String类型的参数,就可以直接操作文件。
如何启动自动刷新:利用构造
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(Writer out, boolean autoFlush)
注意:如果启动了自动刷新,就要使用println、printf 或 format的时候,才可以实现自动刷新
启动自动刷新可以实现三个功能:1.写数据 2.换行 3.刷新
同样的,用一个简单的案例来理解:
利用字符流给文件中写数据(int类型,boolean类型),启动自动刷新
package com.stu_05;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
//利用字符流给文件中写数据(int类型,boolean类型),启动自动刷新
public class PrintWriterStu02 {
public static void main(String[] args) throws IOException {
//创建打印字符流对象
PrintWriter pw = new PrintWriter(new FileWriter("c.txt"),true);
//写数据(写数据、换行、刷新)
pw.println(20);
pw.println(false);
//关流
pw.close();
}
}
编译运行后会在命名为c.txt的文本文档下看到如下内容:
20
false
标准输入输出流
System类下有这样的两个成员变量:
标准输入流:
public static final InputStream in
标准输出流:
public static final PrintStream out
合并流
SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。
构造:
SequenceInputStream(InputStream s1, InputStream s2) :将s1和s2合并成一个输入流,先读取s1后读取s2
利用该方法可以将两个java文件合并为一个java文件
对象的序列化和反序列化
序列化流:把对象按照流一样的方式写到文件或者在网络中传输。
反序列化流:把文件或者网络中的流对象数据还原对象。
ObjectOutputStream:序列化流
writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
ObjectInputStream:反序列化流
Object readObject() 从 ObjectInputStream 读取对象。
注意:如果一个类不是实现Serializable接口无法把实例化,会报异常java.io.NotSerializableException
类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
如何实现序列化?
让对象所属类的实现序列化接口。
举一个简单的例子来证明上面所说:
//创建学生对象
package com.stu_07;
import java.io.Serializable;
public class Student implements Serializable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
}
//序列化流
package com.stu_07;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamStu {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
Student s = new Student("薛之谦", 35);
//将对象写入序列化流中
oos.writeObject(s);
//关流
oos.close();
}
}
//反序列化流
package com.stu_07;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamStu {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));
Object object = ois.readObject();
System.out.println(object);
ois.close();
}
}
编译运行后在oos.txt中会出现如下内容:
运行后在控制台输出入下:
Student [name=薛之谦, age=35]
Properties(查看api实现map接口本质是一个map集合)
Properties:Properties 类表示了一个持久的属性集。属性列表中每个键及其对应值都是一个字符串。
特点:Properties 可保存在流中或从流中加载。
Properties的特有功能:
A:添加元素
public Object setProperty(String key,String value)
B:获取元素
public String getProperty(String key)
public Set stringPropertyNames()
可以和IO流进行结合使用:
把文件中的数据加载到集合中。注意:文件中的数据必须是键值对象形式的(例如:张杰=谢娜)。
public void load(InputStream inStream): 从输入流中读取属性列表(键和元素对)。
public void load(Reader reader):按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
把集合中的数据存储到文本文件中,并且是按照键值对形式存储的。
public void store(OutputStream out,String comments): 以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。
public void store(Writer writer,String comments): 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
结合上面所述,做一个简单的案例进行理解:
我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费
//猜数字代码
package com.stu_09;
import java.util.Scanner;
public class GuessNumber {
public static void playGame(){
int ran=(int) (Math.random()*100+1);
Scanner sc=new Scanner(System.in);
while(true){
System.out.println("请输入你猜的数字:");
int number =sc.nextInt();
if(number<ran){
System.out.println("猜小了,请重新输入:");
}else if(number>ran){
System.out.println("猜大了,请重新输入:");
}else if(number==ran){
System.out.println("恭喜你,猜对了!");
break;
}
}
}
}
//测试代码
package com.stu_09;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
/*
*我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,
超过5次提示:游戏试玩已结束,请付费
*/
public class Test {
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
//将文件中的数据加载到集合中
prop.load(new FileReader("count.txt"));
//用指定的键在属性列表中搜索属性。
String string = prop.getProperty("count");
//转换成int类型
int number=Integer.parseInt(string);
//进行判断
if(number>4){
System.out.println("次数已到5次,请付费");
}else{
GuessNumber.playGame();
number++;
//将改变后的键值对重新存储到集合中去
prop.setProperty("count", number+"");
//将改变后的键值对存储到文件中
prop.store(new FileWriter("count.txt"),null);
}
}
}
每一次玩一次游戏周,我们可以在count.txt中看到键值对的变化,如下:
第一次:
第二次:
第三次:
第四次:
第五次:
当猜完五次之后,第六次运行,在控制台会输出:
次数已到5次,请付费