JAVA I/O中面向字节的InputStream和OutputStream以及面向字符的Reader和Writer简介

转自:http://blog.csdn.net/kkdelta/article/details/7780998

Java的IO操作中有面向字节(Byte)和面向字符(Character)两种方式.
面向字节的操作为以8位为单位对二进制的数据进行操作,对数据不进行转换,这些类都是InputStream和OutputStream的子类.
面向字符的操作为以字符为单位对数据进行操作,在读的时候将二进制数据转为字符,在写的时候将字符转为二进制数据,这些类都是Reader和Writer的子类.
下面是JAVA示例代码:
  1. public class ByteCharStreamTest {      
  2.     private static void readBytes(BufferedInputStream bis,int buffSize) throws Exception{  
  3.         byte[] readBytes = new byte[buffSize];  
  4.           
  5.         int len;  
  6.         while((len=bis.read(readBytes)) !=-1){  
  7.             for(int i=0; i<len;i++){  
  8.                 System.out.print(readBytes[i] + " ");  
  9.             }  
  10.             System.out.println("-----one group --------");  
  11.         }  
  12.     }  
  13.       
  14.     public static void testInPutStream(String fileName) throws Exception {  
  15.   
  16.         File file = new File(fileName);  
  17.         FileInputStream fis = new FileInputStream(file);  
  18.         BufferedInputStream bis = new BufferedInputStream(fis);  
  19.           
  20.         readBytes(bis,10);  
  21.   
  22.         bis.close();  
  23.         fis.close();  
  24.     }  
  25.       
  26.     public static void testOutPutStream() throws Exception {  
  27.   
  28.         File file = new File("D:/temp/outpututf8");  
  29.         FileOutputStream fos = new FileOutputStream(file);  
  30.         BufferedOutputStream bos = new BufferedOutputStream(fos);  
  31.           
  32.         bos.write("abcdefg\r\n".getBytes("UTF-8"));  
  33.         bos.write("中\r\n".getBytes("UTF-8"));  
  34.         bos.write("1234567\r\n".getBytes("UTF-8"));  
  35.         bos.write("中".getBytes("UTF-8"));  
  36.   
  37.         bos.close();  
  38.         fos.close();  
  39.     }  
  40.     private static void readcharBychar(BufferedReader br ) throws Exception{  
  41.         char[] chbf = new char[10];  
  42.         int len;  
  43.         while ((len=br.read(chbf) )!= -1){  
  44.             for(int i=0;i<len;i++){  
  45.                 System.out.print(chbf[i]);  
  46.             }  
  47.               
  48.         }  
  49.     }  
  50.     private static void readcharLines(BufferedReader br ) throws Exception{  
  51.         String line;  
  52.         while ((line=br.readLine()) != null){  
  53.             System.out.println(line);  
  54.         }  
  55.     }  
  56.     public static void testInPutReader(String fileName,String charset) throws Exception {  
  57.   
  58.         File file = new File(fileName);  
  59.         FileInputStream fis = new FileInputStream(file);  
  60.         InputStreamReader fr = new InputStreamReader(fis,charset);  
  61.         BufferedReader br = new BufferedReader(fr);          
  62.         readcharBychar(br);  
  63.         //readcharLines(br);  
  64.         br.close();  
  65.         fr.close();  
  66.         fis.close();  
  67.     }  
  68.       
  69.     public static void testOutputWriter() throws Exception {  
  70.   
  71.         File file = new File("D:/temp/outputgb2312");  
  72.         FileOutputStream fos = new FileOutputStream(file);  
  73.         OutputStreamWriter fwr = new OutputStreamWriter(fos,"GB2312");          
  74.         BufferedWriter bwr = new BufferedWriter(fwr);  
  75.         bwr.write("abcdefg\r\n");  
  76.         bwr.write("中\r\n");  
  77.         bwr.write("1234567\r\n");  
  78.         bwr.write("中");  
  79.         bwr.close();  
  80.         fwr.close();  
  81.         fos.close();          
  82.     }  
  83.       
  84.     public static void main(String[] args) throws Exception {  
  85.         testInPutStream("C:/D/charset/gb2312.txt");  
  86.         //testOutPutStream();      
  87.         //testInPutReader();  
  88.         //testInPutReader("C:/D/charset/gb2312.txt","gb2312");  
  89.         //testOutputWriter();  
  90.         //testStreamSource();  
  91.     }  
  92. }  
public class ByteCharStreamTest {    
    private static void readBytes(BufferedInputStream bis,int buffSize) throws Exception{
        byte[] readBytes = new byte[buffSize];
        
        int len;
        while((len=bis.read(readBytes)) !=-1){
            for(int i=0; i<len;i++){
                System.out.print(readBytes[i] + " ");
            }
            System.out.println("-----one group --------");
        }
    }
    
    public static void testInPutStream(String fileName) throws Exception {

        File file = new File(fileName);
        FileInputStream fis = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fis);
        
        readBytes(bis,10);

        bis.close();
        fis.close();
    }
    
    public static void testOutPutStream() throws Exception {

        File file = new File("D:/temp/outpututf8");
        FileOutputStream fos = new FileOutputStream(file);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        
        bos.write("abcdefg\r\n".getBytes("UTF-8"));
        bos.write("中\r\n".getBytes("UTF-8"));
        bos.write("1234567\r\n".getBytes("UTF-8"));
        bos.write("中".getBytes("UTF-8"));

        bos.close();
        fos.close();
    }
    private static void readcharBychar(BufferedReader br ) throws Exception{
        char[] chbf = new char[10];
        int len;
        while ((len=br.read(chbf) )!= -1){
            for(int i=0;i<len;i++){
                System.out.print(chbf[i]);
            }
            
        }
    }
    private static void readcharLines(BufferedReader br ) throws Exception{
        String line;
        while ((line=br.readLine()) != null){
            System.out.println(line);
        }
    }
    public static void testInPutReader(String fileName,String charset) throws Exception {

        File file = new File(fileName);
        FileInputStream fis = new FileInputStream(file);
        InputStreamReader fr = new InputStreamReader(fis,charset);
        BufferedReader br = new BufferedReader(fr);        
        readcharBychar(br);
        //readcharLines(br);
        br.close();
        fr.close();
        fis.close();
    }
    
    public static void testOutputWriter() throws Exception {

        File file = new File("D:/temp/outputgb2312");
        FileOutputStream fos = new FileOutputStream(file);
        OutputStreamWriter fwr = new OutputStreamWriter(fos,"GB2312");        
        BufferedWriter bwr = new BufferedWriter(fwr);
        bwr.write("abcdefg\r\n");
        bwr.write("中\r\n");
        bwr.write("1234567\r\n");
        bwr.write("中");
        bwr.close();
        fwr.close();
        fos.close();        
    }
    
    public static void main(String[] args) throws Exception {
        testInPutStream("C:/D/charset/gb2312.txt");
        //testOutPutStream();    
        //testInPutReader();
        //testInPutReader("C:/D/charset/gb2312.txt","gb2312");
        //testOutputWriter();
        //testStreamSource();
    }
}
我们先来看对InputStream以字节流的方式处理,字节流的方式不需要指定编码,
操作的是8bit的字节.InputStream提供的read()方法返回的是这8bit代表的int值.
read(byte b[])将8bit的多个数据读入byte数组中.注意,同一个字节用int和byte表示的值是不同的.
byte的范围是-128到127,超过127的用负数表示.
如下面这个例子文件是UTF8的编码
  1. abcdefg  
  2. 中  
  3. 1234567  
  4. 中  
abcdefg
中
1234567
中


其16进制的表示如下:a的16进制表示为61,"中"的16进制为E4 B8 AD

运行testInPutStream输出如下:
97为a的10进制表示,16进制的61和10进制的97转为二进制是相等的.
"中"的10进制为228 184 173,用byte表示为-28 -72 -83.
  1. 97 98 99 100 101 102 103 13 10 -28 -----one group --------  
  2. -72 -83 13 10 49 50 51 52 53 54 -----one group --------  
  3. 55 13 10 228 184 173  
97 98 99 100 101 102 103 13 10 -28 -----one group --------
-72 -83 13 10 49 50 51 52 53 54 -----one group --------
55 13 10 228 184 173

InPutStream有以下的read方法.


OutPutStream输出的时候,能接收的是int,或者byte数组,然后将其以二进制的数据输出.

不要被本例的bos.write("中\r\n".getBytes("UTF-8"));所误导,这里指定编码是将"中"转成
以UTF8表示的byte数组.对同一个字符,不同的编码转换成的二进制数组可能是不一样的.
bos.write("中\r\n".getBytes("GB2312"));得到"中"的16进制表示为D6 D0.如下图,"中"在utf8中占用3个字节,在gb2312中占有两个字节.

InputStreamReader需要指定编码,reader安照编码将二进制的多个字节转成一个字符.

InputStreamReader有下面的一些read方法.


BufferedReader有下面的一些read方法.有支持按行读取的方法。

OutputStreamWriter安照指定编码将字符转成二进制数据保存.

OutputStreamWriter有下面的一些方法:


做JAVA IO操作的时候,我们通常都是将多个对象重叠在一起,提供自己期望的功能的.
通常是在Stream外套上一个Buffered类来提高IO效率和提供更方便的操作方法.
InputStream的作用是标志那些从不同起源地产生输入的类.这些起源地包括(每个都有一个相关的InputStream子类):
(1)字节数组:ByteArrayInputStream(byte buf[])
(2)String对象:StringBufferInputStream(String s)
(3)文件:FileInputStream(file)
(4)其他起源,如InputStream socketIn = socket.getInputStream();
OutputStream的作用是标志输出到不同的目的地.这些目的地包括(每个都有一个相关的OutputStream子类):
(1)字节数组:ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayOutputStream在内存中创建一个缓冲区.我们发送给流的所有数据都会置入这个缓冲区.
(2)文件:FileOutputStream(file)
(3)其他起源,如OutputStream socketOut = socket.getOutputStream();



io流分为两大类,字节流和字符流。
字节流:OutputStream、InputStream
字符流:Writer、Reader

所有的文件在硬盘或在传输时都是以字节的方式进行的,包括图片等都是按字节的方式存储的,而字符是只有在内存中才会形成,所以开发中字节流使用比较广泛

可以参考java api文档
public class FileOutputStream extends OutputStream
文件输出流是用于将数据写入 File 或 FileDescriptor 
的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 
FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。

public class FileWriter extends OutputStreamWriter
用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 
上构造一个 OutputStreamWriter。
文件是否可用或是否可以被创建取决于底层平台。特别是某些平台一次只允许一个 
FileWriter(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
FileWriter 用于写入字符流。要写入原始字节流,请考虑使用 FileOutputStream。 

public class BufferedOutputStream extends FilterOutputStream
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统


因为需要把在线的apk文件下载到本地,一上来就使用了FileWriter的方式进行文件写入,结果发现下载到本地的apk会提示安装包损坏,经过排查,原来FileWriter是使用的字符写入的方式,而可执行的apk实际是二进制文件,这样在字节读取,字符写入的时候文件显然也发生了变化,明显的差异就是文件大小变成了两倍

这里总结一下,我常用的文件写入的方法有三种:FileOutputStream、BufferedOutputStream、FileWriter,前两种都是字节写入。那么这三种方法的差异有什么呢?这篇文章大致比较了这三种方法的性能差异:http://xiaofan-0204.iteye.com/blog/1317668 。

FileWriter代码示例:

  1. public String GetMergedMap(String buildurl, String typeregx,  
  2.     String contentregx, String localfile) {  
  3.     ArrayList<String> urls = new ArrayList<String>();  
  4.     urls = getLinkURL(buildurl, typeregx);  
  5.   
  6.     File local = new File(localfile);  
  7.     if (local.exists()) {  
  8.         local.delete();  
  9.     }  
  10.     try {  
  11.         local.createNewFile();  
  12.         FileWriter fw = new FileWriter(localfile);  
  13.         OkHttpClient httpclient = new OkHttpClient();  
  14.         Request request;  
  15.   
  16.         for (int i = 0; i < urls.size(); i++) {  
  17.             String url = urls.get(i);  
  18.             logger.info("{}""下载:" + url);  
  19.             request = new Request.Builder().url(url).build();  
  20.             Response response = httpclient.newCall(request).execute();  
  21.             if (response.isSuccessful()) {  
  22.                 InputStream is = response.body().byteStream();  
  23.                 BufferedReader br = new BufferedReader(  
  24.                         new InputStreamReader(is));  
  25.                 String line;  
  26.                 while ((line = br.readLine()) != null) {  
  27.                     if (line.matches(contentregx)) {  
  28.                         fw.append(line + "\r\n");  
  29.                         fw.flush();  
  30.                     }  
  31.                 }  
  32.             } else {  
  33.                 logger.error("{}""请求失败 " + response.headers().get("code"));  
  34.                 System.exit(0);  
  35.             }  
  36.   
  37.         }  
  38.         fw.close();  
  39.     } catch (IOException e) {  
  40.         // TODO Auto-generated catch block  
  41.         logger.error("{}""map文件下载失败");  
  42.     }  
  43.     finally {  
  44.         logger.error("{}""全部下载完毕");  
  45.         return localfile;  
  46.     }  
  47. }  
	public String GetMergedMap(String buildurl, String typeregx,
		String contentregx, String localfile) {
		ArrayList<String> urls = new ArrayList<String>();
		urls = getLinkURL(buildurl, typeregx);

		File local = new File(localfile);
		if (local.exists()) {
			local.delete();
		}
		try {
			local.createNewFile();
			FileWriter fw = new FileWriter(localfile);
			OkHttpClient httpclient = new OkHttpClient();
			Request request;

			for (int i = 0; i < urls.size(); i++) {
				String url = urls.get(i);
				logger.info("{}", "下载:" + url);
				request = new Request.Builder().url(url).build();
				Response response = httpclient.newCall(request).execute();
				if (response.isSuccessful()) {
					InputStream is = response.body().byteStream();
					BufferedReader br = new BufferedReader(
							new InputStreamReader(is));
					String line;
					while ((line = br.readLine()) != null) {
						if (line.matches(contentregx)) {
							fw.append(line + "\r\n");
							fw.flush();
						}
					}
				} else {
					logger.error("{}", "请求失败 " + response.headers().get("code"));
					System.exit(0);
				}

			}
			fw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			logger.error("{}", "map文件下载失败");
		}
		finally {
			logger.error("{}", "全部下载完毕");
			return localfile;
		}
	}

FileOutputStream代码示例:

  1. <span style="white-space:pre">    </span>public String downloadApkOnline(String url, String localfile) {  
  2.         File local = new File(localfile);  
  3.         if (local.exists()) {  
  4.             local.delete();  
  5.         }  
  6.         try {  
  7.             local.createNewFile();  
  8.             int chByte = 0;  
  9.             OkHttpClient httpclient = new OkHttpClient();  
  10.             Request request = new Request.Builder().url(url).build();  
  11.             Response response = httpclient.newCall(request).execute();  
  12.   
  13.             InputStream is = response.body().byteStream();  
  14.             chByte =  is.read();  
  15.   
  16.             FileOutputStream fos = new FileOutputStream(localfile);  
  17.             while(chByte != -1)  
  18.             {  
  19.                 fos.write(chByte);  
  20.                 chByte =  is.read();  
  21.             }  
  22.             fos.flush();  
  23.             fos.close();  
  24.             is.close();  
  25.         } catch (IOException e) {  
  26.             // TODO Auto-generated catch block  
  27.             logger.error("{}""下载失败");  
  28.         } finally {  
  29.             return localfile;  
  30.         }  
  31.     }  
<span style="white-space:pre">	</span>public String downloadApkOnline(String url, String localfile) {
		File local = new File(localfile);
		if (local.exists()) {
			local.delete();
		}
		try {
			local.createNewFile();
			int chByte = 0;
			OkHttpClient httpclient = new OkHttpClient();
			Request request = new Request.Builder().url(url).build();
			Response response = httpclient.newCall(request).execute();

			InputStream is = response.body().byteStream();
			chByte =  is.read();

			FileOutputStream fos = new FileOutputStream(localfile);
			while(chByte != -1)
			{
				fos.write(chByte);
				chByte =  is.read();
			}
			fos.flush();
			fos.close();
			is.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			logger.error("{}", "下载失败");
		} finally {
			return localfile;
		}
	}

BufferedOutputStream代码示例:

  1. <span style="white-space:pre">    </span>public String  downloadApkByBuffer(String url, String localfile)  
  2.     {  
  3.         File local = new File(localfile);  
  4.         if (local.exists()) {  
  5.             local.delete();  
  6.         }  
  7.         try {  
  8.             local.createNewFile();  
  9.             int chByte = 0;  
  10.             OkHttpClient httpclient = new OkHttpClient();  
  11.             Request request = new Request.Builder().url(url).build();  
  12.             Response response = httpclient.newCall(request).execute();  
  13.   
  14.             InputStream is = response.body().byteStream();  
  15.             chByte =  is.read();  
  16.   
  17.             FileOutputStream fos = new FileOutputStream(localfile);  
  18.             BufferedOutputStream bos = new BufferedOutputStream(fos);  
  19.             while(chByte != -1)  
  20.             {  
  21.                 bos.write(chByte);  
  22.                 chByte =  is.read();  
  23.             }  
  24.             bos.flush();  
  25.             bos.close();  
  26.             fos.close();  
  27.             is.close();  
  28.         } catch (IOException e) {  
  29.             // TODO Auto-generated catch block  
  30.             logger.error("{}""下载失败");  
  31.         } finally {  
  32.             return localfile;  
  33.         }  
  34.     }  

很多人刚学习程序流一章的时候,就是搞不清楚In和Out,不知道什么时候用in什么时候用out,所以一部分人采取死记硬背的方式,诸如如下这位:

BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("infilename")));
不管你从磁盘读,从网络读,或者从键盘读,读到内存,就是InputStream

写文件
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("outfilename")));
不管你写倒磁盘,写到网络,或者写到屏幕,都是OuputStream。


那么有什么好方法不用背就能记住呢,即使是反应稍微慢点,但是绝对不会错的方法呢?

好吧,那我就来说说,老程序员可以关闭该页面了!

我们所说的流,都是针对内存说的,比如为什么打印到屏幕上就是System.out.println();而从屏幕等待用户输入的却是System.in呢?因为对于内存来说,把字符串打印到屏幕上是从内存流向屏幕这个显示器的,也就是输出,而从屏幕等待用户输入呢?就是等待键盘将字符输入到内存中。

所以,你根本就不用死记硬背,当你遇到IO的时候,就想两件事,第一,我的内存是中心,第二看看流的方向(矢量)!

好吧,那么往硬盘上写文件是out还是in呢?别一看到“写”文件你就说in,那是望文生义,你看,写文件的流向,是 内存---------->硬盘 内存为中心,到硬盘,OK 用out 那么就是FileOutputStream、BufferedOutputStream 等等
那读文件呢?是 内存<---------------硬盘 那么就是in了 , 看清楚数据的流向就OK!

那我访问网络,看网页是什么呢 网络--------------->内存 是in 因为我们访问页面是要抓取该页面得一个html文件,那我要是在网络上输入帐号密码登陆呢? 是不是内存的东西要写到该服务器上呢,所以当然是out了!

同样socket编程用到更多的IO,这里分别用Server(服务器端)和Client(客户端)来说明

Server: 遇到请求,网络----->内存 IN   服务器应答, 内存------->网络 OUT
----------------------------------------------------------------------------------------------
Client: 请求服务,    内存----->网络 OUT 服务器应答, 网络------->内存 IN

被搞糊涂了?那么你先别想太多,只是想是内存的数据出去了就是out 外设的东西到内存了就IN了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值