黑马程序员--自学笔记--IO流(其三)

IO流(其三)

-------- android培训java培训、期待与您交流!--------

七. 其他IO流之Properties集合

    Properties是Hashtable的子类,可用于键值对形式的配置文件也就是说它具备map集合的特点。Properties集合不需要泛型,因为该集合中的键值对都是String类型。该集合的继承关系是:Properties--继承-->Hashtable--继承-->Map。可见,Properties类是以键值对的方式进行对象操作。
1.Properties类的特点
    ① 该集合中的键和值都是字符串类型
    ② 集合中的数据可以保存到流中,或者从流中获取
    ③ 通常该集合用于操作以键值对形式存在的配置文件
2.通过代码演示Properties类的基本方法

① 创建一个Properties集合

        Properties prop = new Properties() ;
② 利用setProperties()方法存储元素
        prop.setProperties("权权",30) ;
③ 取出元素
        // 利用Set集合接收Properties对象的键
        Set<String> names = prop.stringPropertyNames() ;
        for(String name : names){
            //利用getProperty()方法取出键对应的值
       String value = prop.getProperty(name) ;
        }

④ 修改(如果键相同,则值将会被覆盖)
        prop.setProperties("权权",20) ;
⑤ 通过list()方法将Properties集合中的信息进行输出,该方法对于调试很有用
        //Properties集合具有与对象相结合的功能
        prop.list(System.out) ;
⑥ 存储(使数据持久化)
        prop.store("所要关联的流对象","属性列表的描述信息") ;
⑦ 读取配置文件信息
        prop.load("所要关联的流对象") ;

通过以下一个范例,进一步了解Properties集合方法的使用以及其存储和读取功能:(注意:注释中包含注意点以及知识点)

<span style="font-family:KaiTi_GB2312;"><strong><span style="font-family:KaiTi_GB2312;">package cn.itzixue.properties;

import java.io.*;
import java.util.Properties;

public class PropertiesDemo {

	/*
	 * 范例:获取一个应用程序运行的次数,如果超过五次,停止运行程序,并提示试用次数已到
	 * 
	 * 思路:
	 * 		1.涉及到次数,需要一个计数器。每次程序启动都需要进行计数,而该计数器必须能在每次获取的时候自增一次,
	 * 			并且要能将改变之后的值进行保存,便于下一次应用程序运行时能读取到已使用的次数
	 * 		2.要让应用程序每次运行时都能够读到计数器信息,且能对计数信息进行修改,就应该让计数器的生命周期变长,
	 * 			即从内存存取到硬盘文件
	 * 		3.要想实现文件中的信息存储并体现,应该使用键值对的方式让其名字与之相对应,这就需要运用到MAP集合,
	 * 			再加上需要读取硬盘上的数据,所以应该使用与MAP集合相关的io流,即是Properties 
	 */
	public static void main(String[] args) throws IOException {
		
		getAppCount() ;
	}

	public static void getAppCount() throws IOException {
		
		//将配置文件封装成对象
		File confile = new File("count.properties") ;
		
		//如果文件不存在,则创建一个新文件。避免因文件不存在而是读取产生异常
		if(!confile.exists()){
			
			confile.createNewFile() ;
		}
		
		FileInputStream fis = new FileInputStream(confile) ;
		
		//初始化Properties对象
		Properties prop = new Properties() ;
		
		//使用Properties对象的load()方法读取配置文件中的信息
		prop.load(fis) ;
		
		//利用Properties对象的getProperties()方法获取对应键的值
		String value = prop.getProperty("time") ;
		
		//定义一个计数器count来获取配置文件中的信息
		int count = 0 ;
		if(value!=null){
			
			//因为字符串无法进行算术运算,所以应该用Integer.parseInt(value)方法来将获取到的字符串信息转换为整形数据
			count = Integer.parseInt(value) ;
			if(count>5){
				
				//超过无五次进行提示,并结束程序
				/*System.out.println("使用次数已到,请购买正版!!!!!!!!") ;
				return ;*/
				//使用RuntimeException更为合理
				throw new RuntimeException("使用次数已到,请购买正版!!!!!!!!") ;
			}
		}
		
		count++ ;
		
		//将修改后的数据信息重新设置到Properties对象之中
		prop.setProperty("time", count+"") ;
		System.out.println("已使用 : "+count+" 次,剩下使用次数为 : "+(5-count)+" 次 !");
		
		FileOutputStream fos = new FileOutputStream("count.properties") ;
		
		//通过Properties对象的store()方法将修改后的数据写入到配置文件中
		//注意:此处所传参数第一个是目的文件,第二个是对该配置文件的描述信息
		prop.store(fos, "");
		
		fos.close() ;
		fis.close() ;
	}

}
</span></strong></span>

八. 其他IO流之打印流

1.PrintStream

    我们最常用到的输出语句:System.out对应的类型就是PrintStream。PrintStream具有以下几个特点:

1.提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式

2.不抛出IOException

3.构造函数可以接受三种类型的值(包括:① 字符串路径;② File对象;③ 字节输出流)

2.PrintWriter

    构造函数可以接收四种类型的值(包括:① 字符串路径;② File对象;③OutputStream;④ Writer)。对于①,②类型的数据,还可以指定编码表。也就是字符集。对于③,④类型的数据,可以指定自动刷新。
注意:该自动刷新值为true时,只有三个方法可以用:println(),printf(),format()。

    PrintWriter pw = new PrintWriter(new BufferedWriter(

        new OutputSteamWriter(new FileOutputStream("a.txt"),"utf-8")),true);

3.打印流的三种输出方法

    ① void print(数据类型 变量) 

    ② println(数据类型 变量) 提供换行,自动刷新

    ③ printf(String format, Object... args) 可以自定数据格式

    JDK1.5之后Java对PrintStream进行了扩展,增加了格式化输出方式,可以使用printf()重载方法直接格式化输出。但是在格式化输出的时候需要指定输出的数据类型格式。

九. 其他IO流之序列流(SequenceInputStream)

    序列流可用于将多个文件流对象合并成一个流对象,这一个类多用于文件合并操作。合并时有多少个文件要合并就需要多少个流对象与其进行关联,在使用时,还需要传入带有流对象的枚举值,才能够对SequenceInputStream类对象进行使用。
通过以下一个对mp3文件进行切割和合并操作的范例,来深入了解此类的使用方式以及加深对Properties类和和文件过滤器的使用的认识:(注意: 注释中包含关键知识点以及注意点)
自定义一个文件名过滤器:
<span style="font-family:KaiTi_GB2312;"><strong><pre name="code" class="java">package cn.itzixue.sequenceinputstream;

import java.io.File;
import java.io.FilenameFilter;

public class SuffixFilter implements FilenameFilter {

	private String suffix = null ;
	public SuffixFilter(String suffix) {
		
		this.suffix = suffix ;
	}
	public boolean accept(File dir, String name) {
		
		return name.endsWith(suffix);
	}

}</strong></span>
 

对指定目录下的mp3文件进行切割:

<span style="font-family:KaiTi_GB2312;"><strong>package cn.itzixue.sequenceinputstream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class SplitFileDemo {

	private static int SIZE = 1024*1024 ;

	public static void main(String[] args) throws IOException {
		
		File file = new File("F:"+File.separator+"1.mp3") ; 
		
		splitFile(file) ;

	}

	public static void splitFile(File file) throws IOException {
		
		//用文件读取流关联源文件
		FileInputStream fis = new FileInputStream(file) ;
		//定义一个缓冲区
		byte[] buf = new byte[SIZE ] ;
		//定义目的位置
		FileOutputStream fos = null ;
		
		int len = 0 ;
		//定义文件名序号,在创建文件时通过自增来使得文件切割之后分别存储与不同的文件中并且每一段文件通过序号排列
		int count = 1 ;
		//将切割所得文件存放的目录进行封装
		File dir = new File("F:\\mp3part") ;
		//健壮性判断
		if(!dir.exists()){
			//如果目录不存在则创建
			dir.mkdirs() ;
		}
		//进行读写操作
		while((len=fis.read(buf))!=-1){
			
			//通过File类的构造方法将拼接好的目的位置传入FileOutputStream对象中
			fos = new FileOutputStream(new File(dir,(count++)+".part")) ;
			fos.write(buf, 0, len);
			//关闭流操作
			fos.close() ;
		}
		
		Properties prop = new Properties() ;
		
		//将所切割文件的文件名和切割出来的碎片文件个数用键值对方式存储进Properties对象中
		prop.setProperty("partcount", count+"") ;
		prop.setProperty("filename", file.getName()) ;
		
		//创建一个输出流对象关联被切割文件的配置文件,用于存储被切割文件的文件名以及碎片个数,便于以后进行合并
		fos = new FileOutputStream(new File(dir,file.getName()+".properties")) ;
		//将Properties对象中的信息存储到文件中进行持久化
		prop.store(fos, "save file info") ;
		
		fos.close() ;
		fis.close() ;
	}

}
</strong></span>
对指定目录下的文件碎片根据配置文件信息进行合并:
<span style="font-family:KaiTi_GB2312;"><strong>package cn.itzixue.sequenceinputstream;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;

public class MergeFile {

	public static void main(String[] args) throws IOException {
		
		File dir = new File("F:"+File.separator+"mp3part") ;
		
		mergeFile(dir) ;
	}

	public static void mergeFile(File dir) throws IOException {
		
		//定义一个文件名过滤器,将配置文件过滤出来并存储于File对象数组中
		File[] file = dir.listFiles(new SuffixFilter(".properties")) ;
		//判断配置文件个数是否为一个,如果不是,则抛出异常停止运行程序
		if(file.length!=1){
			
			throw new RuntimeException(dir+"目录下缺少配置文件或者配置文件不唯一") ;
		}
		
		//将遍历到的配置文件封装成File类对象(由于配置文件只能有一个,所以只需要获取file[0]即可)
		File confile = file[0] ;
		
		FileInputStream fis = new FileInputStream(confile) ;
		Properties prop = new Properties() ;
		//将配置文件与Properties对象关联
		prop.load(fis) ;
		//将配置文件中的数据通过Properties对象的getProperty()方法通过取到相应的值
		String filename = prop.getProperty("filename") ;
		int num = Integer.parseInt(prop.getProperty("partcount")) ;
		//通过自定义的文件名过滤器过滤出碎片文件,并存储于File对象数组中
		File[] partFiles = dir.listFiles(new SuffixFilter(".part")) ;
		//判断碎片文件个数是否正确,如果不是,则抛出异常停止运行程序
		if(partFiles.length!=(--num)){
			
			throw new RuntimeException("碎片文件数量不符合要求,应该为"+num+"个,请重新下载!!") ;
		}
		
		//创建一个ArrayList类对象,用于接受存放碎片文件
		ArrayList<FileInputStream> a = new ArrayList<FileInputStream>() ;
		
		//将指定目录下的碎片文件添加到集合中
		for(int x=1;x<num;x++){
			a.add(new FileInputStream(new File(dir,x+".part"))) ;
		}
		
		//因为序列流接收的是一个枚举值,所以通过Collections.enumeration(?)方法返回集合对象的枚举值
		Enumeration<FileInputStream> en = Collections.enumeration(a) ;
		//将所获得的集合枚举值传递给序列流对象
		SequenceInputStream sis = new SequenceInputStream(en) ;
		
		//创建文件合并的目的地
		FileOutputStream fos = new FileOutputStream(new File(dir,"1-1.mp3")) ;
		int len = 0 ;
		byte[] buf = new byte[1024] ;
		
		while((len=sis.read(buf))!=-1){
			
			fos.write(buf, 0, len) ;
		}
		
		fos.close() ;
		sis.close() ;	
	}

}</strong></span>

十.其他IO流之ObjectInputStream / ObjectOutputStream

1.ObjectOutputStream
    ObjectOutputStream类可以将对象写入硬盘中,并将其序列化。
例如:
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("…….object")) ;
    // 所存储对象的文件的后缀名一般是.object,且此构造方法会抛出异常
    oos.writerObject(new 类名()) ;    // 类对象在写入文件中时,该类需要实现Serializable接口
    oos.close() ;    // 使用流对象之后要记得关闭
2.ObjectInputStream
    ObjectInputStream类可以将存储在文件中的类对象读出。在初始化该类时,所传入的对象文件需要通过ID值判断是否与相应类对应,如果不对应(即产生对象的原类已经改变)时,会抛出InvalidClassException异常。
例如:
    ObjectInputStream ois = new ObjectInputStream("…….object") ;
    原类名 原类对象 = (原类名)ois.readObject() ;
    ois.close() ;    // 使用流对象之后要记得关闭
3.Serializable接口
    Serializable接口的作用是用于给被序列化的类加入ID号,用于判断类和对象是否相对应。
注意:
    瞬态字段和静态字段以及被transient关键字修饰的字段不进入序列化中,当非静态变量不想被公有化时,可以使用transient关键字进行修饰。

十一. 其他IO流之RandomAccessFile

    RandomAccessFile类对象可以随机访问文件,并且本身具备读写方法。可以通过其对象的skipBytes(int x),seek(int x)等方法来制定指针位置,进而达到随机访问。
RandomAccessFile类的特点:
    1.该对象既能读又能写;
    2.该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素;
    3.可以通过getFilePointer()方法获取指针的位置,和通过seek()方法设置指针的位置;
    4.该对象的源或者目的只能是文件;
    5.该对象将自己额输入输出进行封装
例如:
<span style="font-family:KaiTi_GB2312;"><strong>	// 如果文件不存在,则创建,如果文件存在,不创建,所传入的"rw"是代表可使用的权限(r指可读;w指可写)
	RandomAccessFile raf = new RandomAccessFile("A.txt" ,"rw" );
	raf.write( " 张三 ".getBytes());
	// 使用 write()方法之写入最后一个字节(即最低字节)
	// 使用 writeInt()方法写入四个字节( int 类型)
	raf.writeInt(97);</strong></span>
随机代码演示:
<span style="font-family:KaiTi_GB2312;"><strong>	// 该方法可以返回当前指针位置
	raf.getFilePointer() ;    
	// 可以通过seek()方法设置指针的位置(0*8只是一个演示,因为在此环境中两个中文四个字节,所传入的整数也是四个字节,所以一组数据总共有8个字节,该语句表示从0处插入)   
	raf.seek(0*8) ; </strong></span>
    如果从0位置指针开始写入8个字节,会将原来8个字节数据覆盖,其他数据保持不变。
注意:
    要想实现随机性,则数据需要有规律!

十二. 其他IO流之DateInputStream / DateOutputStream

    DataInputStream类从数据流读取字节,并将它们转换为正确的基本数据类型值或字符串。DataOutputStream类将基本类型的值或字符串转换为字节,并且将字节输出到数据流。
    这两个类的对象在初始化化的时候需要传进io流。能够对基本数据类型进行写入和读取,writeXxx() / readXxx()。同时里面的方法writeUTF()只能用对应的readUTF()读取,因为操修改版的UTF-8使用的四个字节。

十三.其他流之管道流

    和多线程联系紧密的流。管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从PipedInputStream对象读取,并由其他线程将其写入到相应的PipedOutputStream。使用的方法是:管道输入流对象.connect(管道输出流对象)。
注意:
    不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。输出流中写入数据到管道中,然后输入流就可以读到数据。

十四. 其他IO流之ByteArrayInputStream / ByteArrayOutputStream

    字节数组流(ByteArrayInputStream和BytteArrayOutputStream),只往内存中写和读。不需要调用到底层资源,因此不涉及关闭资源(即关闭资源之后仍可使用其对象)。同时也不会抛出IO异常,只有一个方法writeTo(FileInputStreamf)涉及到异常。该流对象的源和目的都是内存。其中,ByteArrayInputStream包含一个内部缓冲区。
    
    另外还有CharArrayReader和CharArrayWriter。以及StringReader和StringWriter,功能都很相似。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值