---------------------- android培训、java培训、期待与您交流! ----------------------
学习日志完成于11年12月20日
今天是自学进阶的第二天,用了一天的时间,重新学习了Java IO,东西太多了,脑子都有点大了,但是Java IO是Java SE中非常重要的一块知识点,所以多花些时间来巩固掌握也就必须的,呵呵,又是充实的一天,自我鼓励一下,加油!
下面是我今天的学习笔记:
1、IO流概述:Java对数据的操作是通过流的方式,IO(InputStream/OutputStream)流用来处理设备之间的数据传输。
流按操作数据的不同分为两种:字节流和字符流。字节流的抽象父类:InputStream 、OutputStream,字符流的抽象父类:Reader、Writer。(字节流都有自己默认的编码)
2、字符输入输出流
1).文件输出流FileWriter
要求:在硬盘上,创建一个文件并写入一些文字数据。
import java.io.*; class FileWriterDemo{ public static void main(String[] args) throws IOException { //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。 //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。 //其实该步就是在明确数据要存放的目的地。 FileWriter fw = new FileWriter("demo.txt");
//调用write方法,将字符串写入到流中。 fw.write("abcdefg");
//刷新流对象中的缓冲中的数据。 //将数据刷到目的地中。 //fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。 //将数据刷到目的地中。 //和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。 fw.close(); } } |
在IO流的操作中,会发生IO异常,可用try...catch..finally方式来处理。标准处理方式:
import java.io.*; class FileWriterDemo2{ public static void main(String[] args) { FileWriter fw = null; //在外边建立引用,在try内进行初始化 try{ fw = new FileWriter("demo.txt"); fw.write("abcdefg"); }catch (IOException e){ System.out.println("catch:"+e.toString()); }finally{ //在finally中对流进行关闭 try{ if(fw!=null) //对IO对象进行空判断,提高代码的健壮性 fw.close(); }catch (IOException e){ System.out.println(e.toString()); } } } } |
在创建初始化流对象时,可传递一个true参数,代表不覆盖已有的文件,并将已有文件的末尾处进行数据续写,若续写时实现换行,可用”\n”,如:
FileWriter fw = new FileWriter("demo.txt",true); fw.write("\n你好!谢谢!"); |
2).文本文件读取流FileWriter
读取方式一: 读取单个字符,int read()
import java.io.*; class FileReaderDemo{ public static void main(String[] args) throws IOException{ //创建一个文件读取流对象,和指定名称的文件相关联。 //要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException FileReader fr = new FileReader("demo.txt");
//调用读取流对象的read方法。 //read():一次读一个字符,而且会自动往下读。如果读到末尾,则返回-1
int ch = 0; while((ch=fr.read())!=-1){ System.out.println("ch="+(char)ch); }
fr.close(); } } |
读取方式二:将字符读入数组,int read(char[]) 返回的是读到字符个数。
import java.io.*; class FileReaderDemo2 { public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024]; //定义一个字符数组,用于存储读到字符。
int num = 0; while((num=fr.read(buf))!=-1){ System.out.println(new String(buf,0,num)); } fr.close(); } } |
3).综合练习:将c盘一个文本文件复制到d盘(复制原理)
import java.io.*; public class CopyText { //从C盘全部读取完之后,再写入D盘 public static void main(String[] args) throws IOException{ copy2(); }
public static void copy2(){ FileWriter fw = null; FileReader fr = null; try{ fw = new FileWriter("SystemDemocopy.txt"); fr = new FileReader("SystemDemo.java");
char[] buf = new char[1024]; int len = 0; while((len=fr.read(buf))!=-1){ fw.write(buf,0,len); } }catch (IOException e){ throw new RuntimeException("读写失败"); }finally { if(fr!=null) try{ fr.close(); }catch (IOException e){} if(fw!=null) try{ fw.close(); }catch (IOException e) {} } } //从C盘读一个字符,就往D盘写一个字符。 public static void copy1() throws IOException{ FileWriter fw = new FileWriter("RuntimeDemo_copy.txt"); FileReader fr = new FileReader("RuntimeDemo.java");
int ch = 0; while((ch=fr.read())!=-1){ fw.write(ch); } fw.close(); fr.close(); } } |
3、字符流的缓冲区
作用:缓冲区的出现提高了对数据的读写效率。
对应类:BufferedWriter、BufferedReader,缓冲区结合流才可以使用
1).字符输出流缓冲区:BufferedWriter
import java.io.*; public class BufferedWriterDemo { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("buf.txt"); //创建一个字符写入流对象。
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。 BufferedWriter bufw = new BufferedWriter(fw);
for(int x=1; x<5; x++){ bufw.write("abcd"+x); bufw.newLine(); //该缓冲区中提供了一个跨平台的换行符newLine()。 bufw.flush(); }
//记住:只要用到缓冲区,就要记得刷新。 bufw.close(); //其实关闭缓冲区,就是在关闭缓冲区中的流对象。 } } |
2).字符输入流缓冲区:BufferedReader(仅此类提供读取一行的方法readLine())
import java.io.*; public class BufferedReaderDemo01{ public static void main(String args[]) throws IOException{ FileReader fr=new FileReader("bufWriter.txt"); BufferedReader bufr=new BufferedReader(fr); //将字符读取流对象作为参数传递给缓冲对象的构造函数。
String str=null; while((str=bufr.readLine())!=null){ //readLine()一次读取一行,当返回null时,表示读到文件末尾。 System.out.println(str); } Bufr.close(); } } |
3).综合练习:通过缓冲区复制一个.java文件。
import java.io.*;
class CopyTextByBuf { public static void main(String[] args) { BufferedReader bufr = null; BufferedWriter bufw = null; try{ bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java")); bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
String line = null; while((line=bufr.readLine())!=null){ //readLine()只读取换行符之前的字符内容 bufw.write(line); bufw.newLine(); bufw.flush(); } }catch (IOException e){ throw new RuntimeException("读写失败"); }finally{ try{ if(bufr!=null) bufr.close(); }catch (IOException e){ throw new RuntimeException("读取关闭失败"); } try{ if(bufw!=null) bufw.close(); }catch (IOException e){ throw new RuntimeException("写入关闭失败"); } } } } |
readLine方法原理:无论是读取一行还是读取多个字符,其实最终都是在硬盘上一个一个读取,所以最终使用的还是read方法一次读一个。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
4、装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰与继承的区别
MyReader //专门用于读取数据的类 |--MyTextReader //专门用于读取文本数据的类 |--MyBufferTextReader //通过引入缓冲,提高读取数据的效率 |--MyMediaReader //专门用于读取媒体数据的类 |--MyBufferMediaReader //通过引入缓冲,提高读取数据的效率 class MyBufferReader{ MyBufferReader(MyTextReader text){} MyBufferReader(MyMediaReader media){} } |
通过继承可以使每一个子类都具备缓冲功能,但是这样的话,继承体系会变得很复杂,并不利于扩展。
class MyBufferReader extends MyReader{ private MyReader r; MyBufferReader(MyReader r){} } MyReader //专门用于读取数据的类。 |--MyTextReader |--MyMediaReader |--MyBufferReader |
现在优化思想,单独描述一下缓冲内容:将需要被缓冲的对象,传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。这样继承体系就变得很简单,从而优化了体系结构。
装饰模式比继承要灵活,避免了继承体系的臃肿。而且降低了类于类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中(继承同一个类或接口)的。
5、字节输入/输出流 InputStream/OutputStream (可以操作多种媒体文件)
综合范例:字节输入输出的基本操作
import java.io.*; class FileStream{ public static void main(String[] args) throws IOException{ readFile_3(); }
public static void readFile_3() throws IOException{ //读取方式3,但对于大文件,不建议使用此方法 FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf = new byte[ fis.available() ]; //定义一个刚刚好的缓冲区,不用在循环了。 fis.read(buf); System.out.println(new String(buf));
fis.close(); }
public static void readFile_2()throws IOException{ //读取方式2(常用) FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf = new byte[1024]; int len = 0; while((len=fis.read(buf))!=-1){ //read(buf)以字节数组方式来读取 System.out.println(new String(buf,0,len)); }
fis.close(); }
public static void readFile_1()throws IOException{ //读取方式1(常用) FileInputStream fis = new FileInputStream("fos.txt");
int ch = 0; while((ch=fis.read())!=-1){ //read()一个一个字节来读 System.out.println((char)ch); }
fis.close(); }
public static void writeFile()throws IOException{ FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("abcde".getBytes()); //将字符串转换成字节
fos.close(); } } |
要求:复制一张图片(可使用字节流的缓冲区BufferedInputStream、BufferedOutputStream,类似于字符流的缓冲区)
import java.io.*; class CopyPic{ public static void main(String[] args) { FileOutputStream fos = null; FileInputStream fis = null; try{ fos = new FileOutputStream("2.jpg"); fis = new FileInputStream("1.jpg");
byte[] buf = new byte[1024]; int len = 0; while((len=fis.read(buf))!=-1){ fos.write(buf,0,len); } }catch (IOException e){ throw new RuntimeException("复制文件失败"); }finally{ try{ if(fis!=null) fis.close(); }catch (IOException e){ throw new RuntimeException("读取关闭失败"); } try{ if(fos!=null) fos.close(); }catch (IOException e){ throw new RuntimeException("写入关闭失败"); } } } } |
6、读取键盘录入
System.out:对应的是标准输出设备,控制台
System.in:对应的标准输入设备:键盘
import java.io.*; class ReadIn { public static void main(String[] args) throws IOException { 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()); }else sb.append((char)ch); } } } |
写入转换流:
import java.io.*; class TransStreamDemo{ public static void main(String[] args) throws IOException{ BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //键盘的最常见写法 BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out)); String line = null; while((line=bufr.readLine())!=null) { if("over".equals(line)) break; bufw.write(line); bufw.newLine(); bufw.flush(); } bufr.close(); } } |
7、打印流
思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便?
肯定是不方便的,因为OutputStream中只能操作字节数据,所以其他的数据类型很难操作,那么在Java的IO包中为了解决这种问题增加了两种类:PrintStream、PrintWriter。
观察PrintStream类的构造:public PrintStream(OutputStream out)
虽然PrintStream是OutputStream的子类,但是在实例化的时候依然需要一个OutputStream的对象。
在PrintStream中定义了一系列的输出操作,可以方便的完成输出,那么这种设计思路就是装饰设计。
package org.lxh.printstreamdemo; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; public class PrintStreamDemo01 { public static void main(String[] args) throws Exception { PrintStream out = new PrintStream(new FileOutputStream(new File("d:" + File.separator + "test.txt"))); out.print(1 + " + " + 1 + " = "); out.println(1 + 1); out.println("Hello World!!!") ; } } |
在开发中由于PrintStream较为好用,所以只要是输出就使用打印流完成。
8、Scanner类
在JDK 1.5之后为了方便输入,又增加了一个新的类:Scanner,此类并不是在java.io包中定义的,而是在java.util包中定义的。
使用Scanner可以方便的完成各种字节输入流的输入,构造:public Scanner(InputStream source)
package org.lxh.scandemo; import java.util.Scanner; public class ScannerDemo01 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); //键盘录入 System.out.print("请输入内容:"); if (scan.hasNext()) { // 现在有内容 String str = scan.next(); System.out.println("输入的内容是:" + str); } } } |
在IO操作记住:输出的时候使用PrintStream,输入的时候使用Scanner。
---------------------- android培训、java培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net/heima