黑马程序员_IO流(三)

来源:互联网 发布:java nestedinteger 编辑:程序博客网 时间:2024/05/21 10:15

-------- ASP.Net+Unity开发、.Net培训、期待与您交流! -----------

IO流(三)

PipedOutputStream/PipedIutputStream和PipedWriter/PipedReader(管道流)

前面说到读取流的时候,读取流和写入流之间没有直接的关系,它们之间需要一个数组或者字符串来进行数据之间的传输,管道就解决了读取流和写入流没有直接关系的局面,管道流可以将读取流和写入流接在一起,一边读取,一遍写入。那就要面临一个问题,是读取先还是写入先?由于它们之间的关系就像一根管子,所以要用到多线程执行读取和写,不然会照成死锁(因为read()是一个阻塞方法)。

管道流的一些特性:

可以将连个流直接关联在一起,形如:PipedInputStream(PipedOutputStream src)在管道输入流中通过参数直接关联到管道输出流,也可以通过connect(PipedOutputStream)方法进行连接。下面的实例启用了两个线程来跑管道流的读取和写入,使用connect的方法将两者连接起来,

实例理解:

package cn.itheima.IO;import java.io.FileInputStream;import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutputStream;class PipedInOut {/** * @param args */public static void main(String[] args) throws Exception{// TODO Auto-generated method stubPipedInputStream pis =new PipedInputStream();PipedOutputStream pos = new PipedOutputStream();pis.connect(pos);new Thread(new myread(pis)).start();new Thread(new myWriter(pos)).start();}}class  myread implements Runnable{PipedInputStream pis =null;myread(PipedInputStream pis){this.pis=pis;}@Overridepublic void run(){// TODO Auto-generated method stubbyte[] b= new byte[1024];int len=0;try {len=pis.read(b);System.out.println("数据写入管道");System.out.println("等待数据写入。。。。。。");System.out.println("收到的数据位:"+(new String(b,0,len)));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {pis.close();} catch (IOException e) {// TODO Auto-generated catch blockthrow new RuntimeException("管道写入流错误");}}}}class myWriter implements Runnable{PipedOutputStream pos =null;myWriter(PipedOutputStream pos){this.pos = pos;}@Overridepublic void run() {// TODO Auto-generated method stubbyte[] str = "黑马程序员".getBytes();try {Thread.sleep(7000);pos.write(str);}catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {pos.close();} catch (IOException e) {// TODO Auto-generated catch blockthrow new RuntimeException("管道写入流失败");}}}}


RandomAccessFile:

随机访问文件的读取,读、取一体,不属于IO类的继承类,直接继承Object类,但是他却是IO包中的成员,因为他具备了读和写的方法,内部封装了一个数组,可以通过指针获取数组里面的值,可以通过可以通过seek改变指针的位置。通过getFielPionter获取指针的位置。其内部完成读写的操作就是底部封装了读取流和写入流的功能,通过构造函数可知,该流对象只能操作文件,而且操作文件还有模式也就是:"r""rw""rws""rwd"写错了就报错。如果模式为"r",会去读一个已经存在的文件,文件不存在报告异常,模式里带有”w“,操作的文件不存在,则自动创建,如果存在,不覆盖

了解该类的方法:

read(int a):获取a的最低8位

readInt(int a):获取a的整数值32位

seek(int a):指针向前移动a个字节,a可为负值

sikpByte(int a):向前跳a个字节,只能向前,不能向后

package cn.itheima.IO;import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;public class RandomAccessFileDemo {/** * @param args * @throws Exception  */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubmyWriter();myRead();}private static void myRead() throws IOException {// TODO Auto-generated method stubRandomAccessFile raf = new RandomAccessFile("test.txt", "r");//跳转指针去读数据//raf.seek(8);try {byte[] buf = new byte[4];int len = raf.read(buf);String str = new String(buf,0,len);System.out.println(str);int n = raf.readInt();System.out.println(n);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}raf.close();}private static void myWriter() throws FileNotFoundException, IOException {RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");raf.write("王五".getBytes());raf.writeInt(12);raf.write("李四".getBytes());raf.writeInt(55);raf.close();}}

ByteArrayInputStream/ByteArrayOutputStream

ByteArrayInputStream:其内包括了一个内部缓冲区,关联到源,将源中的数据存入自己的内部缓冲区,关联的是源而已,没有调用底层资源,所以关闭流是无效的(关闭后任然可以调用,也不会产生任何异常)。在构造的时候需要接受数据源,且数据源是一个字节数组,

ByteArrayOutputStream:数据被写入字节数组,缓冲区会随着字节数据的增长而增长,且不用flush,也不涉及底层资源操作,也就不需关闭流。在构造的时候不要定义目的,因为在封装的时候就已近封装了一个可变长的数组,实际上这个数组就是该流的目的。(使用流的思想来操作数组)

实例:

package cn.itheima.IO;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;public class ByteArrayInOut {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stub    ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".getBytes());        ByteArrayOutputStream bos = new ByteArrayOutputStream();    int len = 0 ;    while((len=bis.read())!=-1){    bos.write(len);    }    System.out.println(bos);}}

相对应的有CharArrayReader/CharArrayWriter:操作字符与StringReader/StringWriter操作字符串,不做详细介绍


字节编码:

关于转换流的的字符编码,就是在进行流的操作的时候指定了固定的编码,在编码和解码是也指定了固定的编码表,有什么编码表编的码就得用什么编码表去解,不然就会得到乱码,就那UTF-8和GBK来说,当向转换流中写入数据的时候,指定的编码是UTF-8,但是在编码的时候指定的GBK,则得到的将会是乱码,反之亦然。原因:使用UTF-8编码,一个字符将会有三个字节表示,也就是说在UTF-8中三个字节表示一个字符,但是在GBK中表示一个字符的只是两个字节,解码的时候如果去查GBK,原本在UTF-8中表示一个字符的三个字节在GBK中只需用到两个就可以表示一个字符,GBK码表拿到两个字节去查询GBK码表,得到的将和UTF-8中的自然不一样。所以说使用什么样的编码表去编码就得使用什么样的编码表去解码,以免出现乱码。

下面的实例是使用GBK编码,使用UTF-8解码导致的结果:

package cn.itheima.IO;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.UnsupportedEncodingException;public class UnicodeDemo {/** * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubOut();In();}private static void In() throws UnsupportedEncodingException, FileNotFoundException {// TODO Auto-generated method stubInputStreamReader isr =new InputStreamReader(new FileInputStream("test.txt"), "UTF-8");char[] buf =new char[50];int len =0 ;try {len = isr.read(buf);String str = new String(buf,0,len);System.out.println(str);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {isr.close();} catch (IOException e) {// TODO Auto-generated catch blockthrow new RuntimeException("读取失败");}}}private static void Out() throws UnsupportedEncodingException,FileNotFoundException, IOException {OutputStreamWriter osw =newOutputStreamWriter(new FileOutputStream("test.txt"), "GBK");osw.write("黑马程序员");osw.write(97);osw.close();}//运行结果:????????a}

如果想要得到正确的字符,则需要将解码使用的编码改变成为GBK编码,

注意:

如果在使用GBK编码的,而使用的ISO-8859解码,得到的也是乱码,如果想在不改变编码的情况下得到正确的结果,只需把得到的字符再进行一次ISO-8859编码,最后使用GBK解码即可得到正确的结果,原理:ISO-8859解码是一个字节代表一个字符,也就是说它会把GBK编的码一个一个地去查询ISO-8859编码,当然不会改变这些字节地大小,将他再次进行一编码,得到的字节码还是原来GBK所编的码,使用GBK解码当然能得到正确的结果,但是GBK和UTF-8就不一样,比如说只有一个字符,使用GBK编码就只会产生两个字节,但是使用UTF-8解码就需要三个字节,那么UTF-8就会去查询相似的结果,也就会把字节变为三个,就算再用UTF-8编码,GBk解码也不能得到原来的结果了。




-------- ASP.Net+Unity开发、.Net培训、期待与您交流! -----------

0 0
原创粉丝点击