一:从数据流开始 java
首先先有一个结构图看一下整个数据流中的API结构和对象继承关系信息: 数据库
其余经常使用与流有关的对象: 数组
首先从字符流开始 网络
一、字符流的由来: app
由于文件编码的不一样,而有了对字符进行高效操做的字符流对象。 jvm
原理:其实就是基于字节流读取字节时,去查了指定的码表。 函数
字节流和字符流的区别: ui
1,字节流读取的时候,读到一个字节就返回一个字节。字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,UTF-8码表中是3个字节)时。先去查指定的编码表,将查到的字符返回。 this
2,字节流能够处理全部类型数据,如图片,mp3,avi。而字符流只能处理字符数据。 编码
结论:只要是处理纯文本数据,就要优先考虑使用字符流。除此以外都用
节流。
基本的读写操做方式:
由于数据一般都以文件形式存在。
因此就要找到IO体系中能够用于操做文件的流对象。
经过名称能够更容易获取该对象。
由于IO体系中的子类名后缀绝大部分是父类名称。而前缀都是体现子类功能的名字。
Reader
|--InputStreamReader
|--FileReader:专门用于处理文件的字符读取流对象。
Writer
|--OutputStreamWriter
|--FileWriter:专门用于处理文件的字符写入流对象。
Reader中的常见的方法:
1,int read():读取一个字符。返回的是读到的那个字符。若是读到流的末尾,返回-1.
2,int read(char[]):将读到的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装的元素的个数。若是读到流的末尾,返回-1.
3,close():读取字符其实用的是window系统的功能,就但愿使用完毕后,进行资源的释放
Writer中的常见的方法:
1,write(ch): 将一个字符写入到流中。
2,write(char[]): 将一个字符数组写入到流中。
3,write(String): 将一个字符串写入到流中。
4,flush():刷新流,将流中的数据刷新到目的地中,流还存在。
5,close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭。
FileWriter:该类没有特有的方法只有本身的构造函数。该类特色在于
1,用于处理文本文件。
2,该类中有默认的编码表,
3,该类中有临时缓冲。
构造函数:在写入流对象初始化时,必需要有一个存储数据的目的地。
对于读取或者写入流对象的构造函数,以及读写方法,还有刷新关闭功能都会抛出IOException或其子类。因此都要进行处理。或者throws抛出,或者try catch处理
另外一个小细节:
当指定绝对路径时,定义目录分隔符有两种方式:
1,反斜线可是必定要写两个。\\new FileWriter("c:\\demo.txt");
2,斜线/ 写一个便可。new FileWriter("c:/demo.txt");
一个读取文本文件的经典例子:
字符流的缓冲区:缓冲区的出现提升了对流的操做效率。
原理:其实就是将数组进行封装。
对应的对象:
BufferedWriter:特有方法:newLine():跨平台的换行符。
BufferedReader:特有方法:readLine():一次读一行,到行标记时,将行标记以前的字符数据做为字符串返回。当读到末尾时,返回null。
在使用缓冲区对象时,要明确,缓冲的存在是为了加强流的功能而存在,
因此在创建缓冲区对象时,要先有流对象存在。
其实缓冲内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储。为了提升操做数据的效率。
代码上的体现:
写入缓冲区对象。
//创建缓冲区对象必须把流对象做为参数传递给缓冲区的构造函数。
BufferedWriter bufw = new BufferedWriter(new FileWriter("buf.txt"));
bufw.write("abce");//将数据写入到了缓冲区。
bufw.flush();//对缓冲区的数据进行刷新。将数据刷到目的地中。
bufw.close();//关闭缓冲区,其实关闭的是被包装在内部的流对象。
读取缓冲区对象。
BufferedReader bufr = new BufferedReader(new FileReader("buf.txt"));
String line = null;
//按照行的形式取出数据。取出的每个行数据不包含回车符。
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
readLine():方法的原理:
其实缓冲区中的该方法,用的仍是与缓冲区关联的流对象的read方法。只不过,每一次读到一个字符,先不进行具体操做,先进行临时存储。当读取到回车标记时,将临时容器中存储的数据一次性返回。
既然明确了原理,咱们也能够实现一个相似功能的方法。
而后说一下字节流:
抽象基类:InputStream,OutputStream。
字节流能够操做任何数据。
注意:字符流使用的数组是字符数组。char [] chs字节流使用的数组是字节数组。byte [] bt
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write("abcde");//直接将数据写入到了目的地。
fos.close();//只关闭资源。
FileInputStream fis = new FileInputStream("a.txt");
//fis.available();//获取关联的文件的字节数。
//若是文件体积不是很大。
//能够这样操做。
byte[] buf = new byte[fis.available()];//建立一个刚恰好的缓冲区。
//可是这有一个弊端,就是文件过大,大小超出jvm的内容空间时,会内存溢出。
fis.read(buf);
一个小问题:
字节流的read()方法读取一个字节。为何返回的不是byte类型,而是int类型呢?
由于read方法读到末尾时返回的是-1,而在所操做的数据中的很容易出现连续多个1的状况,而连续读到8个1,就是-1,致使读取会提早中止。因此将读到的一个字节给提高为一个int类型的数值,可是只保留原字节,并在剩余二进制位补0.
对于write方法,能够一次写入一个字节,但接收的是一个int类型数值。只写入该int类型的数值的最低一个字节(8位)。
简单说:read方法对读到的数据进行提高。write对操做的数据进行转换。这是神马意思???
转换流:
特色:
1,是字节流和字符流之间的桥梁。
2,该流对象中能够对读取到的字节数据进行指定编码表的编码转换。
何时使用呢?
1,当字节和字符之间有转换动做时。
2,流操做的数据须要进行编码表的指定时。
具体的对象体现:
1,InputStreamReader:字节到字符的桥梁。
2,OutputStreamWriter:字符到字节的桥梁。
这两个流对象是字符流体系中的成员。
那么它们有转换做用,而自己又是字符流。因此在构造的时候,须要传入字节流对象进来。
构造函数:
InputStreamReader(InputStream):经过该构造函数初始化,使用的是本系统默认的编码表GBK。
InputStreamReader(InputStream,String charSet):经过该构造函数初始化,能够指定编码表。
OutputStreamWriter(OutputStream):经过该构造函数初始化,使用的是本系统默认的编码表GBK。
OutputStreamWriter(OutputStream,String charSet):经过该构造函数初始化,能够指定编码表。
能够和流相关联的集合对象Properties.
Map
|--Hashtable
|--Properties
Properties:该集合不须要泛型,由于该集合中的键值对都是String类型。
1,存入键值对:setProperty(key,value);
2,获取指定键对应的值:value getProperty(key);
3,获取集合中全部键元素:
Enumeration propertyNames();
在jdk1.6版本给该类提供一个新的方法。
Set<String> stringPropertyNames();
4,列出该集合中的全部键值对,能够经过参数打印流指定列出到的目的地。
list(PrintStream);
list(PrintWriter);
例:list(System.out):将集合中的键值对打印到控制台。
list(new PrintStream("prop.txt")):将集合中的键值对存储到prop.txt文件中。
5,能够将流中的规则数据加载进行集合,并称为键值对。
load(InputStream):
jdk1.6版本。提供了新的方法。
load(Reader):
注意:流中的数据要是"键=值" 的规则数据。
6,能够将集合中的数据进行指定目的的存储。
store(OutputStram,String comment)方法。
jdk1.6版本。提供了新的方法。
store(Writer ,String comment):
使用该方法存储时,会带着当时存储的时间。
File类:
该类的出现是对文件系统的中的文件以及文件夹进行对象的封装。
能够经过对象的思想来操做文件以及文件夹。
1,构造函数:
File(String filename):将一个字符串路径(相对或者绝对)封装成File对象,该路径是可存在的,也能够是不存在。
File(String parent,String child);
File(File parent,String child);
2,特别的字段:separator:跨平台的目录分隔符。
如:File file = new File("c:"+File.separator+"abc"+File.separator+"a.txt");
3,常见方法:
1,建立:
boolean createNewFile()throws IOException:建立文件,若是被建立的文件已经存在,则不建立。
boolean mkdir(): 建立文件夹。
boolean mkdirs(): 建立多级文件夹。
2,删除:
boolean delete():可用于删除文件或者文件夹。
注意:对于文件夹只能删除不带内容的空文件夹,
对于带有内容的文件夹,不能够直接删除,必需要从里往外删除。
void deleteOnExit(): 删除动做交给系统完成。不管是否反生异常,系统在退出时执行删除动做。
3,判断:
boolean canExecute():
boolean canWrite():
boolean canRead();
boolean exists():判断文件或者文件夹是否存在。
boolean isFile(): 判断File对象中封装的是不是文件。
boolean isDirectory():判断File对象中封装的是不是文件夹。
boolean isHidden():判断文件或者文件夹是否隐藏。在获取硬盘文件或者文件夹时,
对于系统目录中的文件,java是没法访问的,因此在遍历,能够避免遍历隐藏文件。
4,获取:
getName():获取文件或者文件夹的名称。
getPath():File对象中封装的路径是什么,获取的就是什么。
getAbsolutePath():不管File对象中封装的路径是什么,获取的都是绝对路径。
getParent(): 获取File对象封装文件或者文件夹的父目录。
注意:若是封装的是相对路径,那么返回的是null.
long length():获取文件大小。
longlastModified():获取文件或者文件最后一次修改的时间。
static File[] listRoots():获取的是被系统中有效的盘符。
String[] list():获取指定目录下当前的文件以及文件夹名称。
String[] list(Filenamefilter): 能够根据指定的过滤器,过滤后的文件及文件夹名称。
File[] listFiles():获取指定目录下的文件以及文件夹对象。
5,重命名:
renameTo(File):
File f1 = new File("c:\\a.txt");
File f2 = new File("c:\\b.txt");
f1.renameTo(f2);//将c盘下的a.txt文件更名为b.txt文件。
对象的序列化。
ObjectInputStream
ObjectOutputStream
能够经过这两个流对象直接操做已有对象并将对象进行本地持久化存储。
存储后的对象能够进行网络传输。
Serializable:该接口其实就是一个没有方法的标记接口。
用于给类指定一个UID。该UID是经过类中的可序列化成员的数字签名运算出来的一个long型的值。
只要是这些成员没有变化,那么该值每次运算都同样。
该值用于判断被序列化的对象和类文件是否兼容。
若是被序列化的对象须要被不一样的类版本所兼容。能够在类中自定义UID。
定义方式:static final long serialVersionUID = 42L;
注意:对应静态的成员变量,不会被序列化。
对应非静态也不想被序列化的成员而言,能够经过transient关键字修饰。
一般,这两个对象成对使用。
————————————————————————————————————
其余的数据操做流
操做基本数据类型的流对象。
DataInputStream
DataInputStream(InputStream);
操做基本数据类型的方法:
int readInt():一次读取四个字节,并将其转成int值。
boolean readBoolean():一次读取一个字节。
short readShort();
long readLong();
剩下的数据类型同样。
String readUTF():按照utf-8修改版读取字符。注意,它只能读writeUTF()写入的字符数据。
DataOutputStream
DataOutputStream(OutputStream):
操做基本数据类型的方法:
writeInt(int):一次写入四个字节。
注意和write(int)不一样。write(int)只将该整数的最低一个8位写入。剩余三个8位丢弃。
writeBoolean(boolean);
writeShort(short);
writeLong(long);
剩下是数据类型也也同样。
writeUTF(String):按照utf-8修改版将字符数据进行存储。只能经过readUTF读取。
一般只要操做基本数据类型的数据。就须要经过DataStram进行包装。
一般成对使用。
————————————————————————————————————
操做数组的流对象。
1,操做字节数组
ByteArrayInputStream
ByteArrayOutputStream
toByteArray();
toString();
writeTo(OutputStream);
2,操做字符数组。
CharArrayReader
CharArrayWriter
对于这些流,源是内存。目的也是内存。
并且这些流并未调用系统资源。使用的就是内存中的数组。
因此这些在使用的时候不须要close。
操做数组的读取流在构造时,必需要明确一个数据源。因此要传入相对应的数组。
对于操做数组的写入流,在构造函数可使用空参数。由于它内置了一个可变长度数组做为缓冲区。