一、Android中文件读写的原理
(1).所有文件的储存都是字节的储存。 (2).在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。
(3).在读取文件(特别是文本文件)时,也是一个字节一个字节的读取以形成字节序列。
二、I/O流概念
Input Output Stream:流是一种抽象概念,它代表了数据的无结构化传递,以流的方式进行输入输出。
抽象到具体,文件在程序中是以流的形式来操作的。
流:是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两个存储位置之间的传输称为流。
流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
三、流的分类
1、按照流向划分:输入流、输出流
以磁盘为参照:
输入流:从文件流向内存
输出流:从内存流向文件
2、按照传输单位划分:字节流、字符流
字节流:以字节为单位向stream中写入或者从stream中读取。一般的二进制数据都使用字节流,比如声音和图像等
字符流:可以用于读写文本文件。
四、字节流和字符流的区别和联系
1、字节和字符概述:
字节:是由8个二进制数组成,也就是8个0或一组成。
字符:字符的大小由实际的编码规则有关,比如在GBK中一个汉字由2个字节组成,而在utf-8中一个汉字由3个或者4个字节组成。
2、字节流和字符流联系:
字符流的由来: 因为数据编码的不同,从而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。
3、区别
1)、读写单位不同:字节流以字节(1 byte,1byte=8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
2)、处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
3)、缓存。字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件。
总结:优先选用字节流。因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
4、字节输入输出流的层次结构图:
字节流抽象父类:InputStream、OutputStream
输入流/输出的结构图如下:
基于上图介绍几个比较常用的输入输出流。
1).inputStream:输入流,获取从外部传入数据源,inputStream类是抽象类,不能够创建对象,需要通过子类来实现。比较常见的方法如下:
(1)public abstract int read( ):Reads the next byte of data from the input stream,return the next byte of data, or <code>-1</code> if the end of the stream is reached.
(2)public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的
(3)public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。
(4)public int available( ):返回输入流中可以读取的字节数。注意:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用,
(5)public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取
(6)public int close( ) :使用完后,必须对打开的流进行关闭.
2).outputStream:输出流,和inputStream一样,也是抽象类。比较常用的方法:
(1). public void write(byte b[ ]):将参数b中的字节写到输出流。
(2). public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。
(3). public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。
(4). public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。
(5). public void close( ) : 关闭输出流并释放与流相关的系统资源。
3)FileInputStream: inputStream类的子类,被称为文件字节输入流,意思指对文件数据以字节的形式进行读取操作如读取图片视频等。常用方法:
//1、得到数据文件 File file = new File( "D:/1.txt"); //2、建立数据通道 FileInputStream fInputStream = new FileInputStream(file); byte[] buf = new byte[1024]; int length = 0; //循环读取文件内容,输入流中将最多buf.length个字节的数据读入一个buf数组中,返回类型是读取到的字节数。 //当文件读取到结尾时返回 -1,循环结束。 while((length = fInputStream.read(buf)) != -1){ System.out.print(new String(buf,0,length)); } //最后记得,关闭流 fInputStream.close();
4)FileOutputStream:用来处理输出地的Stream。常用的方法:
File f=new File("d:/abc.txt"); FileOutputStream out=new FileOutputStream (f);
5)BufferedInputStream继承于FilterInputStream,提供缓冲输入流功能。
缓冲输入流相对于普通输入流的优势是,它提供了一个缓冲数组,每次调用read方法的时候,
它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,
最后再将缓冲区中的内容部分或全部返回给用户.由于从缓冲区里读取数据远比直接从物理数据源(譬如文件)读取速度快。
BufferedInputStream,BufferedOutputStream:允许程序在不降低系统性能的情况下一次一个字节的从流中读取或者写入数据
BufferInputstream定义了两种构造函数
a. BufferInputStream b= new BufferInputstream(in);
b. BufferInputStream b=new BufferInputStream(in,size)
第二个参数表示指定缓冲器的大小。
同样BufferOutputStream也有两种构造函数。一次一个字节的向流中写数据。
6)ObjectInputStream:继承于InputStream。
它和一个InputStream相关联,源数据来自于这个InputStream。但它和传入的InputStream并不是直接关联的,
中间通过了BlockDataInputStream进行中转,要关注的就是它的readObject方法,
它会把一个之前序列化过的对象进行反序列化,然后得到一个Object对象,它的目的在于将(把二进制流转换成为对象)和
(从某个数据源中读出字节流)这两个操作独立开来,让它们可以随意地组合。
五、 字符流
1)字符输出流:Writer
字符适合于处理中文数据,Writer是字符输出流的处理类,这个类的定义如下:
public abstract class Writer implements Appendable, Closeable, Flushable
通过Writer实现输出的例子:
File file=new File("E:test.txt"); Writer out=new FileWriter(file,true); out.write("今天天气真好!"); out.close();
字符串输入流:Reader
Reader类的read()方法用于从流中读取单个字符。
2)字符输入输出流的层次结构图: