zoukankan      html  css  js  c++  java
  • Java_IO流

    这篇我们聊一聊java中的IO流。

    什么是流呢?流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流。流的本质是数据的传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

    IO流的分类

    根据处理数据类型的不同分为:字符流和字节流;

    根据数据流向不同分为:输入流和输出流。

    字符流和字节流

    字符流的由来:因为数据编码的不同,而有了对字符进行高效操作的对象。本质其实就是基于字节流读取时,去查了指定的码表。

    字节流与字符流的区别:

    1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可以读多个字节;

    2)处理对象不同:字节流能处理所有类别的对象(如图片、avi等),而字符流只能处理字符类型的数据;

    3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作;而字符流在操作的时候是会用到缓冲区的,是通过缓冲区来操作文件。

    结论:尽可能使用字节流。硬盘上所有文件都是以字节的形式进行传输或保存的,字符只是在内存中才会形成的,所以在开发中,字节流使用更广泛。

    输入输出流

    对输入流只能进行读操作,对输出流只能进行写操作。程序中需要根据传输数据的不同特性而使用不同的流。

    java流 体系统:

     

    首先我们先看下常用的几个类:

    1、输入字节流——InputStream

    从上面的体系图我们可以看出来,InputStream是所有输入字节流的父类,它是一个抽象类。

    BufferedInputStream、FileInputStream是InputStream常用的子类。

    1)FileInputStream:文件字节输入流,一切文件在系统中都是以字节的形式保存的,无论你是文档文件。视频文件、音频文件...这些文件都可以用FileInputStream去读取其保存在存储介质(磁盘等)上的字节序列。FileInputStream在创建时通过把文件名作为构造参数连接到该文件的内容字节,建立起字节流传输通道。

    然后通过read(),read(byte[]),read(byte[],int begin,int len)三种方法从字节流中读取一个字节,一组字节。

    2)BufferedInputStream:带缓冲的字节流,上面我们知道文件字节输入流读取的时候,是直接同字节流中读取的。由于字节流是与硬件(存储介质)进行的读取,所以速度较慢。CPU需要使用数据时通过read().read(byte[])读取数据时就要受到硬件IO的限制。而且,CPU与内存之间的读写速度比硬件IO快了不止十倍,所以,优化读写的思路就有了。在内存中建立缓冲区,先把存储介质中的字节读取到缓冲区中。CPU需要数据时直接从缓冲区读就行了,缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。

    BufferedInputStream内部有一个缓冲区,默认大小为8M,每次调用read()方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区,最后再将缓冲区中的内容返回个用户,由于从缓冲区中读取数据远比直接从存储介质读取速度快,所以BufferedInputStream的效率很高。

    一个栗子:

    public class Test03 {
    	public static void main(String[] args) throws IOException {
    		String fileName = "D:"+File.separator+"c.txt";
    		File file = new File(fileName);
    		InputStream in = null;
    		if(!file.exists()){
    			file.createNewFile();
    		}
    		try {
    			in = new FileInputStream(file);
    			byte[] b = new byte[(int) file.length()];
    			in.read(b);
    			System.out.println("文件长度为:"+file.length());
    			System.out.println(new String(b));
    		} catch (IOException e) {
    			e.printStackTrace();
    		}finally{
    			in.close();
    		}
    	}
    }
    

     2、输出字节流——OutputStream

    从上面的体系图我们可以看出来,OutputStream是所有输出字节流的父类,它是一个抽象类。

    ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向byte数组,和本地文件中写入数据。

    一个栗子:

    //向文件中一个字节一个字节写入字符串 
    public class Test07 {
    	public static void main(String[] args) throws IOException {
    		String fileName = "D:"+File.separator+"bb.txt";
    		File file = new File(fileName);
    		if(!file.exists()){
    			try {
    				file.createNewFile();
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		OutputStream out = null;
    		try {
    			out = new FileOutputStream(file);
    			String str = "Hello Stream !!";
    			byte[] b = str.getBytes();
    			for(int i=0;i<b.length;i++){
    				out.write(b[i]);
    			}
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			out.close();
    		}
    	}
    }
    

     

    3、字符输入流——Reader

    从上面的体系图我们可以看出来,Reader是所有字符输入流的父类,它是一个抽象类。

    CharReader,StringReader是两种基本的介质流,它们分别从char数组,String数组中读取数据。

    一个栗子:

    //字符流——循环方式从文件中读取内容
    public class Test11 {
    	public static void main(String[] args) throws IOException {
    		String fileName = "D:"+File.separator+"bb.txt";
    		File file = new File(fileName);
    		char[] ch = new char[100];
    		Reader reader = new FileReader(file);
    		int temp = 0;
    		int count = 0;
    		while((temp=reader.read())!=-1){
    			ch[count++]=(char)temp;
    		}
    		reader.close();
    		System.out.println("内容为:"+ new String(ch,0,count));
    	}
    }
    

     

    4、字符输出流——Writer

    从上面的体系图我们可以看出来,Writer是所有输出字符流的父类,它是一个抽象类。

    CharArrayWriter,StringWriter是两种基本的介质流,它们分别向Char数组,String中写入对象。

    一个栗子:

    //字符流——写入数据
    public class Test12 {
    	public static void main(String[] args) throws IOException {
    		String fileName = "D:"+File.separator+"cc.txt";
    		File file = new File(fileName);
    		Writer writer = new FileWriter(file);
    		String str = "Hello R";
    		writer.write(str);
    		writer.close();
    	}
    }
    

     

    5、字符流与字节流转换:

    转换流的特点:

    1)是字符流与字节流之间的桥梁;

    2)可对读取到的字节数据经过指定编码转换成字符;

    3)可对读取到的字符数据经过指定编码转换成字节。

    何时使用转换流?

    当字节和字符之间有转换动作时;

    流操作的数据需要编码或解码时。

    具体的对象体现?

    InputStreamReader:字节到字符的桥梁;

    OutputStreamWriter:字符到字节的桥梁。

    这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

    字节输出流转换为字符输出流栗子:

    public class Test13 {
    	public static void main(String[] args) throws IOException {
    		String fileName = "D:"+File.separator+"aa.txt";
    		File file = new File(fileName);
    		Writer out = new OutputStreamWriter(new FileOutputStream(file));
    		out.write("HHHBBB");
    		out.close();
    	}
    }
    

     字节输入流转换为字符输入流栗子:

    public class Test14 {
    	public static void main(String[] args) throws IOException {
    		String fileName = "D:"+File.separator+"bb.txt";
    		File file = new File(fileName);
    		Reader reader = new InputStreamReader(new FileInputStream(file));
    		char[] ch = new char[100];
    		int len = reader.read(ch);
    		System.out.println(new String(ch,0,len));
    		reader.close();
    	}
    }
    

     

    File类:

    常见方法:

    1)创建一个文件:file.createNewFile();

    2)删除一个文件:file.delete();

    3)创建一个文件夹:file.mkdir();

    4)列出目录下的所有文件:file.list(),filelistFiles();

    一个栗子:

    //list()列出的不是完整路径
    public class Test15 {
    	public static void main(String[] args) {
    		String fileName = "D:"+File.separator+"Resources";
    		File file = new File(fileName);
    		String[] str = file.list();
    		for(int i = 0;i < str.length;i++){
    			System.out.println(str[i]);
    		}
    	}
    }
    
    //listFiles()可列出指定目录下所有文件完整路径
    public class Test16 {
    	public static void main(String[] args) {
    		String fileName = "D:"+File.separator+"Resources";
    		File file = new File(fileName);
    		File[] f = file.listFiles();
    		for(int i=0;i<f.length;i++){
    			System.out.println(f[i]);
    		}
    				
    	}
    }
    

     5)判断一个指定路径是否为目录:isDirectory;

    RandomAccessFile类:

    该对象并不是流体系的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。

    特点:该对象只能操作文件,所以构造函数接收两种类型的参数:字符串文件路径;File对象。

    该对象既可以对文件进行读操作,也可以进行写操作,在进行对象实例化时可指定操作模式(r,rw)。

    注意:该对象实例化时,如果操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有内容。可以用于多线程下载会多个线程同时写数据到文件。

    一个栗子:

    public class Test17 {
    	public static void main(String[] args) throws IOException {
    		String fileName = "D:"+File.separatorChar+"aa.txt";
    		File file = new File(fileName);
    		RandomAccessFile raf = new RandomAccessFile(file,"rw");
    		raf.writeBoolean(true);
    		raf.writeBytes("abc");
    		raf.writeChar('A');
    		raf.writeFloat(3.14f);
    		raf.writeDouble(6.128);
    		raf.close();
    	}
    }
    

     

    参考时光孤岛博文:https://www.cnblogs.com/QQ846300233/p/6046388.html

     

  • 相关阅读:
    Jeecms之查询实现
    JEECMS站群管理系统-- 自定义标签及使用自己创建的表的实现过程
    jeecms 修改后台访问路径
    Jeecms6中后台控制层Action如何将值传入前台视图层模板中的?
    原 JEECMS导入IDEA进行二次开发图文教程
    自己动手编写JEECMS自定义栏目统计标签
    深入浅出 Java Concurrency (8): 加锁的原理 (Lock.lock)
    深入浅出 Java Concurrency (7): 锁机制 part 2 AQS
    深入浅出 Java Concurrency (6): 锁机制 part 1 Lock与ReentrantLock
    深入浅出 Java Concurrency (5): 原子操作 part 4 CAS操作
  • 原文地址:https://www.cnblogs.com/Rain1203/p/10770018.html
Copyright © 2011-2022 走看看