IO流四:转换流、IO流操作规律、异常日志、Properties类

1  转换流:字节流转换成字符流

字符流:

      FileReader

      FileWriter

      BufferedReader

      BufferedWriter

字节流:

      FileInputStream

      FileOutputStream

      BufferedInputStream

      BufferedOutputStream

 

InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即将一个字节流的输入对象变为字符流的输入对象。

OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即将一个字符流的输出对象变为字节流输出对象。

 

System.in System.out都是字节流。

通过System.in获取键盘录入对象,

通过InputStreamReaderInputStream),把字节流转换成字符流输入。

调用字符流的read方法从字符流中读取数据。

 

System.out返回的是PrintStream类型,是OutputStream的子类。

使用OutputStreamWriterOutputStream),把字符流转换成字节流输出。

调用字符流的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,明确源和目的。

            源:输入流。InputStreamReader

            目的:输出流。OutputStreamWriter

      2,明确操作的数据是否是纯文本。

            是:字符流。ReaderWriter

            否:字节流。InputStreamOutputStream

      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):将属性列表输出到指定的输出流,outPrintStreamPrintWriter

loadstore功能相反,load从流中加载到prop属性集合,storeprop集合中加载到流中。

 

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();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值