1 转换流:字节流转换成字符流
字符流:
FileReader
FileWriter
BufferedReader
BufferedWriter
字节流:
FileInputStream
FileOutputStream
BufferedInputStream
BufferedOutputStream
InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即将一个字节流的输入对象变为字符流的输入对象。
OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即将一个字符流的输出对象变为字节流输出对象。
System.in 和System.out都是字节流。
通过System.in获取键盘录入对象,
通过InputStreamReader( InputStream),把字节流转换成字符流输入。
调用字符流的read方法从字符流中读取数据。
System.out返回的是PrintStream类型,是OutputStream的子类。
使用OutputStreamWriter( OutputStream),把字符流转换成字节流输出。
调用字符流的writer方法把数据写入到字符流。
即:
InputStreamReader:把字节流转换成字符流输入,然后从字符流中读取数据。
OutputStreamWriter:把字符流转换成字节流输出,然后把数据输出到字符流中。
转换流特点:可以在构造函数中指定字符编码表。
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("e:\\encode.txt"),"UTF-8"); //指定用UTF-8字符编码表。
InputStreamReader isr =
new InputStreamReader(new FileInputStream("e:\\encode.txt"),"GBK"); //指定用GBK字符编码表。
代码示例:
import java.io.*;
class TransStreamDemo{
public static void main(String[] args) throws IOException{
//byteToChar();
charToByte();
}
public static void byteToChar() throws IOException{
//获取键盘录入对象
InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流InputStreamReader,是Reader子类。
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符流增加缓冲区技术高效操作。使用BufferedReader。
BufferedReader bufr = new BufferedReader(isr);
String line = null;
while((line=bufr.readLine())!=null){//缓冲区的readLine读取一行
if(line.equals("over"))
break;
System.out.println(line);
}
bufr.close();
}
public static void charToByte() throws IOException{
//获取输出对象
OutputStream os = System.out;
//OutputStreamWriter,把字符流转成字节流,是Writer子类。
OutputStreamWriter osw = new OutputStreamWriter(os);
//为了使用newLine()方法换行,定义一个字符流缓冲区。
BufferedWriter bufw = new BufferedWriter(osw);
//使用上个方法中的实现。三个语句简写成一个语句。
//键盘录入最常见写法:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null){
if(line.equals("over"))
break;
bufw.write(line);
bufw.newLine();
bufw.flush();
//BufferedWriter字符流写入缓冲区类中,有一个默认的存储要写入数据的缓冲区,
//写入时要刷新一下,才能完成输出。
}
bufw.close();
}
}
2 IO流操作规律
如果从键盘录入,输出到控制台上。
那么键盘录入是源,控制台就是目的。即System.in是源,System.out是目的。
如果想把键盘录入的数据存储到一个文件中。
那么,键盘录入是源,文件是目的。
IO流操作基本规律,通过三个明确来完成:
1,明确源和目的。
源:输入流。InputStream,Reader
目的:输出流。OutputStream,Writer
2,明确操作的数据是否是纯文本。
是:字符流。Reader,Writer
否:字节流。InputStream,OutputStream
3,当体系明确后,再明确使用哪个具体的对象。
通过设备来进行区分。
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。
源设备:
键盘 System.in,硬盘 FileStream,内存 ArrayStream。//数组流,即ByteArrayStream
目的设备:
控制台 System.out,硬盘 FileStream,内存 ArrayStream。
|--Reader
|--BufferedReader
|--LineNumberReader
|--InputStreamReader
|--FileReader
|--Writer
|--BufferedWriter
|--OutputStreamWriter
|--FileWriter
|--InputStream
|--BufferedInputStream
|--LineNumberInputStream
|--FileInputStream
|--OutputStream
|--BufferedOutputStream
|--FileOutputStream
3 小练习
把一个文本文件中的内容打印在控制台。
1,源:文件。
目的:控制台。
2,源是纯文本,用字符流。
目的控制台System.out,是字节流。
3,源设备:硬盘->内存。
目的设备:控制台。
源使用字符流Reader,目的使用转换流OutputStreamWriter,把字符流转换成字节流System.out,再输出。
代码示例:
import java.io.*;
class IOTest {
public static void main(String[] args) throws IOException{
BufferedReader bufr =
new BufferedReader(new FileReader("流操作规律.java"));
BufferedWriter bufw =
new BufferedWriter(new OutputStreamWriter(System.out)); //字符流转成字节流输出。
String line = null;
while((line=bufr.readLine())!=null){
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();
}
}
4 异常的日志信息
捕获一个异常,然后把时间和异常信息打印到一个文件中,日志文件。
思路:
1,用非法索引访问数组时抛出异常,ArrayIndexOutOfBoundsException。
2,利用try-catch捕获异常。
3,使用Date对象获取时间日期:日期格式封装到SimpleDateFormat对象,然后调用SimpleDateFormat对象的format方法,格式化指定的Date对象,并返回格式化日期的String类型。
4,使用PrintStream对象输出信息到日志文件,关联日志文件。
5,调用PrintStream对象的println方法打印日期到日志文件。
6,调用捕获的Exception异常对象的printStackTrace方法,把异常信息输出到指定的PrintStream流中。
代码示例:
import java.io.PrintStream;
import java.io.IOException;
import java.util.Date;
import java.text.SimpleDateFormat;
class ExceptionInfo {
public static void main(String[] args) {
try{
int[] arr = new int[2];
System.out.println(arr[3]); //出现异常
}
catch(Exception e){ //捕获异常
try{
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d); //用sdf的格式,格式化日期,并返回日期的String类型
PrintStream ps = new PrintStream("e:\\异常日志.log");
ps.println(s); //把日期写入日志文件
System.setOut(ps); //重新分配标准输出流为PrintStream
}
catch(IOException ex){
throw new RuntimeException("日志创建失败");
}
e.printStackTrace(System.out); //输出到日志文件
}
}
}
5 Properties类
Properties类位于java.util包中,是Hashtable的子类。
也就是说它具备Map集合的特点,而且它里面存储的键值对都是字符串。
Properties是集合中和IO技术相结合的集合容器。
该对象的特点:可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有固定格式:键=值。
setProperty( key, value) :可以添加系统属性信息。
getProperty( key) :可以获取指定“键”指示的系统属性。
System类中也可直接调用这两个方法,System调用getProperties()获取Properties对象。
load( in):读取输入流中的数据,加载进Properties属性集合。固定格式:“键=值”。
store( out, string):将Properties中的内容加载到out输出流中,并添加注释信息String。
list( out):将属性列表输出到指定的输出流,out是PrintStream或PrintWriter。
load和store功能相反,load从流中加载到prop属性集合,store从prop集合中加载到流中。
Properties一些方法的演示代码和注释:
import java.util.*;
import java.io.*;
class PropertiesDemo{
public static void main(String[] args) throws IOException{
setAndGet();
method_1(); //load方法原理。
loadDemo();
}
//设置和获取元素。
public static void setAndGet(){
Properties prop = new Properties();
prop.setProperty("zhangsan","30"); //设置
prop.setProperty("lisi","39");
System.out.println(prop);
String value = prop.getProperty("lisi"); //获取
System.out.println(value);
//stringPropertyNames()方法以Set集合形式返回该属性集的键集。
Set<String> names = prop.stringPropertyNames();
for(String s : names){
System.out.println(s+"::"+prop.getProperty(s));
}
}
//演示,如何将流中的数据存储到集合中。
//想要将info.txt中的键值数据存到集合中进行操作。
/*
1,用一个流和info.txt文件关联。
2,读取一行数据,将该行数据用“=”进行切割。
3,等号左边作为键,右边作为值,存入到Properties集合中即可。
*/
public static void method_1() throws IOException{
BufferedReader bufr = new BufferedReader (new FileReader("info.txt"));
String line = null;
Properties prop = new Properties();
while((line=bufr.readLine())!=null){
String[] arr = line.split("=");
//System.out.println(arr[0]+"..."+arr[1]);
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);
}
//Properties集合的load(Reader reader)方法演示,以及list方法、store方法。
//load和store的功能相反。
public static void loadDemo() throws IOException{
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("info.txt");
//load方法将读取流中的数据加载进prop属性集合。
prop.load(fis);
prop.setProperty("wangwu","99");
FileOutputStream fos = new FileOutputStream("info.txt");
//store方法将prop中的内容加载到写入流fos,并附加注释信息"haha"
prop.store(fos,"haha");
//System.out.println(prop);
prop.list(System.out); //list方法将属性列表输出到指定输出流。
//System.out 返回PrintStream类型。
fis.close();
}
}
6 Properties练习
一些收费软件提供免费试用,但会限制使用次数,免费试用次数用完后,软件就不能使用了。
那么怎么记录程序使用的次数呢?
很容易想到:计数器。
但是计数器定义在程序中,随着程序退出,计数器也在内存中消失了,下一次打开程序,计数器又会清零。
这不是我们想要的,应该程序即使退出,计数器的值也会存在,并且在下一次程序运行时自增。
所以要建立一个配置文件,用于记录该软件的使用次数。
该配置文件使用键值对的形式,这样便于阅读数据,并操作数据。
键值对数据想到Map集合,而数据是以文件形式存在,想到IO技术。
那么,Map+IO,我们就想到了Properties集合。
代码示例:
import java.util.*;
import java.io.*;
class PropertiesTest {
public static void main(String[] args) throws IOException{
Properties prop = new Properties(); //创建Properties属性集。
File file = new File("count.ini"); //配置文件对象
if(!file.exists())
file.createNewFile(); //若此配置文件不存在则创建。
FileInputStream fis = new FileInputStream(file); //读取流,输入。
prop.load(fis); //将读取流中的数据加载入prop属性集。
int count = 0;
String value = prop.getProperty("time"); //获取计数器的值
if(value!=null) {
count = Integer.parseInt(value); //String类型转换成Int类型。
if(count>=5){
System.out.println("您好,免费次数已到,请充值");
return;
}
}
count++;
prop.setProperty("time",count+""); //计数器自增后,保存到配置文件
FileOutputStream fos = new FileOutputStream(file); //输出流
prop.store(fos,""); //将prop中的内容加载到输出流中。
fos.close();
fis.close();
}
}