JAVA基础——IO(一)---流概述,节点流、处理流、转换流与标准输入输出流、打印流、File文件对象、合并流

第一讲.IO流概述

  1. Java中是通过IO流的方式处理设备间的数据传输,存放在java.io包中。
  2. 按照操作的数据单元分为字节流和字符流,按照流向分为输入流与输出流。
  3. 字节流的抽象基类:InputStream,OutputStream ,操作字节,其实字符流的底层也是字节流。
  4. 字符流的抽象基类:Reader,Writer ,操作字符,专门用来操作文本,可以处理各种文本编码(GBK,UTF-8)。
  5. IO流中相应的继承类后面都跟着它抽象基类的名字。像FileReader继承Reader,属于字节读取流等等。规律性强,还是很好记的。。。
  6. IO流的体系很庞杂,但只要学会举一反三,理解透了还是很容易的。。

第二讲.节点流——直接从磁盘文件或内存读写,在流体系中比较基础的流

  1. FileInputStream、FileOuputStream,字节流的基本输入、输出,下面为拷贝图片的例子:(这里异常处理尽量标准,第一个例程嘛~)
    import java.io.*;
    //图片拷贝,只能用字节流。用字符流可能会出问题。
    //因为字符流会尝试查编码表,如果查到对应则不变原码,否则就会到未知字符区查找并改变原码。
    class CopyPicture
    {
    	public static void main(String[] args){
    		FileInputStream in = null;
    		FileOutputStream out = null;
    		//in,out的声明应该写在外面,让finally中也能看到。初始化一个null是好习惯。
    		int ch;
    		//这里好好地写了较标准的IO异常处理,即try/catch/finally这一套,以后直接抛了~
    		try
    		{
    			in = new FileInputStream("D:\\xiaxia.jpg");//注意转义\
    			out = new FileOutputStream("D:\\copy.jpg");
    			// 读一个byte,输出由byte提升为int,读不到返回-1
    			while((ch = in.read())!=-1){
    			// 写一个byte,就只截取int的低8位咯
    				out.write(ch);
    			}
    			//read、write还可以将数据读到数组buff中,这就放到字符流与这块对应的演示了。
    		}
    		catch (IOException ex)
    		{
    			throw new RuntimeException("Copy IO failed!");
    		}
    		finally//finally语句块中一般写资源关闭语句,但是close还要try!
    		{
    			try
    			{out.close();}
    			catch (IOException ein)
    			{throw new RuntimeException("In close failed!");}
    			finally{
    				try
    				{in.close();}
    				catch (IOException eout)
    				{throw new RuntimeException("Out close failed!");}
    			}
    		}
    		//close是关闭底层系统资源,这个GC显然是管不到的。out、in这些变量归它管。
    		//严格说必须在finally中执行关闭流操作,防止程序在close前就因为异常退出了。
    	}
    }
  2. FileReader、FileWriter,字符流的基本输入、输出,用法基本同上。下面有一个拷贝文本的例子:
    //将D盘中一个文本文件存到C盘中
    import java.io.*;
    class CopyText 
    {
    	public static void main(String[] args) throws IOException
    	{
    		FileReader in = new FileReader("D:\\dati.txt");
    		FileWriter out = new FileWriter("C:\\Copy.txt");//文件不存在就创建,存在就覆盖。想追加就用FilewWriter("",true);
    		char[] buff = new char[1024];//缓冲数组,一般为1024的整数倍,String也行。字节流用byte[]
    		//利用缓冲数组,减少磁盘的机械操作,加快速度~
    		int len;//读入的长度
    		while((len = in.read(buff))!=-1){
    			out.write(buff,0,len);//将buff中len长度的数据写入目的
    		}
    		out.close();
    		in.close();
    	}
    }

第三讲.处理流(filters)

  1. 顾名思义,通过包装(装饰)其他流以增强其功能。典型的就是BufferedXXX这一系列:BufferedReader, BufferedWriter ,BufferedInputStream ,BufferedOutputStream。它们加入了缓冲功能,优化了读写性能,实例化只能传入流,表明它是专门为流进行优化的存在。
  2. BufferedInputStream,BufferedOutputStream,属于字节流,用法同其父类FileInputStream及FIleOutputStream没有太大的区别(注意如果写String类型的先用getBytes()方法转成byte数组,这对所用字节流输出流都适用~)。当然对应的read(),write()方法已经用缓冲的方式重写,具体见下面代码:自己写一个MyBufferedInputStream来模拟BufferedInputStream。把这个MyBufferedInputStream拿去替换前面第一个例程中的FileInputStream,效果一样,只不过我们这个是缓冲增强过的。
    import java.io.*;
    class MyBufferedInputStream 
    {
    	private InputStream in;
    	private int pos=0,len=0;
    	private byte[] buff = new byte[1024];
    	MyBufferedInputStream(InputStream in){this.in = in;}
    	public int read()throws IOException
    	{
    		if(len==0){
    			len = in.read(buff);
    			if(len==-1)return -1;
    			pos=0;
    		}
    		len--;
    		return buff[pos++]&0xff;//这里需要确保-1(0xffffffff)的唯一性
    		//否则如果byte b= 0xff;(int) b 就是-1了
    	}
    	public void close()throws IOException
    	{in.close();}
    }
  3. BufferedReader,BufferedWriter,字符流,同其父类个增加了一个方法。其中BufferedReader的readLine()方法可以读一行,BufferedWriter的newLine()方法可以跨平台地写入换行符,比较有用。
    //将D盘中一个文本文件存到C盘中
    import java.io.*;
    //还是一样的功能,对比一下可发现,确实简单了不少。
    class CopyText 
    {
    	public static void main(String[] args) throws IOException
    	{
    		//包装一下,这个语句比之前长多了。。。
    		BufferedReader in = new BufferedReader(new FileReader("D:\\dati.txt"));
    		BufferedWriter out = new BufferedWriter(new FileWriter("C:\\Copy.txt"));
    		String line = null;
    		while((line = in.readLine())!=null){
    			out.write(line);
    			out.newLine();
    		}
    		out.close();
    		in.close();
    	}
    }
  4. 通过去实现readLine()方法(read()上面写过了),写一个MyBufferedReader去更好地理解BufferedReader:把之前代码中的BufferedReader换为MyBufferedReader效果一样~
    import java.io.*;
    class MyBufferedReader 
    {
    	private Reader r;
    	MyBufferedReader(Reader r){this.r = r;}
    	public String readLine()throws IOException
    	{
    		int ch;
    		StringBuilder sb = new StringBuilder();
    		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();}
    }
  5. 这里涉及到了装饰设计模式,BufferedReader这些处理流是很典型的装饰设计模式,它们的作用就是:为所有其他的流对象提供缓冲这种功能增强。装饰与继承是完全不同的两个概念。继承通过继承父类完成功能拓展,设想现在如果用继承来完成缓冲功能,只能通过为每一个具体子类新建一个Buffered子类来实现。而装饰是通过装饰父类去增强父类功能,只需有一个BufferReader,就可以为所有Reader添加缓冲功能了,简单而且还有拓展性。

第三讲.转换流与标准输入输出流

  1. 字节流处理文本有些时候不好用。但是有些场合不得不接触,像System.in定义的标准输入设备,这个in就是InputStream类型的;而System.out中的标准输出流out类型为PrintStream也是OutputStream类型的。那么如果能不能把InputStream转化为Reader,再把Writer输出的东西转为OutputStream呢?这个答案就是转换流了——InputStreamReader、OutStreamWriter。
  2. 转换流很简单,看一个例子:通过转换流,用BufferedReader的readLine()去读键盘输入。当然这也是以键盘录入的主要方法。
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    String line = in.readLine();
  3. 转换流还有一个特点就是可以指定字符集(FileReader、BufferedWriter这些是用系统默认字符集的,无法更改)。
    BufferedWriter out =new BufferedWriter(new OutputStreamWriter(System.out),"UTF-8");
    out.write("Hello");out.newLine();
  4. System对象方法全静态,封装了一些系统属性及方法。其中标准输入流(键盘)即System的in字段,为InputStream类型。标准输出流(屏幕)即System.out,为PrintStream打印流,这个之后会讲到,是OutputStream类型。可以通过System.setIn(),System.setOut()更改系统的标准输入输出设备。
  5. 我最早接触的键盘录入方法是Scanner,用法就像这样:Scannner in = new Scanner(System.in); int i = in.nextInt(); 可以看到Scanner可以方便地录入基本类型数据,也有nextLine()读一行的方法。还可以指定录入格式,算得上是功能最强的输入方法了。它在java.util包中。

第四讲.打印流

  1. 刚刚提到System.out为PrintStream打印流,顾名思义,就是拥有许多便捷打印方法的流。当然这种流只有输出流啦——PrintStream、PrintWriter
  2. println()方法是最常用到的,可以输出一行数据,带着换行。利用println("",true)可以autoflush。
  3. printf()方法可以按数据类型并按照制定的格式输出,这一点是很像C的。
  4. new对象时可以接受File对象(下面提到),流对象,String fileName,总之基本想到的都可以,体现其强泛用性。
  5. PrintWriter更常用(应该是最强功能的输出流了),在web开发是都是用PrintWriter一行一行地输出数据。

第五讲.File文件对象

  1. File——Java描述文件或文件夹的对象,是文件或目录的抽象表示形式。可以方便我们配合IO批量操作文件。还能够设置文件的属性(可读可写之类的)。
  2. File的一些方法简介如下:
    //介绍File的一些方法
    /*********创建***********/
    File file = new File("D:\\ha\\abc\\newText.txt");//这只是抽象描述,并不会去真的创建
    file.createNewFile();//如果没有就创建,返回true;有的话不创建返回false,注意跟输出流的对比。
    new file("D:\\hahaha").mkdirs();//创建目录,包括不存在的父目录
    //mkdir()如果父目录不存在是不会创建的,返回false
    /*********删除***********/
    file.delete();//deleteOnExit()程序退出时删除,临时文件回去做这件事情
    /*********判断***********/
    file.isFile();//是否为文件
    file.isDirectory();//是否为目录
    file.isAbsolute();//是否为全路径
    file.exists();//是否存在
    file.canExcute();//是否可以执行
    file.canRead();file.canWrite();file.isHidden();
    /*********获取***********/
    file.getPath();file.getAbsolutePath();//得到文件路径
    file.getParent()//得到父目录 还有long length();long lastModified();等等
  3. 获取文件列表,并利用FilenameFilter筛选文件
    //获取文件夹下所有的.java文件,不去递归文件夹
    class FileDemo2
    {
    	public static void main(String[] args) throws IOException
    	{
    		File dir = new File("D:\\EditPlus\\MyWork\\Day12");
    		String[] names = dir.list(new FilenameFilter(){
    			public boolean accept(File dir,String name){
    				return name.endsWith(".java");
    			}
    		});
    		for(String name:names)
    			System.out.println(name);	
    	}
    }
  4. 利用递归,获取文件夹下所有.java文件
    import java.io.*;
    //获取指定文件夹下的所有.java文件,递归
    class FileDemo 
    {
    	private static StringBuilder sb;
    	public static void main(String[] args) throws IOException
    	{
    		sb = new StringBuilder();
    		File dir = new File("D:\\EditPlus\\MyWork");
    		getJava(dir);
    		System.out.println(sb);	
    	}
    	private static void getJava(File dir){
    		if(!dir.isDirectory())
    			return;
    		File[] files = dir.listFiles();
    		for(File item:files){
    			if(item.isDirectory())
    				getJava(item);
    			if(item.getName().endsWith(".java"))
    				sb.append(item.getAbsolutePath()+item.getName()+"\r\n");
    		}
    	}
    }
  5. Properties——就是专门用来存取配置信息的Map对象,与IO联合使用,load(InputStream或Reader)还有list(PrintStream或PrintWriter)很实用。

第六讲. 合并流: SequenceInputStream 

  1. 合并流可以进行文件合并的操作,它可以把多个流汇聚为一个大流。合并流只有输入流,因为分割操作不需要特定的流对象了。
  2. new一个SequenceInputStream时,只接受多个流封装而成的枚举对象Enumeration<InpupStream>。这个是较其他流不同之处。
  3. 可以利用Vector的elements()方法产生Enumeration<InputStream>,示例代码如下:
    v = new Vector<FileInputStream>();
    v.add(new FileInputStream("1.txt"));
    v.add(new FileInputStream("2.txt"));
    v.add(new FileInputStream("3.txt"));
    Enumeration<FileInputStream> en = v.elements();
    SequenceInputStream sis = new SequenceInputStream (en); //只能传入枚举 ,接下来进行合并文件

附录:

Java的IO类型繁杂,怎样根据问题合理选择呢,这里毕老师视频里有详尽总结,即四个明确:
明确源和目的源:输入流          目的:输出流
操作的数据是否为纯文本纯文本用字符流
通过设备确定选用那个对象源设备:内存,硬盘,键盘      目的设备:内存,硬盘,控制台
是否需要提高效率,提高就用Buffered流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值