----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
1、字节流
针对的字节数据,包括文本也包括媒体数据,如果是纯文本用字符流处理较为便捷。基本操作与字符流相同
字节流所使用的缓冲区是一个byte[]。
常用的对象:
FileInputStream:用来读取文件的字节流
read()方法可以一次读取一个字节
read(byte[])方法可以一次读取若干字节到数组中
FileOutputStream:用来写出文件的字节流
write(int)方法可以一次写出一个字节
write(byte[], int, int)方法可以一次写出数组中的一部分数据
BufferedInputStream:字节流的输入缓冲区
BufferedOutputStream:字节流的输出缓冲区
字节流的缓冲区:
同样是提高了字节流的读写效率。
模拟BufferedInputStream原理:
将一个字节数组进行封装,通过方法将一批数据存入数组中,再通过数组的指针每一次返回数组中一个字节。
当数组元素全部取出后,在存入一批新的数据,重复此过程。
当使用自定义的缓冲区时,居然出现的秒杀的情况,为什么会如此呢?
因为mp3数据最终的二进制表现形式中,很容易出现连续N多1的情况,
只要出现了连续的8个1,对于一个字节而言十进制体现形式就是-1。
那么就满足while循环结束条件。程序终止。
为了避免这种情况,在读到一个字节时,将该字节进行了提升变成int型。
但是byte-1,变成int 还是-1。为了避免,在进行提升的过程中,保留的源字节的8为数据,并在前以补零方式进行提升。
这样一个byte -1 变成了int 的255。这就避免了-1的情况。
如何补的零呢?只要将读到的字节&255或者&0xFF.都可以。这也是read方法不是返回byte而返回int类型的原因。
通过该过程就可以明确,read方法在对字节或者字符进行提升,而write方法在对提升后的int数据进行强转,
只写出了最低的8位,或者最低的16位
2、转换流:
为了实现字符和字节流之间的转换,出现了转换流。
InputStramReader:字节通向字符的桥梁
OutputStreamWriter:字符通向字节的桥梁
转换流的由来:
当读到的字节数据都是纯文本的时候,而且文本中出现中文字符,那么在解析该字节数据时就需要指定编码表。
因为可以识别中的编码表不唯一。在使用转换流时,如果未指定编码表,那么默认使用本地码表。
转换流的应用:
字节流中的数据都是字符时,转成字符流操作更高效。
3、标准输入输出流:
System类中的成员变量:in,out。
它们各代表了系统标准的输入和输出设备。
默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream。
System.out的类型是PrintStream,是OutputStream子类FilterOutputStream的子类。
carriage return 回车; line feed 换行
标准输入输出流示例:
例:获取键盘录入数据,然后将数据流向显示器,那么显示器就是目的地。
通过System类的setIn,setOut方法对默认设备进行改变。
System.setIn(new FileInputStream(“1.txt”));//将源改成文件1.txt。
System.setOut(new FileOutputStream(“2.txt”));//将目的改成文件2.txt
因为是字节流处理的是文本数据,可以转换成字符流,操作更方便。
BfferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
4、流基本应用小节:
流是用来处理数据的。
处理数据时,一定要先明确数据源,与数据目的地(数据汇)。
数据源可以是文件,可以是键盘。
数据目的地可以是文件、显示器或者其他设备。
而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理.转换处理等
流操作的基本规律:
a.明确数据源和数据目的:使用输入流还是输出流。
b.明确要处理的数据是否是纯文本:使用字符流还是字节流。
当明确体系后,到底该用该体系的哪个对象呢?
根据数据存在的设备而定,
数据源所在设备可以是,硬盘,键盘,内存。
数据目的所在设备可以是,硬盘,控制台,内存。
需求:获取键盘录入,将录入信息存储到本地文件中。
分析:
源:键盘录入,使用输入流。
处理的数据:纯文本,使用字符输入流Reader
使用对象:键盘录入System.in完成的。那么它是一个标准的字节输入流。InputStream。
为了操作文本数据方便,将字节流转换成字符流:使用InputStreamReader。为了提高效率使用BufferedReader.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
目的:本地文件(硬盘)输出流。
处理的数据:纯文本,字符输出流。Writer。
使用对象:可以操作的文件FileWriter对象。为了提高写入流的效率。BufferedWriter.
需求:获取本地文本数据,将数据息存储到本地另一个文件中,按照UTF-8的编码形式。
分析:
源:硬盘,输入流。
处理的数据:纯文本,字符输入流,Read。
使用对象:因为是文件FileReader为了提高效率BufferedReader.
目的:本地文件(硬盘)输出流。
处理的数据:纯文本,字符输出流。Writer。
使用对象:可以操作的文件的对象,但是要制定码表再进行存储, 需要使用转换流OutputStreamWriter。
将字符转成字节。而转换流要接收的对象都是字节流对象,所以要使用可以操作File的
FileOutputStream。为了提高写入流的效率使用BufferedWriter.
5、File类
用来将文件或者文件夹路径封装成对象
方便对文件与文件夹进行操作。
File对象可以作为参数传递给流的构造函数。
File类中的常用方法:
创建:
createNewFile(): 创建文件,如果指定目录下已有要创建文件,那么不进行覆盖,通过返回值来确定是否创建成功。
输出流也可以创建文件,但是如果文件已存在,会出现覆盖。
mkdir():创建单级目录。
mkdirs():创建多级目录。
删除:
boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
void deleteOnExit();在程序退出时删除指定文件。
判断:
booleanexsits():判断文件或者文件夹是否存在。
isFile():在判断一个文件对象封装的是否是文件或者文件夹,必须要先明确该文件是存在的。
isDirectory():
isHidden():
isAbsolute():
获取信息:
getName();
getPath();
getParent():返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。
getAbsolutePath():
long length():
static File[] listRoots():列出当前机器有效的盘符。
String[] list():获取指定目录的当前所有文件或者文件夹的名称。
String[] list(FilenameFilter filter):可以通过指定的条件对数据进行过滤。
File[] listFiles():返回的是当前目录下所有文件或者文件夹对应的file对象。
跨平台的目录分隔符:separator File f = new File("c:"+File.separator+"a.txt");
6、递归:函数自己调用自己。
注意:递归时一定要明确限定条件以及控制调用次数,以免出现内存溢出。
应用场景:当某一功能要重复使用时,但是操作的未知内容不同
public static void listAll(File dir) {
System.out.println(dir.getName());
File[] files = dir.listFiles();
for(int x=0;x <files.length; x++) {
if(files[x].isDirectory())
listAll(files[x]);
else
System.out.println(files[x].getName());
}
}
7、IO包中的其它类
序列流:SequenceInputStream
可以将多个字节输入流整合成一个流,操作多文件数据较为方便。在使用这个流读取的时候,读到第一个流
的末尾时继续读第二个,第二个读到末尾则继续读第三个,以此类推,直到读到最后一个流的末尾返回-1。
它的构造函数有两个:一个可以将两个流合并成一个流。一个可以将枚举Enumeration中的流对象合并一个流。
通常获取Enumeration是通过Vector的elements方法来完成。但是Vector效率较低,所以该用ArrayList。
操作对象:ObjectOutputStream与ObjectInputStream:
特点:可以用流直接操作Object.将对象冲对内存存储到了硬盘上,称为对象的本地持久化。
注意:被操作的Object 必须实现一个标记接口Serializable,该接口中没有方法。该接口用来给类进行UID指定。
通过ObjectInputStream的readObject方法,获取存储的对象。
通过ObjectOutputStream的writeObject方法。来完成对象的持久化。
注意:static的成员,还有非静态但被transient关键字所修饰,该属性的对象特有值不会进行持久化存储。
这两个对象在构造的时候都需要传入一个字节流进行。
打印流:PrintStream 、PrintWriter
字节打印流(PrintStream):System.out对应的类型就是PrintStream。
该类构造函数可以接收三种类型的参数:File、String name、OutputStream
前两者在传递参数时,可以指定字符编码。 后者传递参数是,可以指定是否自动刷新。
字符打印流:PrintWriter。
该类构造函数可以接收四种类型的参数:File、String name、OutputStream、Writer
前两者在传递参数时,可以指定字符编码。后两者传递参数时,可以指定是否自动刷新。
该自动刷新动作,只有println,printf,format方法来完成。
该打印流较为常用。在日后学习javaweb中,在进行往客户端应答的时候通过response既可以
获取PrintWriter对象,通过将html数据打印到客户端,客户端通过浏览器进行数据解析并展现页面效果。
PrintWriter out =
new PrintWrite(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),"UTF-8")));
相比普通的OutputStream和Writer增加了print()和println()方法,这两个方法可以输出实参对象的
toString()方法返回值。这两个类还提供自动flush()的功能
操作内存缓冲数组:ByteArrayInputStream与ByteArrayOutputStream
这两个流中的子类对象,并没有调用底层资源。所以关闭方法close是无效的。数据源和数据目的都是内存。
操作字节数组中的元素只要通过指针的偏移即可,封装成对象其实是通过流的读写思想完成了数组操作
ByteArrayInputStream:可以从一个字节数组中读取字节。
ByteArrayOutputStream: 写出到字节数组(内存)中,可以获取写出的内容装入一个字节数组。通常
我们用这个流来缓冲数据。
CharArrayReader:可以从一个字符数组中读取字符。
CharArrayWriter:写出字符到字符数组(内存)中,可以获取写出的内容装入一个字符数组。
StringReader 与 StringWriter:操作字符串,原理和ByteArrayInputStream ByteArrayOutputStream相同。
管道流:
PipedInputStream:管道输入流,可以从管道输出流中读取数据
PipedOutputStream:管道输出流,可以向管道输入流中写出数据
特点:读取流和写入流可以进行连接。通过这两个流对象构造函数,或者通过两个流对象connect方法。
通常都需要结合多线程进行引用。
操作基本数据类型:DataInputStream与DataOutputStream
可以按照基本数据类型占用空间大小读写数据,专门用于操作基本数据类型。如:writeInt(),readInt().
writeUTF(),,readUTF();所使用的utf是utf-8修改版。通过writeUTF()写入的数据,必须通过readUTF()获取。
随机访问文件:RandomAccessFile,封装了字节流。
特点:可以对数据进行读和写的操作。通过构造函数的第二个参数模式来区分读写。r rw。
好处:对于规则的数据可以通过指针的偏移进行随机的数据获取。
方法 :seek(),skipBytes(),getFilePointer().
注意:如果在指定位置写入数据,该位置如果已存在数据,那么会发生局部数据覆盖。
字符编码:
ASCII:ISO8859-1、GB2312、GBK、UTF-8
在流对文本数据操作,为了方便提供了转换流,转换流中就融入了编码表,默认是GBK.