黑马程序员_06_Java IO流及其常见对象

------- android培训java培训、期待与您交流! ----------

1. IO(Input Output)流

  • IO流用来处理设备之间的数据传输

  • Java对数据的操作时通过流的方式

  • Java用于操作流的对象都在IO包中

  • 流按操作数据分为两种: 字节流和字符流

  • 流按类型分为: 输入流, 输出流

IO流常用基类

     字节流的抽象基类对象: InputStream, OutputStream

     字符流的抽象基类对象: Reader, Writer

注:有这四个类派生出来的子类名称都是由其父类名作为子类名的后缀.

     如:InputStream的子类FileInputStream

     如:Reader的子类FileReader

2. FileReader和FileWriter流

     //创建一个FileWriter对象,该文件会在指定目录下创建.如果同名则覆盖,除非构造方法第二个参数append 为 true;
     FileWriter fw = new FileWriter("d://abc.txt",false);
     fw.write("tiqiquxian");
     //刷入目的地
     fw.flush();
     //关闭流对象,之前会flash一次缓冲中的数据.
     //与flush的区别: flush刷新后流可以继续使用,close却将流关闭,不可再写入
     fw.close();

IO异常的标准处理方式(以FileWriter为例)

//fw先为null,后赋值,finally中要分别对各个流进行捕获.
FileWriter fw = null;
try{
     fw = new FileWriter("D:\\demo2.txt");
     fw.write("我要\r\n换行了");
     fw.flush();
}
catch(IOException e){
     throw new RuntimeException("产生IO异常");
}
finally{
     if(fw!=null)
          try{
               fw.close();
               }
          catch(IOException e){
               throw new RuntimeException("流关闭异常");         
     }
}

使用FileReader读取文本文件方式一

     int ch = 0;
     while((ch=fr.read())!=-1){
          //relevant operation
     }

使用FileReader读取文本文件方式二(较方法一好,推荐使用)

     int len= 0;
     char[] buf = new char[1024];
     while((len=fr.read(buf))!=-1){
          //relevant operation
     }

拷贝文件(建议使用方法二)

     //具体操作换成--> fw.write(buf,0,len);

3. 字符流的缓冲流BufferedReader与BufferedWriter

     提高了对数据的读写效率

     对应类:BufferedReader和BufferedWriter

     缓冲区要结合流才可以使用

     在流的基础上对流的功能进行了增强

     BufferedWriter

          为提高字符写入流的效率,只要将需要提高效率的流对象作为参数传递到BufferedWriter的构造方法.

          注: BufferedWriter有自己特有的readLine()方法, 这是不包含行结束符的,如果需要每次换行则bfr.newLine(), 并且还要flush()一下.最后不要忘记close流.

          //我的理解是BufferedWriter和BufferedReader都是基于原流,且衷于原流.提供了每行的写与读,而不参杂多余的行终止符.所以要每次自己换行.

     BufferedReader流读取数据              

 String line = null;
               while((line=bfr.readLine())!=null){
                    System.out.println(line);
               }

BufferedWriter, BufferedReader拷贝文件关键代码

 String line = null;
               while((line=bfr.readLine())!=null){
                    bfr.write(line);
                    bfr.newLine();
                    bfr.flush();
               }

4. 装饰设计模式

     当先要对已有对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能.

     装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能.

     装饰模式比继承要灵活,避免了继承体系臃肿.而且降低了类与类之间的关系,装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能.所以装饰类和比装饰类通常是都属于一个体系中.

5. LineNumberReader()

     BufferedReader()的子类,只是多了标号而已.

     可以自定义MyLineNumberReader;   

6. 字节流FileOutputStream和FileInputStream

     //写方法
     public static void write() throws IOException{
          FileOutputStream fos = new FileOutputStream("d:\\tll.txt" );
          fos.write( "awttwa".getBytes());
          fos.close();
     }
     
     public static void read1() throws IOException{
          FileInputStream fis = new FileInputStream("d:\\tll.txt" );
           int ch = 0;
           while((ch=fis.read())!=-1){
              System.out.print((char)ch);
          }
          fis.close();
     }
     
     public static void read2() throws IOException{
          FileInputStream fis = new FileInputStream("d:\\tll.txt" );
           int len = 0;
           byte[] buf = new byte[1024];
           while((len=fis.read(buf))!=-1){
              System.out.print(new String(buf,0,len));
          }
          fis.close();
     }    
     //太取巧,还是read2比较好
     public static void read3() throws IOException{
          FileInputStream fis = new FileInputStream("d:\\tll.txt" );
           byte[] buf = new byte[fis.available()];
          fis.read(buf);
          System.out.print(new String(buf));
          fis.close();
     }
     //拷贝一个图片
     public static void copyFile() throws IOException{
          FileInputStream fis = new FileInputStream("d:\\kk.jpg" );
          FileOutputStream fos = new FileOutputStream("d:\\mm.jpg" );
           int len = 0;
           byte[] buf = new byte[1024];
           while((len=fis.read(buf))!=-1){
              fos.write(buf, 0, len);
          }
          fis.close();
          fos.close();
     }
     //使用字节流的缓冲区赋值一个MP3文件
     public static void copyFile2() throws IOException{
          BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("D:\\M_Download\\我的音乐\\矜持.mp3" ));
          BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("d:\\jingchi.MP3" ));
           int len = 0;
           byte[] buf = new byte[1024];
           while((len=bfis.read(buf))!=-1){
              bfos.write(buf, 0, len);
          }
          bfis.close();
          bfos.close();
     }

自定义字节流的缓冲区

7. 键盘录入(InputStreamReader和OutputStreamWriter转换流)

     System.out: 对应的是标准输入设备,控制台

     System.in:  对应的是标准输出设备,键盘

练习一: 通过键盘录入,当输入一行数据后将改行数据进行打印,如果录入的数据是over,那么停止录入.

     //方法一: 传统思考
     public static void method1() throws IOException{
          InputStream in = System. in;
          StringBuilder sb = new StringBuilder();
           int ch = 0;
           while(true ){
              ch = in.read();
               if(ch == '\r' )
                    continue;
               else if (ch == '\n' ){
                   String s = sb.toString();
                    if(s.equals("over" ))
                         break;
                   System. out.println(s);
                    //清空缓冲区
                   sb.delete(0,sb.length());
              }                  
               else
                   sb.append(( char)ch);
          }                       
     }         
     
     //方法二: InputStreamReader转换流,将字节流转成字符流的桥梁,然后经缓冲包装提高效率
     public static void method2() throws IOException{
          BufferedReader in = new BufferedReader(new InputStreamReader(System.in ));                String line = null;
          while((line=in.readLine())!=null){
               if(line.equals("over" ))
                    break;
          System. out.println(line.toUpperCase());
          }     
     }

OutputStreamWriter转换流

     和InputStreamReader类似,是字符流通向字节流的桥梁.只是包装System.out在缓冲后,用了三条语句输出

    osw.write(line);
    osw.newLine();
    osw.flush();

8. 流操作规律

     1.明确源和目的

     2.是否是纯文本

     3.具体使用哪个对象

     4.是否需要提高效率而加入缓冲

这其中涉及到的OutputStream(OutputStream out, String charsetName)就是字符转字节的桥梁,并可以指定自定义编码,例如"UTF-8",这也是转换流出现的原因.

9. 改变标准输入输出设备

     System的setIn()方法  重新分配“标准”输入流。否则标准输入流一般都是键盘InputStream.

     System的setOut()方法  重新分配“标准”输出流。否则标准输入流一般都是键盘PrintStream.

     可以利用这两个已关联的流进行相关操作

10. File类

     将文件和文件夹封装成对象,方便操作文件和文件夹

          File(File parent, String child) 

               根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 

          File(String pathname) 

               通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 

          File(String parent, String child) 

               根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。

          File f = new File("c:"+File.separator+"a.txt"); // 可以实现跨平台

          //以上三个构造方法简介.

11. File类常用方法

/* 1.创建
当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。
System.out.println(f.createNewFile());
最终目录的父目录必须存在,因此只是建立一层目录
System.out.println(f.mkdir());
可以任意建立多级目录
System.out.println(f.mkdirs());*/
/* 2.删除
boolean delete(); 删除失败返回false
void delectOnExit();在程序退出时删除指定文件*/
/* 3.判断
boolean exists():文件是否存在,是最为常用的方法
isFile();
isDirectory();
isHidden();
isAbsolute(); */
/* 4.获取
getName();返回文件或目录名
getPath();
getParent();
getAbsolutePath();
lastModified();
length();*/

文件列表:

     static File[] listRoots(): 列出可用的文件系统根。 

     String[] list(): 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 

     String[] list(FilenameFilter filter): 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。 

     //这里面涉及到了FilenameFilter接口,此接口的类实例可用于过滤器文件名.实现该接口的public boolean accept(File dir, String name)即可.

列出指定目录下文件或文件夹,包含子目录中的内容.也就是列出指定目录下所有的内容.

	//5.列出指定目录下文件或文件夹,包含子目录中的内容.	
	public static void listFile(File f,int level){
		level++;
		if(f.isFile())
			System.out.println(getLevel(level)+f);
		else if(f.isDirectory()){
			System.out.println(getLevel(level)+f);
			File[] files = f.listFiles();
			for(File file: files){
				listFile(file,level);
			}			
		}
	}
	
	public static String getLevel(int i){
		StringBuilder sb = new StringBuilder();
		for(int k=0;k<i;k++)
			sb.append("|-");
		return sb.toString();
	}

删除一个带内容的目录

删除原理: 在window中,删除目录从里面到外删,使用递归思想.

	//6.删除一个带目录的内容
	public static void deleteDir(File f){
		if(f.isFile())
			f.delete();
		else if(f.isDirectory()){
			File[] files = f.listFiles();
			for(File file: files){
				deleteDir(file);
			}
			f.delete();
		}
	}

将一个指定目录下的java文件的绝对路径存储到一个文本文件中,建立一个java文件列表文件.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Demo2003listToFile {

	public static void main(String[] args) throws IOException {
		List<File> list = new ArrayList<File>();
		//获取new下所有java文件,参数是目录和list对象
		fileToList(new File("D:\\New"),list);
		//取出list对象中信息,并写入list.txt
		listToFile(list,new File("d:\\list.txt"));
	}
	//通过路径名,将所需信息存入list集合中
	public static void fileToList(File f,List<File> list){
		File[] files = f.listFiles();
		for(File file:files){
			if(file.isDirectory() && !file.isHidden())
				fileToList(file,list);
			else if(file.isFile() && !file.isHidden()){
				if(file.getName().endsWith(".java"))
					list.add(file);
			}
		}
	}
	//取出集合中所需信息,写入目标文件
	public static void listToFile(List<File> list, File f){
		BufferedWriter bfw = null;
		try{
			bfw = new BufferedWriter(new FileWriter(f));
			for(File file:list){
				//getAbsolutePath方法是非常常用的,用来获取绝对路径
				bfw.write(file.getAbsolutePath());
				bfw.newLine();
				bfw.flush();
			}
		}
		catch(IOException e){
			throw new RuntimeException("流写入异常");
		}
		finally{
			if(bfw!=null)
				try{
					bfw.close();
				}
				catch(IOException e){
					throw new RuntimeException("流关闭异常");
				}
		}
	}	
}

12. Properties类

     是HashTable的子类,是集合和IO技术相结合的集合容器.

     该对象的特点: 可以用于键值对形式的配置文件

      //设置和获取元素
     public static void set(){
          Properties prop = new Properties();
          prop.setProperty( "likai", "value1" );
          prop. setProperty("tangl", "value2");
          
           //System.out.println(prop);
          
          Set<String> set = prop.stringPropertyNames();
           for(String key: set){
               System. out.println(key+"___" +prop.getProperty(key));
          }         
     }


//方法一: 自定义将流中的数据存储到集合中: 1.一个流与info.txt关联 2.读一行,用'='进行切割 3.分别存入Properties中
     public static void method1() throws IOException{
          BufferedReader bfr = new BufferedReader(new FileReader(      "D:\\hehe.txt"));
          Properties p = new Properties();
          String line = null;
           while((line=bfr.readLine())!=null){
              String[] sp = line.split( "=");
              p.setProperty(sp[0], sp[1]);
          }
          bfr.close();
          System. out.println(p);
     }
     
     public static void method2() throws Exception{
          Properties p = new Properties();
           //一句话就载入了文件信息
          p.load( new FileReader( "D:\\hehe.txt"));
           //以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
          p.setProperty("tangll", "kk" );
          p.store(new FileWriter("D:\\hehe.txt" ), "by likai");
     }

Properties练习: 用于记录应用程序运行次数,如果使用次数一到则给出注册提示.

import java.io.*;
import java.util.Properties;

public class Demo2005ProPertiesApplication {

	public static void main(String[] args) throws Exception {
		File file = new File("D:\\K_Workspace\\SS\\times.txt");
		if(!file.exists())
			file.createNewFile();
		FileReader fw = new FileReader(file);
		Properties p  = new Properties();
		p.load(fw);
		int t;
		String value = p.getProperty("times");
		if(value == null)
			t = 1;
		else			
			t = Integer.parseInt(value)+1;
			if(t>3){
				System.out.println("该付款了,朋友!");
			return;
		}			
		p.setProperty("times", t+"");
		p.store(new FileWriter("D:\\K_Workspace\\SS\\times.txt"), "by alee");	
	}
}

13. 打印流 PrintStream和PrintWriter

     该流提供了打印方法,可以将各种类型的数据原样打印.

     PrintStream     

          1.File对象

          2.String文件路径名

          3.字符输出流OutputStream

     PrintWriter

          增加了字符输出流Writer

//打印流的简单应用
BufferedReader bfr = new BufferedReader( new InputStreamReader(System.in ));
//设置自动刷新
PrintWriter pw = new PrintWriter(System.out,true);
String line = null;
while((line=bfr.readLine())!=null){
    //这样写比用BufferedWriter更简洁.PrintWriter确实更适合打印各种数据.
    pw.println(line);
}

14. 序列流SequenceInputStream(表示其他输入流的逻辑串联,没有对应的输出流)

练习: 文件的分割与合并

     //切割只用字节流,而不是字符流
     public static void split() throws IOException{
          FileInputStream fis = new FileInputStream("d:\\123.pdf" );
          FileOutputStream fos = null;
           int len = 0;
           //1M=1024KB=1024*1024字节 存储
           byte[] buf = new byte[1024*1024];
           int i=0;
           while((len=fis.read(buf))!=-1){
              fos = new FileOutputStream("d:\\" +(++i)+ ".part");
              fos.write(buf, 0, len);
              fos.flush();
              fos.close();;
          }
          fis.close();       
     }
     //文件合并
     public static void meger() throws IOException{
          Vector<FileInputStream> v = new Vector<FileInputStream> ();
           for(int i=1;i<4;i++)
              v.add( new FileInputStream("d:\\" + i+".part"));
          SequenceInputStream sis = new SequenceInputStream(v.elements());
          FileOutputStream fos = new FileOutputStream("d:\\kk.pdf" );       
           int len = 0;
           byte[] buf = new byte[1024];
           while((len=sis.read(buf))!=-1){
              fos.write(buf, 0, len);
          }
          sis.close();
          fos.close();
     }

15. 操作对象的ObjectInputStream与ObjectOutputStream

     被操作的对象需要实现Serializable(标记接口)

     可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID

 ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

这样生成新的类不会改变UID,而不是使用系统生成的UID.

     另外非静态成员变量可以transient修饰不被序列化,同样类(static)变量也不会序列化.

16. 管道流PipedInputStram和PipedOutputStream

     输入输出可以直接连接,结合线程使用     

     PipedInputStream,接收InputStream对象

          用于与另一输出管道相连,读取写入到输出管道中的数据,用于程序中线程的通信

     PipedOutputStream,

          可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。

package itcast21;

import java.io.*;

public class Demo2101PipedStream {

	public static void main(String[] args) throws IOException {
		//建立管道读入流
		PipedInputStream pis = new PipedInputStream();
		//建立管道输出流并与读入流关联,也可以写成connect
		PipedOutputStream pos = new PipedOutputStream(pis);
		new Thread(new Write(pos)).start();
		new Thread(new Read(pis)).start();		
	}
}

class Read implements Runnable{
	private PipedInputStream pis;
	public Read(PipedInputStream pis){
		this.pis = pis;
	}
	@Override
	public void run(){	
		byte[] buf = new byte[200];
		try{
			System.out.println("---读取流开始获取信息");
			int len = pis.read(buf);
			System.out.println("--"+new String(buf,0,len));
			System.out.println("---读取流读取流信息完毕");
		}catch(IOException e){
			throw new RuntimeException("流读取异常");
		}
		finally{
			if(pis!=null)
				try{pis.close();}
			catch(IOException e){
				throw new RuntimeException("流关闭异常");
			}
		}
	}	
}

class Write implements Runnable{
	private PipedOutputStream pos;
	public Write(PipedOutputStream pos){
		this.pos = pos;
	}
	public void run(){
		try {
			System.out.println("写入流开始写入流信息,持续3S");
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			pos.write("Hello PipedStram".getBytes());
			System.out.println("写入流开始写入完毕");
		} catch (IOException e) {			
			throw new RuntimeException("流写入异常");
		}
		finally{
			if(pos!=null)
				try{pos.close();}
			catch(IOException e){
				throw new RuntimeException("流关闭异常");
			}
		}
	}
}

17. RandomAccessFile支持对随机访问文件的读写.该类实现了DataInput和DataOutput接口,因此可以使用两个接口中所有的读写方法,还支持流的随机访问. 

     //调整对象中指针

     seek(long pos)

     //尝试跳过输入的 n 个字节以丢弃跳过的字节。

     skipBytes()

18. 操作基本数据类型

     DataInputStream与DataOutputstream

操作字节数组

     ByteArrayInputStream与ByteArrayOutputStream

操作字符数组

     CharArrayReader与CharArrayWriter

操作字符串

     StringReader与StringWriter

19. 字符编码

     //"你好"-->"??"是GBK变utf-8 ;  -->"浣�濂�"是utf-8变GBK

编一次解一次即可.  

练习: 有五个学生,每个学生有三名课,键盘输入(包括姓名,三门课成绩.)

输出格式: 如 张三,39,76,54 计算出总成绩,并发学生信息和总分数高到低存放在stud.txt.

import java.io.*;
import java.util.*;
public class Demo2105Student {

	public static void main(String[] args) throws IOException {
		Set<Stu> set = getSet();		
		setToFile(set,new File("D:\\stud.txt"));
	}
	
	public static Set<Stu> getSet() throws IOException{
		Set<Stu> set = new TreeSet<Stu>(new Comparator<Stu>(){
			@Override
			public int compare(Stu o1, Stu o2) {
				int i= new Integer(o1.getSum()).compareTo(new Integer(o2.getSum()));
				if(i==0)
					return o1.getName().compareTo(o2.getName());
				return i;
			}
			
		}); 
		BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
		String line = null;
		for(int i=0;i<3;i++){
			line = bfr.readLine();
			String[] info = line.split(",");
			set.add(new Stu(info[0],Integer.parseInt(info[1]),Integer.parseInt(info[2]),Integer.parseInt(info[3])));		
		}
		return set;
	}
	
	public static void setToFile(Set<Stu> set, File f){
		if(!f.exists())
			try {
				f.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		BufferedWriter bfw = null;
		try{bfw = new BufferedWriter(new FileWriter(f));
			for(Stu stu: set){
				bfw.write(stu.toString());
				bfw.newLine();
				bfw.flush();
			}
		}catch(IOException e){
			throw new RuntimeException("流异常");
		}
		finally{
			if(bfw != null)
				try{
					bfw.close();
				}
				catch(IOException e){
					throw new RuntimeException("流关闭异常");
				}
		}			
	}
}

class Stu{
	private String name;
	private int score1;
	private int score2;
	private int score3;
	private int sum;
	Stu(){}
	
	Stu(String name, int s1, int s2, int s3){
		this.name = name;
		score1 = s1;
		score2 = s2;
		score3 = s3;
		sum = s1+s2+s3;
	}
	
	public String getName(){
		return name;
	}
	
	public int getSum(){
		return sum;
	}
	
	public String toString(){
		return "姓名"+name+",分数"+sum;
	}
}

你可能感兴趣的:(android,程序员,网络编程,java培训)