java学习之IO流总结

1.IO体系的框架图

我们先来介绍一下IO体系的整体框架图

接下来,我们首先开始流式部分的介绍。

2.流的基本概念

一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。

输入流:程序从输入流读取数据源。数据源包括外界(键盘、文件、网络…),即是将数据源读入到程序的通信通道。

输出流:程序向输出流写入数据。将程序中的数据输出到外界(显示器、打印机、文件、网络…)的通信通道。

采用数据流的目的就是使得输出输入独立于设备。

3.java中的字节流和字符流

Java 流在处理上分为字符流字节流。字符流处理的单元为2个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组()。

Java内用Unicode编码存储字符,字符流处理类负责将外部的其他编码的字符流和java内 Unicode字符流之间的转换。而类InputStreamReaderOutputStreamWriter处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。 

字节流是最基本的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的。但实际中很多的数据是文本,又提出了字符流(ReaderWriter)的概念(常用的),它是按虚拟机的encode来处理,也就是要进行字节到字符集的转化。实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。

(1)字节流

InputStream 和OutputStream是两个abstact 类,对于字节为导向的stream都扩展这两个。即二进制,他们的扩展类如下:

下面我们具体举例说明他们的使用,以文件字节流的读写为例。

文件的写操作(字节流的形式)

public static void main(String[] args) throws Exception {
		//第一步:创建文件
		File f=new File("d:"+File.pathSeparator+"test.txt");
		
		//第二步:通过子类实例化父类对象 
		//通过FileOutputStream实例化OutputStream对象
		//true表示可以追加
		OutputStream out=null;   //准备好一个输出对象
		out=new FileOutputStream(f,true);  //通过对象多态性进行实例化,
		
		//第三步:进行读写操作
		//1.准备一个字符串,其中\r\n 起到换行作用
		String str="\r\n qzp 1991";
		//2.将字符串变成字节数组(因为是字节流嘛)
		byte b[]=str.getBytes();
		
		//将内容输出,保存文件
		out.write(b);
		    /**
			* 也可以使用字节一个一个循环输出。
			* for(int i=0;i<b.length;i++){ 
			*	out.write(b[i]);
			* }
		*/
		//第四步:关闭输出流
		out.close();
	}

运行以后d盘中会创建test.txt这样一个文件,并且里面保存了字符串的内容。

文件的读操作(字节流的形式)

public static void main(String[] args) throws Exception {
		//第一步:找到需要操作的文件名
		File f=new File("d:"+File.pathSeparator+"test.txt");
		
		//第二步:通过子类实例化父类对象
		InputStream input=new FileInputStream(f);
		
		//第三步:进行读操作,将需要读入的内容放入此数组中
		byte b[]=new byte[1024];
		//设置一个临时变量,存放输入流,
//当输入流不为空时,都读入,为空时则不读,节省资源
		int temp=0;
		int len=0;
		while((temp=input.read())!=-1){
			b[len]=(byte)temp;
			len++;
		}
				
		//第四步:关闭输入流
		input.close();
		System.out.println("字节数组的长度"+len);
		//输出文件中的内容。限制了len以后,不会有多余的空格输出
		System.out.println("内容为"+new String(b,0,len));		
	}

运行后会打印如下语句

字节数组的长度34

内容为qzp 1991qzp 1991qzp 1991

qzp 1991

(2)字符流

Reader/Writer 为 abstact 类,以Unicode字符为导向的 stream ,表示以Unicode字符为单位从stream中读取或往stream中写入信息。java中一个字符等于二个字节。

下面还是以文件的写为例,此操作与字节流的读写操作差不多,只是返回的结果是一个字符,不是字节,可以直接输出,不比再转化。

public static void main(String[] args) throws IOException {
		//第一步:创建文件
		File f=new File("d:"+File.pathSeparator+"test.txt");
				
		//第二步:通过子类实例化父类对象
		Writer out=null;
		out=new FileWriter(f,true);
				
		//第三步:进行读写操作
		//1.准备一个字符串
		String str="\r\nqzp 1991";
		//2.将字符串变成字节数组(因为是字节流嘛)
		out.write(str);
								
		//第四步:关闭输出流
		out.close();
	}


(3)字节流和字符流的比较

[1]  字节流返回的是字节,最好还是要转化成字符,便于操作输出;字符流返回的是字符

[2]  字节流操作不会用到缓冲区(内存),是文件的本身操作;而字符流使用时用到了缓冲区,通过缓冲区在操作文件。字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

那到底实际开发中用字符流还是字节流呢?首先,文件在硬盘中的传输是以字节的方式进行的,包括图片也是按照字节方式(二进制)存储的,而字符只有在内存中才会形成,所以,实际开发中字节用的更多。

(4)字节流与字符流的转换

InputStreamReader和OutputStreamReader :

把一个以字节为导向的stream转换成一个以字符为导向的 stream 。

InputStreamReader 类是Reader的子类,是从字节流到字符流的桥梁:它读入字节,并根据指定的编码方式,将之转换为字符流。

使用的编码方式可能由名称指定,或平台可接受的缺省编码方式。

InputStreamReader 的 read() 方法之一的每次调用,可能促使从基本字节输入流中读取一个或多个字节。

为了达到更高效率,考虑用 BufferedReader 封装 InputStreamReader ,

BufferedReader in = new BufferedReader(newInputStreamReader(System.in));

例子说明:

        <p><strong><span style="color:#7F0055;">public </span><span style="color:#7F0055;">static</span><span style="color:#7F0055;"> void</span></strong><span style="color:black;"> main(String[] args) {</span></p><p><span style="color:black;">       </span>BufferedReaderbuf=<strong><span style="color:#7F0055;">null</span></strong><span style="color:black;">;</span></p><p><span style="color:black;">       </span>//<span style="color:black;">实例化</span><span style="color:black;">bufferedReader,</span><span style="color:black;">并接受其内容</span></p><p><span style="color:black;">      //此处将输入的字节流转化为字符流,然后存放到BufferedReader之中
</span></p><p><span style="color:black;">       </span>buf=<strong><span style="color:#7F0055;">new</span></strong><span style="color:black;"> BufferedReader(</span><strong><span style="color:#7F0055;">new</span></strong><span style="color:black;"> InputStreamReader(System.</span><em><span style="color:#0000C0;">in</span></em><span style="color:black;">));</span></p><p><span style="color:black;">       </span></p><p><span style="color:black;">       </span>String str=<strong><span style="color:#7F0055;">null</span></strong><span style="color:black;">;</span></p><p><span style="color:black;">       </span>System.<em><span style="color:#0000C0;">out</span></em><span style="color:black;">.println(</span><span style="color:#2A00FF;">"</span><span style="color:#2A00FF;">请输入字符串:</span><span style="color:#2A00FF;">"</span><span style="color:black;">);</span></p><p><span style="color:black;">       </span></p><p><span style="color:black;">       </span><strong><span style="color:#7F0055;">try</span></strong><span style="color:black;"> {</span></p><p><span style="color:black;">           </span>str=buf.readLine();</p><p><span style="color:black;">       </span>}<strong><span style="color:#7F0055;">catch</span></strong><span style="color:black;"> (IOException e) {</span></p><p><span style="color:black;">           </span>e.printStackTrace();</p><p><span style="color:black;">       </span>}</p><p><span style="color:black;">       </span>System.<em><span style="color:#0000C0;">out</span></em><span style="color:black;">.println(</span><span style="color:#2A00FF;">"</span><span style="color:#2A00FF;">输入的内容是</span><span style="color:#2A00FF;">"</span><span style="color:black;">+str);</span></p><p>}</p>

运行结果:

  请输入字符串:

  qzp

   输入的内容是qzp

(5)url读写

url读写调用网页的api必将成为一个重要的研究方向,因而获取网站的url地址是从网站调用API的第一步,以下是将url地址从字节流转化为字符流的过程。从而方便程序中以字符串获取url的值。

public static String httpRequest(String requestUrl) {  
        StringBuffer buffer = new StringBuffer();  
        try {  
            URL url = new URL(requestUrl);  
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();  
  
            httpUrlConn.setDoOutput(false);  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setUseCaches(false);  
  
            httpUrlConn.setRequestMethod("GET");  
            httpUrlConn.connect();  
  
            // 将返回的输入流转换成字符串    很重要将字节流转化为字符流
            InputStream inputStream = httpUrlConn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
  
            String str = null;  
            while ((str = bufferedReader.readLine())!= null) {  
                buffer.append(str);  
            }  
            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源  
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();  
  
        } catch (Exception e) {  
        }  
        return buffer.toString();  
    }  

(6)装饰模式

以文件读写的例子为引子,我们进行具体的研究

public class Test
{
    public static void main(String[] args)
    {
        try {
           BufferedReader br = new BufferedReader(new FileReader("file.txt")); 
           String line = br.readLine();
           while (line != null) {
               System.out.println(line);
               line = br.readLine();
            }
           br.close();
        }
        catch(IOException e) {
            System.out.println("IO Problem");
        }
    }
}

其中BufferedReader br = new BufferedReader(newFileReader("file.txt"));

BufferedReader()是一个装饰器(decorator), 它接收一个原始的对象,并返回一个经过装饰的、功能更复杂的对象。修饰器的好处是,它可以用于修饰不同的对象。我们这里被修饰的是从文件中读取的文本流。 其他的文本流,比如标准输入,网络传输的流等等,都可以被BufferedReader()修饰,从而实现缓存读取。

3.非流式的文件操作

在整个IO包中,唯一一个与文件本身相关的就是File类,使用File类可以进行文件创建、删除等操作,构造方法:

File f=new File(“D:\\test.txt”);

File f=new File(“D:”+ File.separator +“test.txt”);

 

注:使用File.separator代替\\,这样有利于在多个不同的操作系统中进行扩展。因为在Linux中使用//作为文件分隔符,而windows中则是\\。

File类还有一些其他的常用方法,可以参考帮助文档,此处不再罗列。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值