黑马程序员——IO流

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

java中的IO流可以按照不同的角度来分类:

1、按流的方向不同可以分为:输入流、输出流

2、按流的数据单位不同可以分为:字符流、字节流

3、按流的功能可以不同可以分为:节点流、处理流

字符流:Reader、Writer两大抽象类,所以要通过子类去实现他们的功能。该流是处理字符数据的。如文字。

FileReader类:该类的功能的读取一个文件的字符。如下程序:注:要想使下面程序能成功运行要在e盘下建立一个1.txt的文件。因为FileReader在构造时要接收一个文件

import java.io.*;
public class FileWriterTest{
	 public static void main(String[] args) throws IOException {
		FileReader frd=new FileReader("e:\\1.txt");
		int len=-1;
		while((len=frd.read())!=-1){
			System.out.print((char)len);
		}
		frd.close();
	}
}
上面程序是先将一个文件字符输入流与文件相关联,从文件中每次读取一个字符并将字符打印处理,如果读到文件末尾将等于-1跳出循环。在跳出循环后关闭与之相关的系统资源。

FilerWriter类:该类的功能是将字符写入到某个文件中。

import java.io.*;
 public class FileWriterTest{
	 public static void main(String[] args) throws IOException {
		FileWriter frd=new FileWriter("e:\\1.txt");
		frd.write("abc");
		//frd.flush();
		frd.close();
	}
 }

上面程序执行后如果e盘下有该文件那么将字符写入到该文件中(覆盖),如果没有该文件,那么将在该盘下创建该文件并将字符写如到文件中。从程序中可以看到frd.flush()方法这个方法的作用就是将流中的数据刷新到文件中,如果没有该方法和frd.close()方法,那么字符将会在流中没有写入到文件中。如果没有frd.flush()方法有frd.close()方法,那么程序在执行frd,close()方法时在关闭系统资源前自动将流中的数据刷新到文件中。

字节流:InputReader、OutputWriter两大抽象类,也是所有输入、输出流的超类。该流是专门处理字节数据的(也可以处理字符数据。前提是要将字符数据转化为字节数据)。如图片

下面通过FileInputStream和FileOutputstrean两个类来实现一张图片从e盘下复制到c盘下。程序如下:

import java.io.*;
public class DemoTest{
	 public static void main(String[] args) throws IOException {
		 FileInputStream fis=new FileInputStream("e:\\1.jpg");
		 FileOutputStream fos=new FileOutputStream("c:\\1.jpg");
		 byte[] buf=new byte[1024];
		 while((fis.read(buf))!=-1){
			 fos.write(buf,0,buf.length);
		 }
		 fis.close();
		 fos.close();
	}
}

前面程序中可以看到每次读取字符都是一个字符一个字符的读,是不是速度慢,感觉很不爽?那么下面说一说带有缓冲区的字符输入输出流BufferedReader、BufferedWriter

通过查阅API文档可以看到BufferedReader类中有一个读一行的方法。下面通过程序来看看这个类该怎么用。

程序功能实现一个记事本文件从e盘复制到c盘。

import java.io.*;
public class BufTest{
	 public static void main(String[] args) throws IOException {
		 BufferedReader br=new BufferedReader(new FileReader("e:\\1.txt"));
		 BufferedWriter bw=new BufferedWriter(new FileWriter("c:\\1.txt"));
		 String line=null;
		 while((line=br.readLine())!=null){
			 bw.write(line);
			 bw.newLine();
		 }
		br.close();
		bw.close();
	}
}
从上面程序可以看出在读取文件的时候是每次都是读取一行的,写入文件的时候也是将一行一行的将数据写入到文件中。在写入文件后面都加一个换行符(方法newLine()),这是BuuferedWriter的特点。

如果在控制台中输入字母,将这些字母写入到文件中,程序该如何写呢?

先来分析下:读取控制台数据可以用System.in,写入到文件中可以用FileWriter类,为了提高效率可以用BufferedReader、BufferedWriter进行包装。而Ststem.in是字节读取流,BufferedReader是字符输入流,那该怎么办?我们可以在中间环节加入一个转换流。如下程序:

import java.io.*;
public class BufTest{
	 public static void main(String[] args) throws IOException {
		 BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		 BufferedWriter bw=new BufferedWriter(new FileWriter("e:\\1.txt"));
		 String line=null;
		 while((line=br.readLine())!=null){
			 if(line.equals("over")){
				 break;
			 }
			 bw.write(line);
			 bw.newLine();
		 }
		 br.close();
		 bw.close();
	 }
}
上面通过在控制台中输入over来结束程序,并将数据写入到了文件中。而新出现的类InputStreamReader是字符流通向字节流的桥梁。

通过上面所见可以总结出流操作的基本规律:

流操作的基本规律
1:明确源和目的
源:输入流 inputstream Reader
目的:输出流 outputstream Writer
2:操作的数据是否是纯文本
是:字符流
不是:字节流
3:当体系明确后,在明确要使用哪个具体的对象
通过设备来进行区分
源设备:内存,硬盘、键盘
目的设备:内存 、硬盘、控制台

File类:

先来看一看File类怎么创建创建文件

import java.io.*;
public class FileTest{
	public static void main(String[] args) throws IOException {
		File file=new File("e:\\b\\1.txt");
			file.createNewFile();
	}
}
从实验的结果可以发现,当该目录下如果有文件将不创建文件,如果没有文件将会创建。

import java.io.*;
public class FileTest{
	public static void main(String[] args) throws IOException {
		File file=new File("e:\\b\\3.txt");
			System.out.println(file.delete());
	}
}
如果目录下没有3.txt打印false,所以当要删除某个文件时应该先判断文件是否存在,如果存在才将文件删除。程序如下:

import java.io.*;
public class FileTest {
	public static void main(String[] args) throws IOException {
		File file = new File("e:\\b\\1.txt");
		if (file.isFile()) {
			System.out.println("文件存在删除:" + file.delete());
		} else
			System.out.println("文件不存在创建:"+file.createNewFile());
	}
}
下面通过File类和输出流功能遍历出某一个盘符的所有文件,并将路径文件写入到一个记事本中。

import java.io.*;
import java.util.*;
public class FileTest {
	public static void main(String[] args) throws IOException {
		File file = new File("e:\\");
		BufferedWriter br=new BufferedWriter(new FileWriter("e:\\a\\6.txt"));
		List<File> list=new ArrayList<File>();     //用集合将遍历到的文件存储起来
		recursionTest(file,list);                                //遍历文件的方法
		for(File ls:list){ 
			br.write(ls.toString()); 	 //将集合中的数据写入到记事本中 
			br.newLine(); 			 //换行
		}
		br.close();
	}
	private static void recursionTest(File file,List list) {
		File[] fls=file.listFiles(); 		 遍历该目录下的所有目录或文件
		for(File fl:fls){ 		 
			if(fl.exists()){
				if(fl.isDirectory() && !fl.isHidden()){  //如果是目录且不是隐藏的那么继续递归遍历
					recursionTest(fl,list); 
				}
				else
					if(fl.isFile()){        //如果是文件那么就将文件写入到list集合中
						list.add(fl);
					}				
			}
		}	
	}
}

管道流:一个PipedInputStream对象和一个PipedOutputStream对象进行连接实现通信管道,就如同一根水管一样,从一端倒入水而从另一端流出水,这两个类主要用于线程之间的通信,一个线程写入管道流中一个线程取出管道流中的数据。

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class Test {
	public static void main(String[] args) throws IOException {
		PipedInputStream pis=new PipedInputStream();
		PipedOutputStream pos=new PipedOutputStream();
		pos.connect(pis);
		new Thread(new PipedInputStreamTest(pis)).start();
		new Thread(new PipedOutputStreamTest(pos)).start();
	}
}
class PipedInputStreamTest implements Runnable{
	private PipedInputStream in;
	public PipedInputStreamTest(PipedInputStream in){
		this.in=in;
	}
	@Override
	public void run() {
		byte[] buf=new byte[1024];
		int len=-1;
		try {
			len=in.read(buf);
			System.out.println(new String(buf,0,len));
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}
}
class PipedOutputStreamTest implements Runnable{
	private PipedOutputStream out;
	public PipedOutputStreamTest(PipedOutputStream out){
		this.out=out;
	}
	@Override
	public void run() {
		String str="guang dao liu";
		try {
			out.write(str.getBytes());
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}		
	}
}

当一次读取多个文件怎么办?这时可以用SequenceInputStream类,这个类表示其他输入流的逻辑串联。

下面将多个文件中的内容写入到一个文件中。程序如下:

import java.io.*;
import java.util.*;
public class SequenceInputStreamTest {
	public static void main(String[] args) throws IOException {
		Vector<FileInputStream> v=new Vector<FileInputStream>();  //因为SequenceInputStream接收一个Enumeration所以定义一个Vector
		BufferedWriter br=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("e:\\4.txt"))); //定义一个输出流与一个文件关联
		v.add(new FileInputStream("e:\\1.txt"));
		v.add(new FileInputStream("e:\\2.txt"));
		v.add(new FileInputStream("e:\\3.txt"));
		Enumeration<FileInputStream> en= v.elements();   //转换为Enumeration
		SequenceInputStream sis=new SequenceInputStream(en); 
		int len=-1;
		byte[] buf=new byte[1024];			//读取多个文件中的内容并将内容写入到一个指定的文件中
		while((len=sis.read(buf,0,buf.length))!=-1){
			br.write(new String(buf,0,len));
		}
		sis.close();		//关闭资源操作
		br.close();
	}
}

上面程序实现了文件合并功能,那么文件切割该怎么实现呢?

import java.io.*;
import java.util.*;
public class FileTest {
	public static void main(String[] args) throws IOException {
		FileInputStream fis=new FileInputStream("e:\\1.mp3");
		FileOutputStream fos=null;
		int len=-1;
		byte[] buf=new byte[1024*1024];
		int count=1;
		while((len=fis.read(buf))!=-1){
			fos=new FileOutputStream("c:\\"+(count++)+".suipian");
			fos.write(buf,0,len);
		}
		fis.close();
		fos.close();
	}
}


ByteArrayInputStream和ByteArratOutputStream类:这两个类主要是操作字节数组的。假如需要创建一个临时文件,可以用这两个类在内存中创建一个虚拟临时文件,实现读取和写入操作。可以不用对硬盘进行操作所以速度快。

import java.io.*;
import java.util.*;
public class ByteArrayInputStreamTest{
	public static void main(String[] args) throws IOException {
		byte[] bt="lin shi xu ni wen jian".getBytes();
		ByteArrayInputStream bis=new ByteArrayInputStream(bt);  //创建字节数组输入流
		ByteArrayOutputStream bos=new ByteArrayOutputStream();
		int len=-1;
		while((len=bis.read())!=-1){                   //读取输入流中的数据
			bos.write(len);                   //将数据写入到字节数组输出流中
		}
		bis.close();
		bos.close();
		System.out.println(bos.toString());         //将流中的数据以字符串的形式打印出来。
	}
}
RandomAccessFile类:这个一个很强大的类,它具有随机读取和写入操作的能力,直接继承Object类

import java.io.*;
import java.util.*;
public class FileTest {
	public static void main(String[] args) throws IOException {
		RandomAccessFile raf=new RandomAccessFile("e:\\1.txt","rw");
		byte[] str="123456".getBytes();
		raf.write(str);
		raf.seek(3);                       //设置从哪里开始读取数据
		byte[] buf=new byte[1024];
		int len=0;
		len=raf.read(buf);
		System.out.println(new String(buf,0,len));	
	}
}
运行结果是:4 5 6

从程序可以看出写入的数据是1 2 3 4 5 6而打印出来的数据是4 5 6该程序说明了这个类具有随机访问性。

字符编码:

先看下面程序的结果:

import java.io.*;
public class FileTest {
	public static void main(String[] args) throws IOException {
		BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("e:\\2.txt"),"utf-8"));
		BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("e:\\2.txt"),"gbk"));
		bw.write("张三");
		bw.close();
		String line=null;
		while((line=br.readLine())!=null){
			System.out.println(line);
		}
	}
}
程序是先写入张三两字到文件中,而运行后的结果是乱码?这是为什么呢?这是因为先将张三以UTF-8编码写入到文件中的,而取出的时候却用的是gbk编码。所以导致了乱码。

假如UTF-8编码87、76代表张三两字。在取出是的时候87 76在gbk编码中又代表了其他字,那么取出的汉字就不是张三。如下图所示

---------------------- android培训、java培训、期待与您交流! ----------------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值