---------------------- android培训,java培训、期待与您交流! ----------------------
IO流:
IO流是java中的一个重要的部分,主要用于操作数据的.
IO流按照流向来分可以分为输入流和输出流
按照流的操作数据来分可以分为字节流.和字符流
流的常用基类:
字节流的抽象基类:
InportStream OutputStream
字符流的抽象基类:
Reader Worker
字符流:
字符流是基于字节流产生的,字符流主要用于操作文本数据,文件的操作无非是写入和读取,字符流有两个基类分别用于文件的写入和读取:
Writer Reader
先看看Writer类
Writer类是抽象类,其中对文件的操作的子类是OutputStreamWriter,它有一个直接子类是FileWriter类,它没有空参数的构造方法,因为要操作文件首先要初始化一个文件才行,所以要使用带参数的构造函数来初始化.
Writer中的主要方法:
| 将数据添加到此 writer。 |
| 关闭此流,但要先刷新它。 |
| 刷新该流的缓冲。 |
| 写入数据。 |
FileWriter没有自己独立的方法,全部都是继承OutputStreamWriter.
要值得注意的是: FileWriter会创建一个指定名字的文件,这是绝对的,如果目的地已经有了同名的文件,那么FileWriter会创建一个新的文件,把那个同名文件覆盖掉.如果一定要在文件的末尾处继续写数据要怎么办呢? FileWriter有一个构造函数:
FileWriter(String filename, boolean append),第二个参数就是是否允许继续添加文件,如果为true,那么填入的数据就会被添加到文件的末尾处了.
小问题一个: Windows和Linux中的换行符不一样,在Windows中用\r\n表示换行,而在Linux中用\n表示换行
Reader
Reader也是一个抽象的类,它的子类中有一个文件读取的子类InputStreamReader
FileReader
没有空参数的构造函数,因为要读取文件首先肯定要有一个文件才行,所以要初始化一个文件才行
FileReader
中的read:
read方法有两个读取方式
第一种:read() 读取单个字符。
它们都返回字符的二进制码,所以需要用char强转,read是一次读取一个字符,每次都接着上一个继续读取,读到末尾没有字符的时候,返回-1
fr=new FileReader("读取.txt");
intch=0;
while((ch=fr.read())!=-1){
System.out.print((char)ch);
}
第二种, read(ch [ ])把数据读入数组
过程:
首先读取一个文件中的数据,把数据读入一个数组,此时会返回一个数组中元素的个数,当读到数据的末尾的时候,会返回-1,然后通过把数组中的元素变成字符串的形式打印出来
fr=new FileReader("读取.txt");
char[] ch=newchar[1024];
int buf=0; //再循环外面定义一个变量,用于记录
while((buf=fr.read(ch))!=-1){ //当数组里还有元素就进入循环
System.out.print(new String(ch,0,buf)); //把数组从0到buf位置的元素变成字符串
}
缓冲区:
IO流中为了提高流的操作效率,避免过多次读写操作,提供了缓冲区的对象,缓冲区可以存放流对象的资源,当读写的数据达到一定数量的时候,再把数据读写到目的地,实质上,缓冲区内部调用了数组,所以在创建缓冲区之前必须要有流对象.
输入流和输出流各有自己的缓冲区,分别是BufferedWriter和BufferedReader
缓冲区没有空参数的构造方法,因为要缓冲,首先要有被缓冲的流
BufferedWriter bufw=new BufferedWriter ( fw);
缓冲区提供了一个跨平台的换行符:newline( )
关闭缓冲区实际上就是在关闭流对象,所以流对象不用单独关闭
字符读取流缓冲区:BufferedReader
和输入流缓冲区一样读取流缓冲区也是为了提高读取效率的
BufferedReader提供了一个一次读取一行的方法readLine,方便与读取,当返回null时,表示读到文件的末尾
字节流:
字符流只能操作文本类型的文件,这样具有很高的局限性, 为了操作其他类型的文件,我们可以使用字节流,因为字节流是操作字节的.
字节流有两个基类分别用于文件的写入和读取:
OutputStream(字节写入流) InputStream(字节读取流)
和字符流一样,上面两个都是字节流的两个基类,它们都是抽象的.
先看看OutputStream(字节写入流)
| 关闭此流,但要先刷新它。 |
flush | 刷新该流的缓冲。 |
| 写入数据。 |
字节流与字符流有一个不同的就是,字节流的写入不需要使用flush()
方法刷新
InputStream(字节读取流):
int | available() (获取到文件中的字节个数) |
void | close() |
void | mark(int readlimit) |
abstract int | read() |
int | read(byte[] b) |
int | read(byte[] b, int off, int len) |
void | reset() |
long | skip(long n) |
字节流和字符流一样,都有缓冲技术,同样都是为了提高效率
键盘录入:
用IO流不仅能操作已有的文件,而且能进行动态的键盘录入,键盘录入使用的是System类中的in.和out.但是键盘录入是字节流中的方法,每一次都要一个一个字节的读取和写入,这样非常麻烦,如果可以一次读写一行,这样就非常方便了,但是一次读一行是BufferedReader中的方法,我们知道字节流是不能使用字符流中的方法的, 这怎么办呢?这时,就需要用到字符流中的另一个流对象:转换流:
转换流是字符流和字节流之间的桥梁,通过转换流可以实现字符流和字节流的自由转换.转换流有两个:
第一中转换流: InputStreamReader ,字节流转换成字符流,它初始化需要接收一个字节流对象.
第二种转换流: OutputStreamWriter ,字符流转换成字节流, 它初始化需要接收一个字符流对象.
键盘录入最常见的写法:
BufferedWriter bfw=new BufferedWriter(new OutputStreamWriter(System.out));
读取键盘的最常见写法:
BufferedReader bfr=new BufferedReader(new InputStreamReader(System.in));
File:
IO流可以操作数据,但是遗憾的是,IO流能操作文件夹或文件属性,为了弥补这个不足,JAVA提供了另一个类来专门操作文件的各种信息,这个类就是 File .
File(File parent,String child) 参数一:文件地址 参数二:文件名 |
File(String pathname) 参数:文件名 |
File(String parent,String child) 参数一:文件地址 参数二:文件名 |
File的字段摘要:
static String | pathSeparator |
static char | pathSeparatorChar |
static String | separator |
static char | separatorChar |
这些分隔符是跨平台的
File类常见方法:
1. 创建:如果地址中已存在这个文件,那么就不再创建
boolean createNeaFile(); 创建文件
boolean mkdir(); 创建文件夹
boolean mkdirs(); 创建多级文件夹
2. 删除:
Boolean delete(); 删除文件
Boolean deleteOnExit() ; 在程序结束的时候删除文件
3. 判断:
Boolean exists(); 文件是否存在
isFile(); 是否是文件
isDirectory是否是目录
isHidden();是否隐藏
在判断是什么类型的文件之前,一定要先判断文件是否存在
4. 获取:
getAbsolutePath()
获取绝对路径
getPath()
获取路径
getParent()
获取绝对路径中的父目录,如果是相对路径,就返null
File中的List,用于得到指定目录下的文件名称
File[ ] listRoots( );返回一个File数组,得到所有可用的盘符
String [ ] list( ); 返回一个字符串数组,得到所有此路径下的文件,包含隐藏文件 .调用list的对象必须是一个存在的目录
File[]
listFiles():
返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
File[]listFiles(FilenameFilter filter):
通过过滤器放回指定目录下的指定文件
List
和listFiles的区别就是:list返回的只是文件名称,而listFiles返回的是文件对象名称,通过这些对象名称可以得到路径,大小等信息
Properties:
Properties是hashtable的子类,具备map集合的特点,并且它里面存储的键值对都是字符串.
它是集合中和IO技术相结合的集合容器,它的特点是:可以用于键值对形式的配置文件.
Properties中的常用方法:
获取:
getProperty(String key) | |
getProperty(String key,String defaultValue) |
创建
setProperty(String key,String value) |
遍历(迭代)
stringPropertyNames() |
加载配置文件信息
void | load(InputStream inStream) |
void |
把改变后的配置文件信息重新写入配置文件
void | store(OutputStream out,String comments) |
void | store(Writer writer,String comments) |
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。
合并流:SequenceInputStream
一个流对象只能操作一个文件的数据,但是如果要把多个文件的数据合并到一个文件中,IO流就显得有些吃力了,还好IO包中提供了一个专门用于多个流合并成一个流的流对象:SequenceInputStream
SequenceInputStream是一个合并流,可以把多个流合并成一个流
构造函数:
SequenceInputStream
(InputStream s1,InputStream s2)
通过记住这两个参数来初始化新创建的SequenceInputStream
(将按顺序读取这两个参数,先读取s1
,然后读取s2
),以提供从此SequenceInputStream
读取的字节。
SequenceInputStream
(Enumeration<? extendsInputStream> e)
通过记住参数来初始化新创建的SequenceInputStream
,该参数必须是生成运行时类型为InputStream
对象的Enumeration
型参数。
第二种构造函数接收一个Vector集合,因为只有Vector集合才有Enumeration
,把每一个流对象存入集合,然后在通过Vector集合得到Enumeration ,
传递给合并流.
例:
Vector v=new Vector();
v.add(new FileInputStream(“a.txt”));
v.add(new FileInputStream(“b.txt”));
v.add(new FileInputStream(“b.txt”));
Enumeration e= v . elements() ;
SequenceInputStream sis=new SequenceInputStream(e);
byte [] b =new byte[1024];
int len=0;
while((len=sis.read(b))!=-1){
System.out.println(new String(b,0,len));
}
序列化:ObjectInputStream和ObjeceOutputStream
IO流可以操作文件数据,但是不能直接操作对象,这样一来,如果程序中的一个对象的信息要持久化保存就不行了,如果要把堆内存中的对象的数据持久化保存起来并且每次运行此程序的时候都要读取这些信息,就必须使用两个类:ObjectInputStream和ObjectOutputStream.这两个类要搭配使用,因为用ObjectOutputStream写入的文件一定要用ObjectInputStream才能读取.
他们的构造函数需要传入一个字节流流对象,并且此对象要实现Serializable,这个接口没有抽象方法,所以这是一个标记接口,用于表示:这个类可以序列化
要从由 ObjectOutputStream 中的示例写入的流读取:
FileInputStream fis = new FileInputStream("t.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);
int i = ois.readInt();
String today = (String) ois.readObject();
Date date = (Date) ois.readObject();
ois.close();
要写入可通过 ObjectInputStream 中的示例读取的对象,请执行以下操作:
FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeInt(12345);
oos.writeObject("Today");
oos.writeObject(new Date());
oos.close();
由于对象的序列号是根据对象中的成员决定的,只要对象中的成员改变了,对象的序列号也随之改变了,如果要在成员改变后依然对这个对象进行序列化,此时就需要手动的给对象添加序列号,这样对象的序列号就可以保持不变了: public static final long serialVersionUID = 42L;
静态的成员不能被序列化,也就是说,静态的成员的值只能在内存中改变,但是无法保存在文件中;另一方面,如果一个非静态成员也不需要序列化,那么可以加上一个访问修饰符: transient (短暂的,片刻的,非持久的)
管道流:PipedInputStream和PipedOutputStream
管道流是IO技术和线程技术相结合的流对象,通过管道流,可以直接把数据从输出流输出到输入流,输出流和输入流可以通过构造函数或者connect方法创建关联.通常读取方法和写入方法都分别封装到一个线程中.其实管道流没有什么特别的,只是把读取和写入的方法都定义在不同的线程中,然后把管道连接起来,通过线程来调用读取和写入的方法.下面用一个例子演示管道流的用法:
import java.io.*;
class Demo{
PipedInputStream pis=null;
PipedOutputStream pos=null;
try{
pis=new PipedInputStream();
pos=new PipedOutputStream();
pis.connect(pos); //把读取流和写入流相关联
Write w=new Write(pos); //写入数据的线程
Read r=new Read(pis); //读取数据的线程
new Thread(w).start(); //写入数据
new Thread(r).start(); //读取数据
}catch(IOException e){
}
}
//写入数据的线程
class Write implements Runnable{
private PipedOutputStream pos;
Write (PipedOutputStream pos){ //在创建时接受一个管道输出流
this.pos=pos;
}
public void run(){
try{
pos.write(“管道流练习”.getBytes());
}catch(IOException e){
}finally{
if(pos!=null){
try{
pos.close();
}catch(IOException e2){}
}
}
}
}
//读取数据的线程
class Read implements Runnable{
private PipedInputStream pis;
Read(PipedInputStream pis){ //在创建时接受一个管道输入流
This.pis=pis;
}
public void run(){
try{
byte [] b=new byte[1024];
int len=0;
while((len=pis.read(b))!=-1){
System.out.println(new String(b,0,len));
}
}catch(IOException e){
}finally{
if(pis!=null){
try{
pis.close();
}catch(IOException e2){}
}
}
}
}
任意访问: RandomAccessFile
RandomAccessFile是java输入输出流中功能最丰富的文件内容访问类,它提供了众多的文件访问方法,包括读取文件数据和向文件输出数据.但是RandomAccessFile却不是IO包中的类,而是直接继承自Object. RandomAccessFile可以从文件的任意位置来读写数据,这也是它比IO流强的一个方面.
RandomAccessFile的构造函数:
RandomAccessFile(File file , String mode);
RandomAccessFile(String name , String mode);
第一个参数是要读写的文件名,第二个参数是一个模板,”r”只读, “rw”读写
RandomAccessFile的常用方法:
getFilePointer() :返回此文件中的当前偏移量。
seek
(long pos)
:设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
write
(int b)
及writeInt(int v)写入基本数据类型的方法
数组流:
ByteArrayInputStream和ByteArrayOutputStream
专门操作数组的流,操作的源和目的都是内存.
ByteArrayInputStream是读取一个字节数组的元素,所以在它的构造函数中要传入一个字节数组
ByteArrayOutputStream是把文件写入一个数组,在内部封装了一个字节数组,所以不需要在构造的时候传递数组.
ByteArrayOutputStream
中的方法writeTo
(OutputStream out)
是把ByteArrayOutputStream中写入元通过一个输出流输出到文件中
编码表:
GBK
Gbk编码表,一个中文是两个字节
GBK编码是GB2312编码的超集,向下完全兼容GB2312,同时GBK收录了Unicode基本多文种平面中的所有CJK汉字。同 GB2312一样,GBK也支持希腊字母、日文假名字母、俄语字母等字符,但不支持韩语中的表音字符(非汉字字符)。GBK还收录了GB2312不包含的汉字部首符号、竖排标点符号等字符。
GBK的整体编码范围是为0x8140-0xFEFE(两个字节,16位二进制码),不包括低字节是0×7F的组合。高字节范围是0×81-0xFE,低字节范围是0x40-7E和0x80-0xFE。
低字节是0x40-0x7E的GBK字符有一定特殊性,因为这些字符占用了ASCII码的位置,这样会给一些系统带来麻烦。
有些系统中用0x40-0x7E中的字符(如“|”)做特殊符号,在定位这些符号时又没有判断这些符号是不是属于某个 GBK字符的低字节,这样就会造成错误判断。在支持GB2312的环境下就不存在这个问题。需要注意的是支持GBK的环境中小于0x80的某个字节未必就是ASCII符号;另外就是最好选用小于0×40的ASCII符号做一些特殊符号,这样就可以快速定位,且不用担心是某个汉字的另一半。Big5编码中也存在相应问题。
CP936和GBK的有些许差别,绝大多数情况下可以把CP936当作GBK的别名。
UTF-8
UTF-8编码表,一个中文是三个字节
Unicode Transformation Format-8bit,允许含BOM,但通常不含BOM。是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24为(三个字节)来编码。UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。UTF-8编码的文字可以在各国支持UTF8字符集的浏览器上显示。如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,他们无需下载IE的中文语言支持包。
GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1。GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大。
GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:
GBK、GB2312--Unicode--UTF8
UTF8--Unicode--GBK、GB2312
对于一个网站、论坛来说,如果英文字符较多,则建议使用UTF-8节省空间。不过现在很多论坛的插件一般只支持GBK。
----------------------android培训,java培训、期待与您交流! ----------------------
详细请查看http://edu.youkuaiyun.com/heima