---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------
IO流(字符流)用来处理设备之间的数据传输。
Java对数据的操作时通过流的方式。
Java用于操作流的对象都在IO包中。
流按操作的数据分为字节流和字符流,按流向分为输入流和输出流。
数据的最常见体现形式:文件。
1.需求:在硬盘上创建一个文件,并写入一些文件数据。
找到一个专门操作文件的Writer子类对象:FileWriter。后缀是父类名,前缀是该对象的功能。
创建一个FileWriter对象,该对象一经创建就必须明确要被操作的文件。
该文件会被创建到指定的路径下,如果该路径下已有同名文件,将被覆盖
其实该步就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter(”f: \\demo.txt“);
调用write方法,将字符串写入到流中
Fw.write(”bvdaid“);//在写的时候应注意换行符的使用
刷新流对象中的缓冲中的数据,将数据刷新到目的地。
Fw.flush();
关闭资源,但是关闭前会刷新一次缓冲中的数据,将数据刷新到目的地中。与flush的区别是:flush刷新后流可以继续使用,close刷新后,流将被关闭
Fw.close();
以上方法都将抛IOException。
2.IO异常的处理方式:
try{...}
catch(IOException e){...}
finally{
if(fw!=null)
try{
Fw.close();
}
Catch(IOException e){...}
如果要关闭的流有多个,应分别关流,而不应在同一个if语句里关。
3.文件的续写:
传递一个true参数,表示不覆盖已有的文件,而在原文件的末尾处进行续写
FileWriter fw = new FileWriter(”f: \\demo.txt“,true);
4.文本文件的读取。
创建一个文件读取对象,和指定的文件相关联
要保证指定的文件存在,不然会发生FileNotFoundException
读取文本文件的两种方式:
Int Read();读取单个字符,返回作为整数读取的字符,读到末尾时返回-1,
Int read(char[] ch);将数据读到字符数组ch中,返回读到的字符数,如某一次读取到末尾而为读取到数据,返回-1.注意该方法的到的数据转换成字符串时只需将读到的数据进行转换,即用构造方法new String(char[] ch, int offset, int count);
5.字符流缓冲区
缓冲区的出现提高了对数据的读写效率。
要结合流才可以使用,对流的功能进行了增强。
1.BufferedWriter
切记:只要用到缓冲区,就一定要刷新。其实关闭缓冲区,就是在关闭缓冲区中的流对象。所以不用在单独关闭缓冲区所操作的流。
BufferedWriter提供了一个跨平台的换行符:newLine();
6.BufferedReader
该缓冲区提高了一个一次读一行的方法readLine,方便于都文本文件的读取;
当读到文件末尾时,返回null。
readLine原理:无论是读取一个还是多个字符,最终都是在硬盘上一个一个读取,所以最终使用的还是read方法一次读一个。
自定义readLine方法:
Class MyBufferedReader{
private Reader r;
public MyBufferedReader(FileReader r){
this.r = r;
}
public String MyReadLine(Reader r) throws IOException{
//定义一个临时容器,原BufferedReader封装的是字符数组
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.read())!-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
sb.append(ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void close() throws IOException{
r.close();
}
}
7.装饰设计模式
当想要对已有的对象进行功能增强时,可以定义一个类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的类称为装饰类。
装饰类一般会通过构造方法接收备装饰的类,并基于被装饰对象的功能,提供更强大的功能。
自定义装饰类:
Class MyBufferedReader extends Reader{
private Reader r;
public MyBufferedReader(FileReader r){
this.r = r;
}
public String MyReadLine(Reader r) throws IOException{...}
public int read(char[] cbuf,int offset,int len) throws IOException //覆盖父类中的抽象方法
{
return r.read(cbuf,offset,len);
}
public void close() throws IOException //覆盖父类中的抽象方法
{
r.close();
}
8.LineNumberTeader:可以跟踪行号缓冲区的输入字符流
LineNumberReader lnr = new LineNumberTeader(new FileReader("..."));
lnr.setLineNumber();
String line = null;
while((line=lnr.readLine())!=null){
system.out.println(lnr.getLineNumber()+":"+line);
}
lnr.close();
练习:模拟一个带行号的缓冲区对象。
继承自MyBufferedReader,注意父类方法的使用。
IO流(字节流)
1.available();返回关联文件的大小。利用此方法在定义缓冲区时刻直接定义大小为available的返回值。
但是该方法要慎用,应为如果操作的文件过大的话会导致内存溢出。
练习:拷贝图片
1.用字节读取流对象和图片关联
2.用字节写入流创建一个图片文件
3.通过循环读写,完成数据的存储
4.关闭资源
2.字节流缓冲区
BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("..."));
BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("..."));
int by = 0;
while((by=bfis.read())!=1){
bfos.write(by);
}
bfos.close();
bfis.close();
3.自定义字节流缓冲区。
缓冲区原理:缓冲区read方法的原理是先用被装饰类的read(buf)方法将一批目标数据读到一个数组,
然后再从数组里一个一个字节读出来
既然如此,那么可以定义一个字节数组,用一个计数器count记录读到数组中的字节数,当数组中的字节数被取出一个时,count的值-1,
当减到0时,再从源文件读取到到数组中,如果read(buf)的值为-1,表示源文件已读取完毕。
同时用一个指针记录取出数组中元素的数组元素,取出一个后,指针+1,当指针为arr.length-1时,表示数组中的元素已取完,再次读取源文件。
class MyBufferedInputStream{
private InputStream in;
ptivate byte[] buf = new byte[1024];
private int count = 0,pos = 0;
public MyBufferedInputStream(InputStream in) {
this.in = in;
}
public int myRead(){
if(count==0){
count = in.read(buf);
if(count<0)
return -1;
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b&255;//如果读到的第一个字节是11111111(-1),那么类型提升为int后会在高位补-1,则仍为-1;
//那么就会不再读取了。那么只要在高位补0,既可以保证数据的原样性,又可以避免出现-1.
}
else{
byte b = buf[pos];
count--;
pos++;
return b&&0xff;
}
return -1;
}
public void close(){
in.close();
}
}
4.读取键盘录入
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true){
int ch = in.read();
if(ch=='\r')
continue;
if(ch=='\n'){
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length()); //清空用delete。但是清空集合用clear
}
sb.append((char)ch);
}
5.转换流扩展
想要把录入的数据按指定编码表(utf-8),将数据存储到文件中。
目的:OutputStream Writer
是否纯文本?是:Writer
设备:硬盘,文件 FileWriter
但是FileWriter使用的是默认编码表GBK。
要想加入指定编码表,只能使用转换流。OutputStreamWriter.
而转换流需要操作字节输出流,还可以操作文本文件,可传入FileOutputStream
下面是需要高效率和编码表的转换流用法:
BufferedWriter bufw =
new BufferedWriter(new OutputStreamWriter(new FileOutputStream("..."),"utf-8"));
什么时候使用转换流?字节流和字符流之间的桥梁,通常需要用到编码转换时,需要用转换流。
6.异常日志信息
1.改变标准输出,将异常信息存储在文件中
System.setOut(new PrintStream("exception.log"));
e.printStackTrace(System.out);
2.帮助完成日志信息建立的包:log4j
7.系统信息
Properties prop = System.getProperty();
prop.list(new PrintStream("...")); //注意list方法与File对象中list的区别
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------