J2SE知识点归纳笔记(七)---Java IO Part 3:基本字节流

J2SE知识点归纳笔记(七)---Java IO Part 3:基本字节流

                                                                ——转载请注明出处:coder-pig

本节引言:

在上一节中我们学习了控制台输入数据的方法以及对Java IO流体系图进行了初步的了解,

在本节中我们针对性地学习一些基本字节流与字符流的使用~开始本节内容:

1.InputStream与OutputStream的相关方法:

首先要说一点的是:这两个类是抽象类,通过子类来实现各种功能;

数据单位为字节(1 byte = 8bit);下面是相关的方法:

1)InputStream的相关方法:

①public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值;

若返回值=-1说明没有读取到任何字节读取工作结束。

②public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。

如果流位于文件末尾不在有数据可用,返回-1;等同于read(b,0,b.length)

③public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中,

如果流位于文件末尾不在有数据可用,返回-1;

④public int available( ):返回输入流中可以读取的字节数

ps:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,

这个方法必须由继承InputStream类的子类对象调用才有用

⑤public int close( ):使用完毕后,关闭流

⑥public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数,跳过一些字节来读取

⑦public void mark(int readlimit):在此输入流中标记当前位置,如果后续调用reset方法会在最后标记的位置重新定位

此流,以便后续读取重新读取相同的字节,另外参数:readlimit代表:标记失效钱允许读取的字节数

ps:jdk 1.6后貌似没限制多少个字节~

⑧public void reset( ):将流重新定位到最后一次调用mark方法的位置!

⑨public boolean markSupported( ):判断该输入流是否支持mark和reset方法

ps:这里的mark和reset方法,你们可能不是很明白,后面学习BufferedInputStream的时候,

会给大家写个例子,到时你就知道这两个玩意的作用了...

还有,虽然read有三种不同的构造方法,但是建议使用后面两个,第一个少用!!!

2)OutputStream的相关方法:

①public void close( ):关闭此输出流并释放与此流有关的所有系统资源

②public void flush( ):刷新此输出流并强制写出所有缓冲的输出字节

③public abstract void write(int b):将指定的字节写入此输出流

public void write(byte[] b):
b.length个字节从指定的byte数组写入此输出流

⑤public void write(byte[] b,int off,int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流

ps:其实这些方法,直接查文档都可以查出来的,笔者也是贴的api上的解析而已~

    所以遇到不会用,没见过的方法,先查文档~

2.FileInputStream与FileOutputStream类的使用:

先来介绍字节流的第一个子类:ileInputStream与FileOutputStream类吧!

见名知意:就是以字节的形式对文件进行读写操作;

这里就不贴相关方法了,自行查阅API文档吧,直接上实例:

代码实例:实现文件复制

/*
	 * 该方法用于复制文件,是最简单的,没有加入缓冲机制,所以很垃圾~只是方便读者理解
	 * 参数以此是:被复制文件的完整路径,以及复制后生成的文件的完整路径
	 * */
	public static void copyFile1(String file1,String file2) throws IOException
	{
		File file = new File(file1);
		File outfile = new File(file2);
		FileInputStream inputStream = new FileInputStream(file);
		FileOutputStream outputStream = new FileOutputStream(outfile);
		int i = 0;
		while(i != -1) {
			i = inputStream.read();
			outputStream.write(i);
		}
		//记得关闭流
		inputStream.close();
		outputStream.close();
	}

运行截图:

好了,上述的代码,如果复制的是大文件,就呵呵了,等死你...所以我们需要加入缓冲区,

以便提高文件的复制速度,就是添加一个字节缓冲数组而已~

代码也很简单:

/*
	 * 该方法在1的基础上,添加了byte[]数组缓冲机制,复制大文件的时候,他的优势就显现出来了~
	 */
	public static void copyFile2(String file1, String file2) throws IOException {
		File file = new File(file1);
		File outfile = new File(file2);
		FileInputStream inputStream = new FileInputStream(file);
		FileOutputStream outputStream = new FileOutputStream(outfile);
		int i = 0;
		//设置缓冲的字节数组为缓冲512 byte
		byte[] buffer = new byte[512];
		while (true) {
			if (inputStream.available() < 512) {
				while (i != -1) {
					i = inputStream.read();
					outputStream.write(i);
				}
				break;
			} else {
				// 当文件的大小大于512 byte时
				inputStream.read(buffer);
				outputStream.write(buffer);
			}
		}
		// 记得关闭流
		inputStream.close();
		outputStream.close();
	}

代码解析:

就是添加一个512byte的字符数组,但是速度却明显提高了,不信么?

你可以找个大文件试试,比如笔者这里用的美图秀秀,差不多30M,用1中的

方法,过了差不多1分多钟才复制完毕,而用加了缓冲的几秒钟就复制好了~

3)ByteArrayInputStream与ByteArrayOutputStream类的使用:

见名知意:字节数组的字节流,创建实例是程序内部会创建一个byte型数组的缓冲区,

在网络传输的时候用的比较多,这里给获得某个页面的网页源代码~

ByteArrayOutputStream用得比较多,另外toByteArray( )方法很常用

你也可以自行扩展,比如,访问的url是图片,然后把图片保存到本地~

代码实例:

/*
	 * 获得某个网页源代码:
	 * 参数是一个网页的链接:
	 * */
	public static String getHtml(String path)throws Exception
	{
		URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		conn.setRequestMethod("GET");
		if(conn.getResponseCode() == 200)
		{
			InputStream in = conn.getInputStream();
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len = 0;
			while((len = in.read(buffer)) != -1)
			{
				out.write(buffer,0,len);
			}
			in.close();
			byte[] data = out.toByteArray();
			String html = new String(data,"UTF-8");
			return html;
		}
		return null;
	}

运行截图:

好了,这样就读取到一个网页的源代码了~

4)ObjectInputStream与ObjectOutputStream类

见名知意,对象字节流,就是可以直接把对象转换为流,另外,转换的对象对应的类,

需要实现Serializable接口,另外对象中的transient和static类型成员变量不会被读取和写入

下面我们来写个简单的代码示例:

step 1:定义一个业务Bean:

import java.io.Serializable;

public class Book implements Serializable {
	private String bName;
	private String bReporter;

	public Book(String bName, String bReporter) {
		super();
		this.bName = bName;
		this.bReporter = bReporter;
	}

	public String getbName() {
		return bName;
	}

	public void setbName(String bName) {
		this.bName = bName;
	}

	public String getbReporter() {
		return bReporter;
	}

	public void setbReporter(String bReporter) {
		this.bReporter = bReporter;
	}

}

step 2:先构造低级流FileOutputStream和FileInputStream,然后才能使用

ObjectOutputStream与ObjectInputStream:

public static void main(String[] args) throws Exception {
		Book b1 = new Book("《如何与傻B相处》", "猪小猪");
		Book b2 = new Book("《逗比的自我修养》", "猫小猫");
		Book b3,b4;
		//注意:使用高级流需要先构造低级流
		//①把对象直接写入到文件中
		FileOutputStream fout = new FileOutputStream("D:/books.txt");
		ObjectOutputStream out = new ObjectOutputStream(fout);
		out.writeObject(b1);
		out.writeObject(b2);
		//关闭输出流
		out.close();
		//②读取文件中的对象:
		FileInputStream fin=new FileInputStream("D:/books.txt");
		ObjectInputStream in=new ObjectInputStream(fin);
	    b3=(Book) in.readObject();
	    b4=(Book) in.readObject();
	    //关闭输入流
	    in.close();
	    System.out.println(b3.getbName() + " 作者: "+ b3.getbReporter());
	    System.out.println(b4.getbName() + " 作者: "+ b4.getbReporter());
	}

运行截图:

同时,我们可以在D盘下看到这个book.txt的文件,但是打开后是乱码,

这是因为,我们写入的是字节流~中文就会出现乱码,如果想解决这种情况,

可以使用后面会说的FileWriter和FileReader~

5)PipedOutputStream与PipedInputStream类

这个是管道流,相比起前面的介绍的几个流,这个就稍微复杂点了,

通过这两个流可以让多线程通过管道进行线程间的通讯,两者需要搭配使用哦!

不同于Linux和Unix系统中的管道,他们是不同地址空间空间的两个进程可以通过管道通信,

Java中则是运行在同一进程中的不同线程!

原理:PipedInputStream内部有一个Buffer,使用InputStream的方法读取其Buffer中的字节;

而Buffer中的字节是PipedOutputStream调用PipedInputStream的方法放入的;

另外,不建议把这两个流对应的对象写在同一线程中,不然很容易引起死锁,

使用connect( )方法可以将这个管道搭建起来,再进行数据传输~

这里找了个简单的小例子给大家体会下吧~

1)SendThread.java:(输出流)

import java.io.IOException;
import java.io.PipedOutputStream;

public class SendThread extends Thread{
	private PipedOutputStream out = new PipedOutputStream();
	public PipedOutputStream getOutputStream(){
        return out;
    }
	public void run(){
	        String strInfo = "我是PipedOutputStream写入的东西" ;
	        try {
	            out.write(strInfo.getBytes());
	            out.close();
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	    }
}

2)ReceiverThread.java:(输入流)

import java.io.IOException;
import java.io.PipedInputStream;

public class ReceiverThread extends Thread {
	private PipedInputStream in = new PipedInputStream();

	public PipedInputStream getInputStream() {
		return in;
	}

	public void run() {
		byte[] buf = new byte[1024];
		try {
			int len = in.read(buf);
			System.out.println(new String(buf, 0, len));
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

测试类:Test5.java:

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class Test5 {
	public static void main(String[] args) {
		ReceiverThread rThread = new ReceiverThread();
		SendThread sThread = new SendThread();
		// 获取对应流:
		PipedOutputStream out = sThread.getOutputStream();
		PipedInputStream in = rThread.getInputStream();
		try {
			// 管道链接
			out.connect(in);
			sThread.start();
			rThread.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

运行截图:

6)SequenceInputStream合并流:

见名知意,就是合并多个输入流.即当我们需要从多个输入流中向程序读入数据的时候可以考虑使用合并流,

SequenceInputStream会将与之相连接的流集组合成一个输入流并从第一个输入流开始读取,

直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止;

合并流的作用是将多个源合并合一个源!

要注意的地方:(构造方法)

SequenceInputStream为我们提供了两个不同的构造方法:

1~SequenceInputStream(Enumeration<? extends InputStream> e)

2~SequenceInputStream(InputStream s1, InputStream s2)

PS:这个Enumertaion是一个接口,Enumeration接口定义了从一个数据结构得到连续数据的手段

该接口提供的两个方法:

boolean hasMoreElements():测试此枚举是否包含更多的元素。 

nextElement( ):如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素.

这里并不详细介绍Enumertaion了,想了解的自行查阅文档~

那么接下来我们来写两个简单的小程序方便我们理解:

①使用两个流作为参数的构造方法:

	public static void main(String[] args) throws IOException {
        InputStream s1 = new ByteArrayInputStream("ABC".getBytes());
        InputStream s2 = new ByteArrayInputStream("abc".getBytes());
        InputStream in = new SequenceInputStream(s1, s2);
        int data;
        while ((data = in.read()) != -1) {
            System.out.println(data);
        }
        in.close();
    }  

运行结果:(对应ABCabc的ASCII码值,别问我为什么不用汉字,因为本节讲的是字节流,一个汉字两个字节~)

②使用Enumeration作为参数的那个构造方法:

public static void main(String[] args) throws IOException {
		 //创建合并流
        SequenceInputStream sin = null;
        //创建输出流
        BufferedOutputStream bout = null;
        try {
            //构建流集合
            Vector<InputStream> vector = new Vector<InputStream>();
            vector.addElement(new FileInputStream("D:\\test1.txt"));
            vector.addElement(new FileInputStream("D:\\test2.txt"));
            vector.addElement(new FileInputStream("D:\\test3.txt"));
            vector.addElement(new FileInputStream("D:\\test4.txt"));
            Enumeration<InputStream> e = vector.elements();  

            sin = new SequenceInputStream(e);
            bout = new BufferedOutputStream(
                    new FileOutputStream("D:\\textUnion.txt"));  

            //读写数据
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = sin.read(buf)) != -1) {
                bout.write(buf, 0, len);
                bout.flush();
            }
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } finally {
            try {
                if (sin != null)
                    sin.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (bout != null)
                    bout.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }  

接着我们在D盘目录下创建:test1,test2,test3,test4四个txt文件,内容依次为:

逗A,逗B,逗C,逗D

运行截图:

会在D盘下生产testUnion.txt的文件,打开文件后可以看到:

最后说两句:

好的,关于Java IO中的基本字节流就讲到这里了,现在我们来回顾下本节讲解的东东:

①InputStream和OutputStream两个父类的相关方法

②FileInputStream与FileOutputStream类文件读写类的使用,加入了缓冲数组提高了读写效率~

③ByteArrayInputStream与ByteArrayOutputStream类字节数组类,我们写了个获取网页源码的例子:

④ObjectInputStream与ObjectOutputStream类对象读写类,我们通过这两个类可以很方便地完成

从对象到流,流到对象的转化,另外要注意一点,这个对象所属的类要继承Serializable接口!

⑤PipedOutputStream与PipedInputStream类管道输入输出类,这两个是用于线程间进行通信的,

一般避免把这两个写到同一个线程中,不然很容易引起死锁,本节只是给出一个简单的应用例子,后续有

需要再进行深入研究~

⑥SequenceInputStream合并流,就是可以将多个输入流合并成一个输入流,有两种构造形式:

分别是两个输入流,或者一个Enumeration参数,也很简单,大家看懂例子即可~

那么,关于本节的基本字节流就到这里,谢谢你的阅读~

如果你觉得本文可以的话,可花1s点个赞,让更多的朋友可以看到这篇文章~万分感谢~

时间: 2024-10-13 18:37:24

J2SE知识点归纳笔记(七)---Java IO Part 3:基本字节流的相关文章

J2SE知识点归纳笔记(七)---Java IO Part 1:File类与RandomAccessFile类

J2SE知识点归纳笔记(七)---Java IO Part 1:File类与RandomAccessFile类                                                                 --转载请注明出处:coder-pig 本节引言: 兜兜转转,又回来写Java了,上一篇J2SE知识点归纳笔记(六)---Java常用类是上2014.4.14写的,时隔一年 又来重拾之前还没写完的系列了,前些天群里一个妹子反映她Java基础薄弱,然后抱怨在cs

J2SE知识点归纳笔记(七)---Java IO Part 4:基本字符流

J2SE知识点归纳笔记(七)---Java IO Part 4:基本字符流                                                                 --转载请注明出处:coder-pig 本节引言: 上一节中,我们对于Java IO流中的一些基本字节流进行了学习,他们都是InputStream与 OutputStream的子类;本节学习的字符流则是Reader与Writer的子类,好了,话不多说, 开始本节内容! 本节正文: 1.Reade

J2SE知识点归纳笔记(七)---Java IO Part 2:获取键盘输入与IO流体系图

J2SE知识点归纳笔记(七)---Java IO Part 2:获取键盘输入与IO流体系图                                                                 --转载请注明出处:coder-pig 本节引言: 好了,上一节中我们给大家介绍了File与RandomAccessFile类的用法,本节我们还是讲一些 常用的东西,如果学过C++或者C的朋友都知道,获取键盘的输入都很简单,scanf( )和cin就可以 获得我们从控制台输入的参

Java学习笔记-7.Java IO流

一.输入/输出流 1.流:不同类型的输入.输出源    数据流:输入或输出的数据 Java数据流的所有接口和类都是在java.io包中定义的,因此应在程序开头加入 import java.io.* 2.流的分类: (1)从流的流动方向来看,可以将IO流分为输入流和输出流 输入流:数据信息从某个地方流向程序中 输出流:数据信息从程序中发送到某个目的地 (2)从流的数据处理单位来看,可以将IO流分为字节流和字符流 字节流:以字节方式处理的二进制数据 字符流:以字符方式处理的数据流(Java使用Uni

【学习笔记】java IO编程2

类 InputStream 此抽象类是表示字节输入流的所有类的超类. 需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法. 注意红色部分 举个例子: package com.study2; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Inpu

Java IO字符流与字节流

一.基本概念 流:从一端流向另一端,从源头到目的地. 始终与程序为中心,都是程序与文件|数组|网络连接|数据库进行操作. 二.IO流分类 1.流向: 输入流和输出流 2.数据: 字节流:二进制,可以处理文本文件,视频,音频等 . 字符流:文本文件,只能处理纯文本,全款为可见字符(.txt..html). 3.功能: 节点:包裹源头 处理:增强功能,提高性能. 三.字节流与字符流 1.字节流 输入流:InputStream int read(byte[] b) int read(byte[] b,

Java基础学习笔记七 Java基础语法之继承和抽象类

继承 继承的概念 在现实生活中,继承一般指的是子女继承父辈的财产.在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系. 例如公司中的研发部员工和维护部员工都属于员工,程序中便可以描述为研发部员工和维护部员工继承自员工,同理,JavaEE工程师和Android工程师继承自研发部员工,而维网络维护工程师和硬件维护工程师继承自维护部员工.这些员工之间会形成一个继承体系,具体如下图所示. 在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称

利用java.io.File类实现遍历本地磁盘上指定盘符或文件夹的所有的文件

2016-11-18 这是本人的第一篇随笔博客,纠结了半天还是选择自己学的时候比较用心的一些知识点上.利用java.io.File类指定本地的文件夹进行遍历所有的文件. package org.lxm.filedemo; import java.io.File; import java.util.Scanner; /* * 本程序是将某个盘的所有文件夹及其文件全部调出来的操作 */ public class FileAllDemo { public static void main(String

java.io 字节流与字符流及简单实例

java io是java中非常基础的知识点,对于通信和不涉及到数据库的项目java io应该是要经常使用.java io分为字节流和字符流,分清字节流和字符流的异同是掌握java io的起点. 字节流,最小单位是字节,通信协议中的X-MODEM和Y-MODEM协议传输单位就是字节流.java io中与字节流相关的主要类有:InputStream,OutputStream,FileInputStream,FileOutputStream.与字符流有关的主要类有:Writer,Reader,File