黑马程序员 IO流学习

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

 

io流:

用来处理设备之间的数据传输;

java流的分类:

java流四大抽象基类
I/O流字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

 

 流操作的基本规律:

流太多,使用哪一个?

一、两个明确来确定使用哪个基类。

1、明确需求的源和目的。

源:用输入流,inputStream、Reader

目的:用输出流,OutputStream、Writer

2、操作的对象是否为纯文本文件

是:用字符流

否:用字节流

二、再通过设备,确定使用哪个具体流对象

内存、硬盘、键盘、控制台。

转换流最大功用:指定编码表

 

 

需求:将一个字符串写入指定文件中。

思路:用FileReader和FileWriter

import java.io.*;
public class WriteStrToFile {
	public static void main(String[] args) {
		//创建文件输出流
		FileWriter fw = null;
		try {
			fw = new FileWriter("G:\\Demo.txt", true);//可以续写
			//写字符串到输出流中
			fw.write("Hello java.");
			//将输出流中的信息“冲刷”到文件中
			fw.flush();
		} catch (IOException e) {
			System.out.println(e.toString());
		}
		finally {
			try {
				if(fw != null)
					//关闭输出流用到的系统资源
					fw.close();
			} catch (IOException e) {
				System.out.println(e.toString());			}
		}
	}
}

 

FileReader读取文本文件并打印到控制台

1、读一个字符打印一个字符

2、将读到的字符存入一个字符数组中,用字符数组构造成字符串,再打印。

 

为什么read返回下一个数据字节,而返回的是int?

它内部返回数值时&255;防止了文件开始为-1的情况(影响文件结束判断标记)

read提升数据类型为int,然后write再将其强转为byte

 

需求:将G盘中的一个文本文件复制到E盘

思路:用带有缓冲区的文件流BufferedReader和BufferedWriter来操作

import java.io.*;
public class BufferedWriterDemo {

	public static void main(String[] args) throws Exception {
		//输入流
		BufferedReader br = null;
		//输出流
		BufferedWriter bw = null;
		
		br = new BufferedReader(new FileReader("G:\\Demo.java"));
		bw = new BufferedWriter(new FileWriter("E:\\Demo_copy.java"));
		
		String line = null;
		//用字符串变量line记下读取的每行文本
		while((line = br.readLine()) != null) {
			//读取一行写一行
			bw.write(line);
			//换行
			bw.newLine();
		}
		//关闭资源,实现开发中要捕捉异常,而且要分别捕捉
		br.close();
		bw.close();
	}
}


LineNumberReader

原理:在BufferedReader的基础上多添加了一个private lineNumber属性

跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) getLineNumber(),它们可分别用于设置和获取当前行号。

注意没有LineNumberWriter类

 

需求:复制任意文件(复制后能正常使用)

FileWriter和FileReader对文本文件操作方便,但操作多媒体文件复制后会使文件失效。

public class FileCopy {

	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("G:\\Demo.java");
		FileOutputStream fos = new FileOutputStream("E:\\Demo_copy.java");//文件不存在即创建,会抛FileNotFoundException
		
		byte[] buf = new byte[1024];//定义缓冲区,提高了写效率
		while(fis.read(buf) != -1) {
			fos.write(buf);
			//fos.flush();字节流不需要flush
		}
		fis.close();
		fos.close();
	}

}


上面代码还可以用BufferedInputStream和BufferedOutputStream提高效率。\

 

 

字节流不需要flush()

字符流需要flush():因为字符流底层还是字节+加缓冲,一个字符=2字节。

 

 通过键盘录入信息,并打印,当遇到over即退出。

import java.io.*;
public class KeyboardEntry {

	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		String line = null;		
		try
		{
			while((line=br.readLine()) != null) {
				if("over".equals(line)) {
					System.exit(0);
				}				
				System.out.println(line);			
			}
		}
		catch (IOException e)
		{
			System.out.println(e.toString());
		}
			
	}
}

 

从键盘录入写到文件中去:

//通过键盘录入信息,并写入到文件中,可以追加,当遇到over即退出。

import java.io.*;
public class KeyBoardToFile {

	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt", true));

		String line = null;		
		try
		{
			while((line=br.readLine()) != null) {
				if("over".equals(line)) {
					System.exit(0);
				}				
				bw.write(line);
				bw.newLine();
				bw.flush();
			}
		}
		catch (IOException e)
		{
			System.out.println(e.toString());
		}

		br.close();
		bw.close();
			
	}
}

 

PrintStream:打印流

 

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

//用文件记录日记信息
public class PrintStreamException {

	public static void main(String[] args) throws IOException {
		//记录时间
		Date d = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String s = sdf.format(d);
		
		//定义打印流
		PrintStream ps = new PrintStream(new FileOutputStream("1.txt", true));
		try {
			
			int[] i = new int[3];
			System.out.println(i[3]);
		} catch(Exception e) {
			//输出异常信息到文件中,并在开始处加上分隔线和时间
			ps.println("------------------------------------------------");
			ps.println(s);//2012-09-01 16:02:48
			ps.println(e.toString());//java.lang.ArrayIndexOutOfBoundsException: 3
			ps.println(e.getMessage());//3
			e.printStackTrace(ps);	/*	java.lang.ArrayIndexOutOfBoundsException: 3
										at Demo.main(Demo.java:19)
									 */
		}
	}

}


读取jvm启动信息:

import java.util.*;
import java.io.*;
class Sysinfo {
	public static void main(String[] args) throws Exception{
		Properties sysinfo = System.getProperties();
		sysinfo.list(new PrintStream("sysinfo.txt"));//将系统信息保存到一个文件中
	}
}


 

 

File类:

将文件或文件夹封装成对象。

import java.io.*;
import java.util.Arrays;

public class FileDemo {

	public static void main(String[] args) throws Exception {
		File file = new File("1.txt");
		if(!file.exists()) {
			//创建文件
			file.createNewFile();
		}
		//删除文件
		//file.delete();
		//jvm退出时删除文件或目录
		//file.deleteOnExit();
		//得到全路径
		System.out.println(file.getAbsolutePath());
		//得到文件名
		System.out.println(file.getName());
		//是否为目录
		System.out.println(file.isDirectory());
		//是否为文件
		System.out.println(file.isFile());
		//是否为隐藏文件
		System.out.println(file.isHidden());
		//文件内容的长度
		System.out.println(file.length());
		//是否为绝对路径
		System.out.println("是绝对路径?" + file.isAbsolute());
		
		File dir = new File("abc\\cd\\java\\a");
		//创建多级文件夹
		System.out.println(dir.mkdirs());
		//创建单个文件夹
		System.out.println(dir.mkdir());
		
		//列出系统根目录
		File[] sys = dir.listRoots();
		System.out.println(Arrays.toString(sys));
		
		//列出某个目录下的文件和目录名
		File dir = new File("c:\\"); 
		String[] files = dir.list();
		for(String file : files) {
			System.out.println(file);
		}
	


 需求:列出目录下的所有目录和文件(包括子目录和子目录中的文件)

import java.io.*;
public class FileAllList {
	public static void main(String[] args) {
		File dir = new File("C:\\Documents and Settings\\Administrator\\桌面");
		listAll(dir, 0);		
	}
	
	//列出所有文件及目录
	public static void listAll(File dir, int level) {
		System.out.println(getLevel(level) + dir.getName());//打印目录名
		level++;	//级数自增
		File[] files = dir.listFiles();
		for(File file : files) {
			if(file.isDirectory()) {	//是目录则递归			
				listAll(file, level);
			} else {
				System.out.println(getLevel(level) + file.getName());//打印文件名
			}
		}
	}
	//添加分级分隔符
	public static String getLevel(int level) {
		StringBuilder sb = new StringBuilder();
		for(int i=0; i<level; i++) {
			sb.append("|----");
		}
		return sb.toString();
	}
}


需求:删除一个带内容的目录:

import java.io.*;
public class DirRemover {
	public static void main(String[] args) {
		File dir = new File("C:\\Documents and Settings\\Administrator\\桌面\\abc");
		System.out.println(removeDir(dir));	
	}
	public static boolean removeDir(File dir) {
		if(dir.exists()) {
			File[] files = dir.listFiles();
			for(File file : files) {				
				if(file.isDirectory()) //是目录递归
					removeDir(file);
				else {
					file.delete();//是文件直接删除
				}
			}
			dir.delete();//最后删除最初指定的目录
			return true;			
		}
		return false;
	}
}



 

//需求:从一个磁盘复制一个带内容的文件夹到另一个磁盘中。
import java.io.*;
public class DirctoryCopy {

	public static void main(String[] args) {
		System.out.println(copyDir("G:\\Code", "E:\\test"));
	}

	//文件夹复制程序
	private static boolean copyDir(String originPath, String destPath) {
		//将传进来的路径封装成File对象
		File originFile = new File(originPath);
		File destFile = new File(destPath);
		
		//若源目录不存在,则返回false,程序结束。
		if(!originFile.exists()) {
			return false;
		}
		//若目标目录不存在,则新建目录
		if(!destFile.exists()) {
			destFile.mkdir();
		}
		
		//将源目录内的所有文件及文件夹封装成File对象
		File[] files = originFile.listFiles();
		for(File file : files) {//遍历每个File对象
			if(file.isDirectory()) {
				//如果是目录则递归
				copyDir(file.getPath(), destPath + "\\" + file.getName());
			}
			else {
				//若是文件则调用文件复制程序来copy文件
				copyFile(file.getPath(), destPath + "\\" + file.getName());
			}
		}
		
		return true;
		
	}

	//文件复制程序
	private static boolean copyFile(String originFilePath, String destFilePath) {
		//用传进来的文件路径封装成File对象
		File originFile = new File(originFilePath);
		File destFile = new File(destFilePath);
		
		//创建流对象,准备复制
		FileInputStream fis = null;
		FileOutputStream fos = null;
		
		try {
			fis = new FileInputStream(originFile);
			fos = new FileOutputStream(destFile);
			
			byte[] buf = new byte[1024];
			//增加缓冲区。先将数据读到buf数组内,再将buf数组里的有效数据一次性写入目标文件 
			while(fis.read(buf)!=-1) {
				fos.write(buf, 0, buf.length);
			}
			
		//捕捉异常
		} catch (FileNotFoundException e) {
			System.out.println("文件不存在");
		} catch (IOException e) {
			System.out.println("文件读写错误");
		}
		
		
		//关闭资源
		finally {
			if(fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("fis关闭失败");
				}
			}
			if(fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					System.out.println("fos关闭失败");
				}
			}
		}

		return true;
	}

}


 SequenceInputStream(合并流):能将多个流文件进行连接的高级流

其有个构造方法为:

public SequenceInputStream(Enumeration<? extends InputStream> e)
用到了枚举。
实际操作中可以将流对象存入Vector集合中,再用其方法:
public Enumeration<E> elements(),得到向量中组件的枚举。

 

文件切割:将数据读到byte[]数组中,数组大小自定义。装满即写入一个文件中,最后文件被分成几部分

文件合并:用到合并流。

 

ObjectOutputStream和ObjectInputStream:操作对象的流(对象需要实现Serializable接口)

 

RandomAccessFile:对随机访问文件的读取和写入★★★

内部封装了字节输入流和输出流

有模式r、rw、rws、rwd

该流可以跳过一些字节

使用多线程,就可以实现“跳节”下载

 

PipedOutputStream(管道流):使得输入流和输出流相接。(需结合线程使用)

 

DataInputStream:操作基本数据类型

 

ByteArrayInputStream:操作数组

 

CharArrayReader:操作字符数组

 

StringReader:操作字符串
 

 

编码:

import java.io.*;
import java.util.Arrays;
public class EncodeStream {

	public static void main(String[] args) throws Exception {
		OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream("G:\\utf.txt"), "UTF-8");
		String str = "你好";
		
		byte[] bGBK = str.getBytes();
		//打印“你好”字符串在内存中的字节表示形式
		System.out.println(Arrays.toString(bGBK));//[-60, -29, -70, -61]
				
		byte[] bUTF = str.getBytes("UTF-8");
		//打印“你好”字符串在内存中的字节表示形式
		System.out.println(Arrays.toString(bUTF));//[-28, -67, -96, -27, -91, -67]
		
		os.write(str);
		os.close();
	}
}




Windows默认编码表为GBK,若文件存入时是按UTF-8编码存,然后用GBK编码表来读就出问题,反之亦然。

GBK一个中文字符用两字节表示,UTF-8中一个中文字符用三个字节表示。

用记事本软件只所以能打开,是因为它根据你存入时用的编码来读取文件,所以会获得正确的显示。

 

二次编码、解码得到正确结果:

public class EncodeDecode {

	public static void main(String[] args) throws Exception {
		String str = "你好";
		
		//第二种情况
		/*//对字符串用UTF-8编码
		byte[] b1 = str.getBytes("UTF-8");
		
		//用了GBK解码
		String str1 = new String(b1, "GBK");
		System.out.println(str1);//浣犲ソ	三个字符
		
		//再次用GBK编码
		byte[] b2 = str1.getBytes("GBK");
		
		//用UTF-8编码
		System.out.println(new String(b2, "UTF-8"));//你好	两个字符
		 */	
		
		//第一种情况
		//对字符串用GBK编码
		byte[] b1 = str.getBytes("GBK");//
		
		//用ISO8859-1解码
		String str1 = new String(b1, "ISO8859-1");
		System.out.println(str1);//????
		
		//再次用ISO8859-1编码
		byte[] b2 = str1.getBytes("ISO8859-1");
		
		//再次用GBK解码
		String str2 = new String(b2, "GBK");
		System.out.println(str2);//你好
	}
}


 

第一种情况是编码相似,可反编;第二种情况是第一次编码后的字节数 = “解码表”表示位数的整数倍,可反编。

 

装饰设计模式:

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

所以装饰类和被装饰类属于同一个体系。

继承:

装饰:

装饰比继承灵活,避免了继承体系臃肿,降低了类与类之间的关系。(继承-组合)

 

 

 

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

 详情请查看:http://edu.csdn.net/heima

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值