java基础--IO流之其它流对象

来源:互联网 发布:美工的岗位职责 编辑:程序博客网 时间:2024/04/30 04:45

笔记摘要:

本篇文章主要是对于IO流中除了经常见到的读写流之外的一些其他流对象,

Properties打印流、合并流SequenceInputStream、对象的序列化,持久化的流对象、

管道流对象、操作基本数据类型的流对象、  随机访问文件流对象以及源和目的都是内存的IO流对象


一、Properties

Properties是hashtable的子类。

也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串。

是集合中和IO技术相结合的集合容器。


该对象的特点:

可以用于键值对形式的配置文件。

那么在加载数据时,需要数据有固定格式:键 = 值。

 

Properties练习:记录应用程序运行次数,如果使用次数已到,那么给出注册提示

示例说明:

该配置文件使用键值对的形式,这样便于阅读数据,并操作数据。

键值对数据是map集合,数据是以文件形式存储,使用io技术。

那么map+io-->properties.

配置文件可以实现应用程序数据的共享。

 

程序中发现的问题:

FileOutputStream的创建应该在count自加之后,这样每次创建FileOutputStream时,就可以用新值覆盖旧值。如果在之前创建,需要将boolean值设为true,这样count才不会被覆盖,否则,文件被覆盖,count获取到的值为null,那么count的值在+1后,第二次会重复这样的操作,所以永远是1,这样就会在文件后面写入,所以出现多条除了count其它都相同的信息,所以我们在count+1后再创建FileOutputStream,让它去覆盖


package cn.xushuai.io;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.util.Properties;public class RunCount {public static void main(String[] args) throws IOException {File file = new File("c:\\info.ini");if(!file.exists())try {file.createNewFile();} catch (IOException e) {throw new RuntimeException("创建文件失败");}int count =0;Properties prop = new Properties();FileInputStream fis = new FileInputStream(file);//在这里定义输出流,由于没有设为true,所以每次会覆盖源文件,//所以count只能在本次运行后+1,之后又被覆盖,所以总是1。//FileOutputStream fos = new FileOutputStream(file);try {prop.load(fis);String value = prop.getProperty("time");if(!(value == null))count = Integer.parseInt(value);if(count>5){System.out.println("试用期限已到,请到官网注册!");return ;}count++;//在count自增过后再创建,然后将count的新值覆盖旧值FileOutputStream fos = new FileOutputStream(file);prop.setProperty("time", count+"");prop.store(fos, "");} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

二、  打印流

该流提供了打印方法,可以将各种数据类型的数据都原样打印                                                                                       

字节打印流:PrintStream

字符打印流:PrintWriter

 

字节打印流PrintStream构造函数可以接收的参数类型

1,file对象。File

2,字符串路径。String

3,字节输出流。OutputStream

 

字符打印流PrintWriter构造函数可以接收的参数类型:

1,file对象。File

2,字符串路径。String

3,字节输出流。OutputStream

4,字符输出流,Writer

PrintWriter可以同时传入输出流对象和boolean值,以便实现自动刷


import java.io.*;class  PrintStreamDemo{public static void main(String[] args) throws IOException{BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);PrintWriter out2 = new PrintWriter(System.out,true);//打印到控制台,并自动刷新String line = null;while((line=bufr.readLine())!=null){if("over".equals(line))break;out2.println(line.toUpperCase());//out.flush();}out2.close();bufr.close();}}


三、 合并流SequenceInputStream

 

使用说明:

操作合并流的时候需要将操作的文件读取流封装成对象,存入集合中,然后进行写入,又因为SequenceInputStream接收一个Enumeration 类型的参数,而枚举类型只有在Vector中才有,所以只能使用Vector集合,通过elements方法获取枚举,传入SequenceInputStream。然后确定写入流,进行读写。

 

由于Vector效率低,所以用ArrayList替代,但要想得到枚举类型,可以利用迭代器,创建Enumeration对象,通过匿名内部类的方法实现Enumeration接口,并使用迭代器的方法覆盖其中的hasMoreElements和nextElement方法,然后确定写入流,进行读写。


文件的切割与合并示例代码:

import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.SequenceInputStream;import java.util.ArrayList;import java.util.Enumeration;import java.util.Iterator;public class SplitFileDemo {public static void main(String[] args) throws IOException {// TODO Auto-generated method stub//splitFile();merge();}public static void splitFile() throws IOException  {FileInputStream fis = new FileInputStream("c:\\1.mp3");FileOutputStream fos = null;byte[] buf = new byte[1024*1024];int len = 0;int count=1;while((len = fis.read(buf))!=-1){fos = new FileOutputStream("c:\\"+(count++)+".part");fos.write(buf,0,len);fos.close();}/*//应该让程序自动运行,而不是手动指定要切割多少次for(int i=1;i<13;i++){//FileOutputStream fos = new FileOutputStream("c:\\"+i+".part");while((len = fis.read(buf))!=-1){ fos = new FileOutputStream("c:\\"+(count++)+".part");//应该在外部定义,避免创建不需要的对象//FileOutputStream fos = new FileOutputStream("c:\\"+(count++)+".part");fos.write(buf,0,len);fos.close();System.out.println("......"+count);}}*/fis.close();}public static void merge() throws IOException{ArrayList<FileInputStream> al  = new ArrayList<FileInputStream>();for(int i=0;i<12;i++){al.add(new FileInputStream("c:\\"+i+".part"));}//通过Iterator来获取枚举方法final Iterator<FileInputStream> it = al.iterator();//通过内部类的形式来创建枚举Enumeration<FileInputStream> en = new Enumeration<FileInputStream>() {@Overridepublic boolean hasMoreElements() {//使用迭代器的方法来覆盖枚举的方法return it.hasNext();}@Overridepublic FileInputStream nextElement() {return it.next();}};SequenceInputStream sis = new SequenceInputStream(en);FileOutputStream fos  = new FileOutputStream("c:\\merge.mp3");int len=0;byte[] buf = new byte[1024];while((len=sis.read(buf))!=-1){fos.write(buf,0,len);}sis.close();fos.close();}}

四、对象的序列化,持久化对象

ObjectInputStream 

ObjectOutputStream

可以直接将对象持久的存入介质中,并读出,必须成对使用。


 使用注意事项:

1>进行序列化时需要继承Serializable,  以启用其序列化功能。(该序列化只能将堆内存中的数据序列化,序列号是根据类中的成员计算而得)

2>由于定义的类后期可能会进行修改,因此重新编译后会生成新的序列号,为了让原有类被序列化的数据可以继续使用,必须给类进行自定义标识,

该标识必须是静态,最终,长整型的 :static final long serialVersionUID = 42L;

3>静态不能够序列化,由于对象是在对内存中的。

4>对非静态成员也不想序列化,可以用transient修饰,保证其值在堆内存中存在而不在文本文件中存在。


示例代码:

import java.io.*;class Person implements Serializable{public static final long serialVersionUID = 42L;private String name;transient int age;static String country = "cn";Person(String name,int age,String country){this.name = name;this.age = age;this.country = country;}public String toString(){return name+":"+age+":"+country;}}import java.io.*;class ObjectStreamDemo {public static void main(String[] args) throws Exception{//writeObj();readObj();}public static void readObj()throws Exception{ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));Person p = (Person)ois.readObject();System.out.println(p);ois.close();}public static void writeObj()throws IOException{ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));oos.writeObject(new Person("lisi0",399,"kr"));oos.close();}}

五、管道流

PipedInputStreamPipedReader

PipedOutputStream  PipedWriter

可以直接将输入流与输出流连接,将流中的数据直接写入到读取端,必须结合多线程使用,因为单线程可能导致死锁。

 

管道流使用示例代码:

import java.io.*;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("piped lai la".getBytes());out.close();}catch (Exception e){throw new RuntimeException("管道输出流失败");}}}class  PipedStreamDemo{public static void main(String[] args) throws IOException{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();}}

六、操作基本数据类型的流对象 

DataInputStream

DataOutputStream

 

直接对基本数据类型进行操作,由于存入数据的类型可能不一致,所以读取时应注意顺序的一致,否则出现乱码

 

示例代码

import java.io.*;class DataStreamDemo {public static void main(String[] args) throws IOException{//writeData();//readData();//writeUTFDemo();//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");////osw.write("你好");//osw.close();//readUTFDemo();}public static void writeData()throws IOException{DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));dos.writeInt(234);dos.writeBoolean(true);dos.writeDouble(9887.543);dos.close();ObjectOutputStream oos = null;oos.writeObject(new O());}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();}//使用修改版的UTF-8写入,必须用相应的方式读取,用转换流读不出来public static void writeUTFDemo()throws IOException{DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));dos.writeUTF("你好");dos.close();}public static void readUTFDemo()throws IOException{DataInputStream dis = new DataInputStream(new FileInputStream("utf.txt"));String s = dis.readUTF();System.out.println(s);dis.close();}}


七、RandomAccessFile

   随机访问文件,自身具备读写的功能,只能操作文件。


使用说明:

 1>通过skipBytes(intx) ,seek(int x)来达到随机访问


2>该类不是IO中的子类,而是直接继承自Object,但是它是IO包中的成员,因为它  具备读和写的功能,内部封装了一个数组,而且通过指针对数组的元素进行操作,其完成读写的原理就是内部封装了字节输入流和输出流、


3>该类只能操作文件,而且还有操作模式,

如果模式为只读 r,不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常。

如果模式rw,操作的文件不存在,会自动创建,如果存则不会覆盖。


4>该类可以利用多线程实现分段写入,文件的下载就是此原理。


随机读取示例:

class RandomAccessFileDemo {public static void main(String[] args) throws IOException{//writeFile_2();//readFile();//System.out.println(Integer.toBinaryString(258));}//写入数据,同时移动指针public static void writeFile()throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");raf.write("李四".getBytes());raf.writeInt(97);raf.write("王五".getBytes());raf.writeInt(99);raf.close();}//可以任意修改数据public static void writeFile_2()throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");raf.seek(8*0);raf.write("周期".getBytes());raf.writeInt(103);raf.close();}//可以任意读取数据public static void readFile()throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt","r");//调整对象中指针。//raf.seek(8*1);//跳过指定的字节数raf.skipBytes(8);byte[] buf = new byte[4];raf.read(buf);String name = new String(buf);int age = raf.readInt();System.out.println("name="+name);System.out.println("age="+age);raf.close();}}

八、源和目的都是内存的IO类

用流的读写思想来操作数据

 

   操作字节数组      ByteArrayInputStream   ByteArrayOutputStream   

字符数组                    CharArrayReader      CharArrayWrite

      字符串                        StingReader                         StringWriter       

 

ByteArrayInputStream :

在构造的时候,需要接收数据源,而且数据源是一个字节数组

ByteArrayOutputStream:

在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地。


 注意:

因为这两个流对象都操作的数组,并没有使用系统资源, 所以,不用进行close关闭。


import java.io.*;class ByteArrayStream {public static void main(String[] args) {//数据源。ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());//数据目的ByteArrayOutputStream bos = new ByteArrayOutputStream();int by = 0;while((by=bis.read())!=-1){bos.write(by);}System.out.println(bos.size());System.out.println(bos.toString());//一次性地将数据写入文件//bos.writeTo(new FileOutputStream("a.txt"));}}


原创粉丝点击