一、IO流的一些其他东西
1.LineNumberReader:
其特有方法:
public int getLineNumber():获取行号
public void setLineNumber(int lineNumber):设置起始行号
String readLine():读取一行
案例:读取一个文件,且获取每行的行号
public static void main(String[] args) throws IOException {
//创建LineNumberReader对象
//public LineNumberReader(Reader in)
LineNumberReader lnr = new LineNumberReader(new FileReader("a.txt"));
//默认起始行号从0开始
//设置其实行号为从10开始
lnr.setLineNumber(10);
//一次读取一行
String line;
while ((line = lnr.readLine())!=null) {
//打印每一行的行号和内容
System.out.println(lnr.getLineNumber()+":"+line);
}
//关流
lnr.close();
}
2.可以操作基本数据类型的流
可以操作基本类型的流对象。
DataInputStream:读数据
DataOutputStream:写数据
注意:读数据的顺序要和写数据的顺序一样,否则数据有问题。
案例:在文本中写入不同类型数据,并读取。
public static void main(String[] args) throws IOException {
//写数据
write();
read();
}
private static void read() throws IOException {
//DataInputStream:读数据
//创建对象:public DataInputStream(InputStream in)
DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt"));
//读数据了,按什么顺序写入就必须按照什么顺序读出来
System.out.println(dis.readByte());
System.out.println(dis.readShort());
System.out.println(dis.readInt());
System.out.println(dis.readLong());
System.out.println(dis.readChar());
System.out.println(dis.readFloat());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
//关流
dis.close();
}
private static void write() throws IOException {
//public DataOutputStream(OutputStream out)
DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));
//给流关联的文件中写入基本类型的数据
dos.writeByte(20);
dos.writeShort(200);
dos.writeInt(2000);
dos.writeLong(20000L);
dos.writeChar(97);
dos.writeFloat(12.34F);
dos.writeDouble(23.34);
dos.writeBoolean(true);
//关流
dos.close();
}
这里write和read后面的类型,要与写入或读取的内容类型相对应。
3. 内存操作流:解决临时数据存储的问题。
操作字节数组
ByteArrayInputStream
ByteArrayOutputStream
toByteArray() 将之前写入内存的流转换成字节数组
案例:向内存写入数据,并读取。
public static void main(String[] args) throws IOException {
//给内存中写数据public ByteArrayOutputStream()
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//给内存中调用方法写数据
baos.write("hello".getBytes());
//将写入内存中的数据读取出来
byte[] buf = baos.toByteArray();//调用这个方法,将之前写入内存中的数据存储到字节数组中
ByteArrayInputStream bais = new ByteArrayInputStream(buf);//将刚才存储到字节数组中的内容关联上bais
//只有这样之后,我们才可以直接从bais中读取我们想要的内容
//一次读取一个字节
int by;
while ((by=bais.read())!=-1) {
System.out.print((char)by);
}
//关流
bais.close();
baos.close();
}
4.打印流:
字节打印流 PrintStream
字符打印流 PrintWriter
特点:
A:只能操作目的地,不能操作数据源
B:可以操作任意类型的数据
C:如果启动了自动刷新,能够自动刷新
D:可以操作文件的流
注意:什么流可以直接操作文件?
看流对象的API,如果其构造方法同时有File和String类型的参数,就可以直接操作文件。
利用构造方法开启自动刷新:
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(Writer out, boolean autoFlush)
注意:如果已经开启了自动刷新功能,必须调用则 println、printf 或 format的时候,才可以实现自动刷新
案例:利用字符打印流给文件写入数据,并自动刷新。
public static void main(String[] args) throws IOException {
//创建字符打印流对象,并开启自动刷新
PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);
//给流中写数据
//注意:如果已经开启了自动刷新功能,必须调用则 println、printf 或 format的时候,才可以实现自动刷新
pw.println("hello");
pw.println("java");
pw.println("world");//调用println这个方法给文件中写数据,1.写数据 2.换行 3.刷新
//可以操作任意类型的数据
pw.println(true);
pw.println(12.34);
//关流
pw.close();
}
这里可以配合BufferedReader来复制文本,只需要在println()中写入readline即可完成写入一行数据并换行、刷新的功能。
5.标准输入输出流
System类下有这样的两个成员变量:
标准输入流:
public static final InputStream in
案例1:利用标注输入流进行键盘录入,录入后读取流并打印在控制台
public static void main(String[] args) throws IOException {
/**
* public static final InputStream in
*/
//将键盘录入的数据封装在了输入流中
//Scanner sc = new Scanner(System.in);
InputStream is = System.in;
//将键盘录入的数据从输入流中读取出来
int by;
while ((by=is.read())!=-1) {
System.out.print((char)by);
}
//关流
is.close();
}
案例2:用IO流实现键盘录入,一次读取一行数据
分析:
InputStream is = System.in;
BufferedReader是字符缓冲流,是对字符流进行高效操作的
所以,参数必须是字符类型
而我们现在有的是字节类型的流
因此,我们可以通过转换流实现。
InputStream is = System.in;
InputSreamReader isr = new InputStreamReader(is)
BufferedReader br = new BufferedReader(isr);
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//一次读取一行数据
System.out.println("请输入你的姓名");
String name = br.readLine();
System.out.println("请输入你的年龄");
String age = br.readLine();
System.out.println(name+":"+age);
}
标准输出流:
public static final PrintStream out
解析输出语句System.out.println("helloworld");
PrintOut ps = System.out;
ps.println("helloworld");
6.
合并流:SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。
构造方法:
SequenceInputStream(InputStream s1, InputStream s2) :将s1和s2合并成一个输入流,先读取s1后读取s2
案例:将两个Java文件写到一个Java文件中
public static void main(String[] args) throws IOException {
//创建合并流对象
//SequenceInputStream(InputStream s1, InputStream s2) :将s1和s2合并成一个输入流,先读取s1后读取s2
SequenceInputStream sis = new SequenceInputStream(new FileInputStream("PrintWriterDemo.java"), new FileInputStream("SystemIn2.java"));
//封装目的地
FileOutputStream fos = new FileOutputStream("copy2.java");
//一下读写一个字节数组
byte[] buf = new byte[1024];
int len;
while ((len=sis.read(buf))!=-1) {
//读多少写多少
fos.write(buf, 0, len);
}
//关流
fos.close();
sis.close();
}
8. 对象的序列化和反序列化
序列化流:把对象按照流一样的方式写到文件或者在网络中传输。
反序列化流:把文件或者网络中的流对象数据还原对象。
ObjectOutputStream:序列化流
writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
ObjectInputStream:反序列化流
Object readObject() 从 ObjectInputStream 读取对象。
注意:如果一个类不是实现Serializable接口无法把实例化,会报异常java.io.NotSerializableException
类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
案例: 写一个Student类,将其序列化写入文本中,并通过反序列化读取。
1.创建一个学生类,实现Serializable接口。public class Studnet implements Serializable
2.创建序列化流,写入对象
public static void main(String[] args) throws IOException {
//创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
//创建一个学生对象,将学生对象写入文件中
Studnet s = new Studnet("刘德华", 50);
oos.writeObject(s);
//关流
oos.close();
}
3.创建反序列化流,读取数据
public static void main(String[] args) throws Exception {
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));
//读取文件中存储的对象,以实现反序列化
//readObject()
Object object = ois.readObject();
System.out.println(object);
//关流
ois.close();
}
这里所创建的文本"oos.txt"打开后我们是看不懂的,需要ObjectInputStream反序列化读取。
9. Properties(查看api实现map接口本质是一个map集合)
9.1
Properties:Properties 类表示了一个持久的属性集。属性列表中每个键及其对应值都是一个字符串。
特点:Properties 可保存在流中或从流中加载。
9.2
Properties的特有功能:
A:添加元素
public Object setProperty(String key,String value)
B:获取元素
public String getProperty(String key)
public Set<String> stringPropertyNames()
9.3
可以和IO流进行结合使用:
把文件中的数据加载到集合中。注意:文件中的数据必须是键值对象形式的(例如:张杰=谢娜)。
public void load(InputStream inStream)
public void load(Reader reader)
把集合中的数据存储到文本文件中,并且是按照键值对形式存储的。
public void store(OutputStream out,String comments)
public void store(Writer writer,String comments)
案例:将创建的键值对集合加载到文件中
public static void main(String[] args) throws IOException {
//创建集合
Properties prop = new Properties();
//给集合中存储数据
prop.setProperty("liudehua", "50");
prop.setProperty("liming", "60");
prop.setProperty("zhangxueyou", "40");
//将集合中的元素,存储到文本文件中
prop.store(new FileWriter("prop.txt"), null);
}
这里通过Properties集合存入文本的数据,是以“=”隔开的。 store方法写入时,第一行是一个字符串,内容可以定为null ,第二行为写入时间。
案例:我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。
分析:通过Properties集合实现,可以创建一个文本,记录count游戏次数,每玩完一次,将剩余次数写入文本。当次数大于5时,无法启动游戏,并提示充值。
public static void main(String[] args) throws IOException {
//1.将文件中的键值对加载到集合中
Properties prop = new Properties();
prop.load(new FileReader("count.txt"));
//2.拿出已经玩耍的次数做判断
String count = prop.getProperty("count");
//将String类型转换为int类型
int number = Integer.parseInt(count);
if (number>4) {
System.out.println("次数已到,请付费");
}else {
//开启游戏
startGame();
number++;
//将自增的次数重新存储到文件中
prop.setProperty("count", number+"");
//将新的prop集合存储到文件中
prop.store(new FileWriter("count.txt"), null);
}
}
private static void startGame() {
// TODO Auto-generated method stub
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;
}
}
}
流的总结:
流分为字节流和字符流,可以分为字节输入流InputStream、字节输出流OutputStream、字符输入流Reader、字符输出Writer四个类(抽象类)。字节流FileInputStream和FileOutputStream可以直接关联文件,其子类高级流BufferedInputStream和BufferedOutputStream可以操作流。
字节流可以通过InputStreamReader和OutputStreamWriter转化为字符流,通常使用他们的简化子类FileReader和FileWriter来实现。高效流需要关联的是字符流,BufferedReader中有readLine()方法,BufferedWriter中有newLine()方法。其他流的使用方法与这些类的使用方法大体相同,只是多了一些特有的方法方便使用。