黑马程序员---IO流(2)

------- http://www.itheima.comjava培训、android培训期待与您交流!-------


接着学习,,,,,
四、Properties
1、概述
   Properties 是集合中和IO技术相结合的集合容器。
   可用于键值对形式的配置文件
   加载数据时,需要数据有固定格式,即键=值。
因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty 方法。
2、获取
import java.io.*;
import java.util.*;
class PropertiesDemo 
{
	public static void main(String[] args) 
	{
		//创建对象
		Properties prop = new Properties();
		
		//设置属性,以键值的形式设置
		prop.setProperty("wangwu","20");
		prop.setProperty("lisi","30");

		//以键值对的形式打印
		System.out.println(prop);
		
		//通过键取值
		String value = prop.getProperty("wangwu");
		System.out.println(value);
		
		//先将map转化成set集合,再获取
		Set<String> names = prop.stringPropertyNames();

		for (String s : names )
		{
			//若只打印 s ,只是获取的是姓名
			System.out.println(s+"----"+prop.getProperty(s));
		}

		
	}
}


3、
用于记录应用程序运行次数 如果使用次数已到,那么给出注册提示信息。那么就要用计数器记录运行的次数,但是在程序结束后,会在内存中消失,此时就需要将其存入到文件中,
所以需要一个配置文件,用于记录该软件使用的次数。下次程序启动时会先加载该计数器的值并加以后重新存储。Map+IO=Properties
import java.util.*;  
import java.io.*;	
  
class RunCount  
{  
    public static void main(String [] args)throws IOException  
    {  
        //创建一个Properties对象,集合和io的结合  
        Properties pop = new Properties();  
        //创建一个文件对象,用于操作文件  
        File file = new File("count.ini");  
        //先判断文件是否存在,如果不存在就创建一个  
        if(!file.exists())  
            file.createNewFile();  
  
        //创建读取流对象,读取文件中的信息  
        FileInputStream fis = new FileInputStream(file);  
        //将流中的文件信息存入集合中  
        pop.load(fis);  
          
        //定义计数器  
        int count = 0;  
        //获取文件中键所对应的值  
        String value = pop.getProperty("time");  
        //判断值是否为null,不为空就将值传给计数器  
        if(value!=null)  
        {  
            count = Integer.parseInt(value);  
            //判断计数器是否为到达次数  
            if(count>=5)  
            {  
                System.out.println("次数已到,请注册");  
                return ;  
            }  
        }  
        count++;  
        //将获得的键值设置后存入集合中  
        pop.setProperty("time",count+"");  
        FileOutputStream fos = new FileOutputStream(file);  
        pop.store(fos,"");  
        fos.close();  
        fis.close();  
    }  
}  


五、IO包中的其他流
1、打印流
打印流提供了打印方法,可将各种数据类型的数据都原样打印。

(1)字节打印流:PrintStream
构造函数可接收的参数类型:
File对象  File
字符串路径 String
字节输出流 OutputStream
(2)字符打印流:PrintWriter,这是web开发常用的。
构造函数可接收的参数类型:
File对象  File
字符串路径 String
字节输出流 OutputStream
字符输出流 Writer

import java.io.*;   
class PrintDemo  
{  
    public static void main(String[] args) throws IOException  
    {  
        //键盘录入,创建读取流对象  
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));  
        //使用打印流,将文件输出  
        //输出到屏幕   
		//PrintWriter(Writer out, boolean autoFlush)  这里的autoFlush设置为true
		//则不用刷新缓冲区,
        PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);  
        String line = null;  
        while((line=bufr.readLine())!=null)  
        {  
            if("over".equals(line))  
                break;  
            out.println(line.toUpperCase());  
            //out.flush();  
        }  
        bufr.close();  
        out.close();  
    }  
}  

2、合并流
将多个输入流合并到一个流中。
import java.io.*;
class SequenceInputStreamDemo 
{  
		public static void sequenceFile()throws IOException  
		{  
		    //合并流对象
			FileOutputStream fos = null;  
			SequenceInputStream sis = null;  
			try  
			{  
				//创建集合,存储多个文件  
				ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();  
				for(int i=1;i<=3;i++)  
				{  
					al.add(new FileInputStream(i+".part"));  
				}  
				//匿名内部类访问局部变量要final  
				final Iterator<FileInputStream> it = al.iterator();  
				//创建Enumeration匿名对象  
				Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()  
				{  
					public boolean hasMoreElements()  
					{  
						return it.hasNext();  
					}  
					public FileInputStream nextElement()  
					{  
						return it.next();  
					}  
				};  
				//合并流对象,将集合元素加入。  
				sis = new SequenceInputStream(en);  
				//创建写入流对象,FileOutputStream  
				fos = new FileOutputStream("7.bmp");  
				byte[] b = new byte[1024*1024];  
				int len = 0;  
				//循环,将数据写入流资源  
				while((len=sis.read(b))!=-1)  
				{  
					fos.write(b);  
				}  
		  
			}  
			catch (IOException e)  
			{  
				throw new RuntimeException("文件操作失败");  
			}  
			//关闭流资源  
			finally  
			{  
				try  
				{  
					if(fos!=null)  
						fos.close();  
				}  
				catch (IOException e)  
				{  
					throw new RuntimeException("关闭流资源操作失败");  
				}  
				try  
				{  
					if(sis!=null)  
						sis.close();  
				}  
				catch (IOException e)  
				{  
					throw new RuntimeException("关闭流资源操作失败");  
				}  
			}         
		}  
}

3、切割文件
import java.io.*;
class SplitFile 
{
	//切割流对象  
    public static void splitFile()throws IOException  
    {  
        //创建全局变量  
        FileInputStream fis = null;  
        FileOutputStream fos = null;  
        try  
        {  
            //创建文件读取流  
            fis = new FileInputStream("0.bmp");  
            //创建数组  
            byte[] b = new byte[1024*1024];  
            int len = 0;  
            //计数器  
            int count = 1;  
            //循环写入数据  
            while((len=fis.read(b))!=-1)  
            {  
                //每次创建一个新写入流,写入后关闭流资源  
                fos = new FileOutputStream((count++)+".part");  
                fos.write(b,0,len);  
                fos.close();  
            }  
        }  
        catch (IOException e)  
        {  
                throw new RuntimeException("关闭流资源操作失败");  
        }  
        //关闭流资源  
        finally  
        {  
            try  
            {  
                if(fis!=null)  
                    fis.close();  
            }  
            catch (IOException e)  
            {  
                throw new RuntimeException("关闭流资源操作失败");  
            }  
        }  
          
    }  
}  

}

4、对象的序列化
将对象中的数据(信息,如姓名、年龄等)存储到指定的文件(硬盘)中,就叫对象的序列化或对象的持久化存储。可以说,存储的文件是一个可以长久存储对象的介质。
需要注意的是,
静态不能被序列化,因为静态在方法区中存储,而序列化的是内存中的信息数据。
被transient关键字修饰的不能被序列化(即不能被存储到文件中)。
//创建Person类,实现序列化  
class Person implements Serializable{  
    //定义自身的序列化方式  
    public static final long serialVersionUID = 42L;  
    //定义私有属性  
    private String name;  
    private int age;  
   //该属性被transient修饰,故id不能被序列化
    transient String id;  
   //该属性被被static修饰,故"cn"不能被序列化
    static String country = "cn";  
    //构造Person类  
    Person(String name,int age,String id,String country){  
        this.name = name;  
        this.age = age;  
        this.id = id;  
        this.country = country;  
    }  
    //覆写toString方法  
    public String toString(){  
        return name+ ":" + age + ":" + id + ":" + country;  
    }  
}  
//对象序列化测试  
class ObjectStreamDemo{  
    public static void main(String[] args){  
        //对象写入流  
        writeObj();  
        //对象读取流  
        readObj();  
    }  
    //定义对象读取流  
    public static void readObj(){  
        ObjectInputStream ois = null;  
        try{  
            //创建对象读取流  
            ois = new ObjectInputStream(new FileInputStream("obj.txt"));  
            //通过读取文件数据,返回对象  
            Person p = (Person)ois.readObject();  
            System.out.println(p);  
        }catch (Exception e){  
            throw new RuntimeException("写入文件失败");  
        }  
        //最终关闭流对象  
        finally{  
            try{  
                if(ois!=null)  
                    ois.close();  
                }catch (IOException e){  
                throw new RuntimeException("写入流关闭失败");  
            }  
        }  
    }  
    //定义对象写入流  
    public static void writeObj(){  
        ObjectOutputStream oos = null;  
        try{  
            //创建对象写入流  
            oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));  
            //写入对象数据  
            oos.writeObject(new Person("lisi",25,"01","cn"));             
        }catch (Exception e){  
            throw new RuntimeException("写入文件失败");  
        }  
        //关闭流资源  
        finally{  
            try{  
                if(oos!=null)  
                    oos.close();  
                }catch (IOException e){  
                throw new RuntimeException("写入流关闭失败");  
            }  
        }  
    }  
} 

5、管道流
PipedOutputStream
PipedInputStream
输入和输出可直接进行连接,结合线程使用
import java.io.*;
class PipedStream 
{
	public static void main(String[] args)throws Exception 
	{
		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream();
		in.connect(out);

		Read r = new Read(in);
		Write w = new Write(out);

		new Thread(r).start();
		new Thread(w).start();

	}
}

class Read implements Runnable
{
	private PipedInputStream in;
	Read(PipedInputStream in)
	{
		this.in = in;
	}
	public void run()
	{
		try
		{
			//定义一个字节数组,用于存储读出的数据
			byte[] buf = new byte[1024];

			System.out.println("读取前,,没有数据阻塞");
			

			//将数据读取到字节数组中
			int len = in.read(buf);

			System.out.println("读到数据,,阻塞结束");

			//将有效数据转换成字符串打印
			String s = new String(buf,0,len);
			System.out.println(s);
			in.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道读取流失败");
		}
	}
}

class Write implements Runnable  
{
	private PipedOutputStream out;
	Write(PipedOutputStream out)
	{
		this.out = out;	
	}
	public void run()
	{
		try
		{
			System.out.println("开始写入数据,等待6秒后");
			Thread.sleep(6000);
			out.write("管道流创建成功".getBytes());
			out.close();
		}
		catch (IOException ioe)
		{
			throw new RuntimeException("管道s输出流失败");
		}
	}
}

6、RandomAccessFile
RandomAccessFile类是随机访问文件类,他并不是io体系中的子类,
而是直接继承Object。
但他是IO包中的成员,因为他既能读取数据也可写入数据。
他的内部封装了一个数组么热切通过指正对数组的元素进行操作,
getFilePointer() 获取指针位置
seek() 改变指针位置

其完成读写原理是:内部封装了字节输入流和输出流。
通过构造函数,该类只能操作文件,且操作的文件还有模式。
RandomAccessFile(String name, String mode)
          创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

r:  只读模式,即对该文件的操作只能是读取已存在文件的数据,
    不会创建文件,,若该文件不存在,会出现异常
rw: 可读可写,即对该文件的操作可以是读取也可以是写入数据,
    如果要操作的文件不存在,则会在当前目录下自动创建,
若该文件存在不会讲该文件中的内容覆盖。
import java.io.*;
class RandomAccessFileDemo 
{
	public static void main(String[] args) throws IOException
	{
		writeFile();
		//writeFile_2();
		readFile();
		
	}
	public static void readFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("random.txt","r");

		//调整对象中指针,获取该指针位置的数据信息 u获取的信息不一样8*0  8*1
		//raf.seek(8*1);

		//跳过指定的子节数,跳过8个字节,获取8个字节后的数据信息
		//该方法只能向后跳,不能向前跳(回跳)
		raf.skipBytes(8);

		byte[] buf = new byte[4];

		/*
		raf.write("你好".getBytes());
		Exception in thread "main" java.io.IOException: 拒绝访问。
		若设定的文件操作模式为只读,则不能再对其进行写入操作
		*/
		

		raf.read(buf);

		//将姓名打印在控制台
		String name = new String(buf);
		//获取年龄,此处要使用获取整数数据的方法
		int age = raf.readInt();

		System.out.println(name);
		System.out.println(age);

		raf.close();

	}
	public static void writeFile_2()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
		//将第一个指针处的数据信息 李四a  修改掉,变为周六
		raf.seek(8*0);
		raf.write("周六".getBytes());
		raf.writeInt(113);
		raf.close();
	}
	public static void writeFile()throws IOException
	{
		//创建随机访问文件的对象,并关联一文件,指定模式类型
		RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
		/*
		raf.write(97);
		存储数据的结果为:李四a
		
		raf.write(258);存储结果为:李四
		查表 数据丢失
		//打印结果:  100000010 将最低8位写出  数据丢失
		System.out.println(Integer.toBinaryString(258));

		*/
		raf.write("李四".getBytes());	
		raf.writeInt(97);
		raf.write("王五".getBytes());
		raf.writeInt(99);
		raf.close();
	}
}

7、DataInputStream/DataOutputStream,可直接操作基本数据类型。
写入的是什么顺序,就按照什么顺序读取。
import java.io.*;
class DataStream 
{
	public static void main(String[] args) throws IOException
	{
		//writeData();
		//readData();
		//writeUTF();
		readUTF();
	}

	public static void readUTF()throws IOException
	{
		//若使用readUTF方法读取gbk编码的数据文件会报异常,
		//所以写入的是什么编码的数据就使用哪种读取的方法读取
		DataInputStream dis = new DataInputStream(new FileInputStream("dataUTF.txt"));

		String s = dis.readUTF();
		System.out.println(s);
		dis.close();
	}
	public static void writeUTF() throws IOException
	{
		/*
		该文件4字节大小
		*/
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("GBK.txt"),"GBK");
		osw.write("你好");
		osw.close();

		/*
		该文件大小为6字节
		
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("dataUTF.txt"),"UTF-8");
		osw.write("你好");
		osw.close();
		*/

		/*
		该文件大小8字节
		
		DataOutputStream dos = 
			new DataOutputStream(new FileOutputStream("dataUTF.txt"));
		
		//默认是写入的是UTF修改版的编码
		dos.writeUTF("你好");

		dos.close();
		*/
		

	}
	public static void readData()throws IOException
	{
		//创建数据输入流对象,并接收一个文件输入流,指定读取数据的来源
		DataInputStream dis = 
			new DataInputStream(new FileInputStream("data.txt"));
		
		//对文件进行读取操作,一定要按照写入的顺序读取,否则读取的数据不对
		int num = dis.readInt();
		boolean b = dis.readBoolean();
		double d = dis.readDouble();
		

		System.out.println("num=="+num);
		System.out.println("b=="+b);
		System.out.println("d=="+d);

		dis.close();
		
	}
	public static void writeData() throws IOException
	{
		//创建数据输出流对象,并在一初始化就关联一个文件输出流
		DataOutputStream dos = 
			new DataOutputStream(new FileOutputStream("data.txt"));
		
		//将指定基本数据类型的数据写入,写入的数据大小为8个字节
		dos.writeInt(234);
		dos.writeBoolean(true);
		dos.writeDouble(3223.123);
		
		//关闭数据输出流资源
		dos.close();

	}
}


8、ByteArrayInputStream/ByteArrayOutputStream
(1)不涉及调用底层资源,所以不用关流。不产生任何IOException。
(2)输出流中缓冲区随着数据的不断写入而自动增长。
(3)操作的是数组,即目的地是数组
import java.io.*;  
class ArrayStreamDemo  
{  
    public static void main(String[] args)  
    {  
        //数据源  
        ByteArrayInputStream bais = new ByteArrayInputStream("ABCDEFF".getBytes());  
        //数据目的  
        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
        int by = 0;  
        //读取和写入数据  
        while((by=bais.read())!=-1)  
        {  
            baos.write(by);  
        }  
        System.out.println(baos.size());  
  
        System.out.println(baos.toString());  
          
        try  
        {  
            //方法,此处抛异常,所以上面需要抛出去  
            baos.writeTo(new FileOutputStream("a.txt"));  
        }  
        catch (IOException e)  
        {  
            throw new RuntimeException("写入文件失败");  
        }  
          
    }  
}  

9、转换流的字符编码
可传入编码表的有:
(1)转换流:InuputStreamReader和OutputStreamWriter
2)打印流:PrintStream和PrintWriter,只有输出流
字符编码/解码
(1)编码:字符串变成字节数组
(2) 解码:字节数组变成字符串
2、转换:
(1)默认字符集:
      String  --->  byte[]   :srt.getBytes()
      byte[]   --->  String  :new String(byte[])
2)指定字符集:
      String  --->  byte[]   :srt.getBytes(charsetName)
      byte[]   --->  String  :new String(byte[],charsetName)
字符编码--联通
12、练习
需求:
有5个学生,3门成绩,
从键盘输入学生数据,
格式为:zhangsan,78,98,96
学生的属性有姓名,3门课程的名称,
计算出学生3门课程的总成绩,并按照从高到底的顺序将总成绩排序。
并将该信息存储到一个文件中:studentInfor.txt

描述学生对象,
定义学生信息工具类,

分析:
1、定义一学生类,属性有:name,3门课程:math chinese english ,总成绩sum
   复写hashCode()和equals()方法,(可能将数据存储到hashMap表中)
   使学生具有比较性,实现Comparable接口,复写compareTo()方法,自定义比较方法
   复写toString()方法,获得信息:name,math chinese english

2、定义一工具类,用于向集合中存储数据信息  TreeSet(要存储的信息有顺序)
   将信息通过键盘录入写入到studentInfor.txt文件中
import java.util.*;
import java.io.*;
class Student implements Comparable<Student>
{
	private String name;
	private int math;
	private int chinese;
	private int english;
	private int sum;
	Student(String name,int chinese,int english )
	{
		this.name = name;
		this.math = math;
		this.chinese = chinese;
		this.english = english;
		sum = math + chinese + english;
	}
	
	//复写hashCode方法,自定义比较方式
	public int hashCode()
	{
		//判断对象属性的姓名的哈希值
		return name.hashCode()+sum*5;
	}
	//复写equals方法,将
	public boolean equals(Object obj)
	{
		//判断传递进来的数据是否是Student类型,如果不是,抛出异常
		if (!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");
		//如果是,将传递进来的数据强转为Student类型
		Student stu = (Student)obj;
		
		return this.name.equals(s.name) && this.sum == s.sum;
	}
	//复写Comparable接口的compareTo方法,
	public int compareTo(Student s)
	{
		int num = new Integer(this.sum).compareTo(new Integer(s.sum));
		if (num ==0)
			return this.name.compareTo(s.name);
		return num;
		
	}
	//定义方法,获取姓名和总成绩
	public String getName()
	{
		return name;
	}
	public int getSum()
	{
		return sum;
	}
	public String toString()
	{
		return name+ math+ chinese + english;
	}

}
class StudentInforTool
{
	public static Set<Student> getStudnets()
	{
		return getStudents(null);
	}
	//定义一个带有比较器的学生集合
	public static Set<Student> getStudnets() 
	{
		//读取键盘录入
		BufferedReader bufr = null;

		Set<Student> stus = null;
		try  
        {  
            //创建读取流对象缓冲区,键盘录入  
            bufr = new BufferedReader(new InputStreamReader(System.in));  
            String line = null;  
            //选择集合是否有比较器  
            if(cmp==null)  
                stus = new TreeSet<Student>();  
            else  
                stus = new TreeSet<Student>(cmp);  
            //循环读取键盘录入的数据  
            while((line=bufr.readLine())!=null)  
            {  
                if("over".equals(line))  
                    break;  
                //对读取的数据进行分割并存入集合  
                String[] info = line.split(",");  
                Student stu = new Student(info[0],Integer.parseInt(info[1]),  
                                                Integer.parseInt(info[2]),  
                                                Integer.parseInt(info[3]));  
                stus.add(stu);  
            }  
        }  
        catch (IOException e)  
        {  
            throw new RuntimeException("学生信息读取失败");  
        }  
        //关闭流资源  
        finally  
        {  
            try  
            {  
                if(bufr!=null)  
                    bufr.close();  
            }  
            catch (IOException e)  
            {  
                throw new RuntimeException("读取流关闭失败");  
            }  
            return stus;  
        }  
    }  
	  //将数据写入指定文件  
    public static void write2File(Set<Student> stus,String fileName)  
    {  
        BufferedWriter bufw = null;  
        try  
        {  
            //创建写入流对象  
            bufw = new BufferedWriter(new FileWriter(fileName));  
            //循环写入数据  
            for(Student stu : stus)  
            {  
                bufw.write(stu.toString() + "\t");  
                bufw.write(stu.getSum() + "");  
                bufw.newLine();  
                bufw.flush();  
            }  
        }  
        catch (IOException e)  
        {  
            throw new RuntimeException("读取流关闭失败");  
        }  
        //关闭流资源  
        finally  
        {  
            try  
            {  
                if(bufw!=null)  
                    bufw.close();  
            }  
            catch (IOException e)  
            {  
                throw new RuntimeException("写入流关闭失败");  
            }  
        }  
    }  
} 

class StudentInfoTest
{
	 public static void main(String[] args)   
    {  
        //反转比较器,将成绩从大到小排  
        Comparator<Student> cmp = Collections.reverseOrder();  
        //将录入的学生信息存入集合  
        Set<Student> stus = StudentInfoTool.getStudents(cmp);  
        //将信息写入指定文件中  
        StudentInfoTool.write2File(stus,"sudentinfo.txt");  
    } 
}




------- http://www.itheima.comjava培训、android培训期待与您交流!-------

你可能感兴趣的:(java)