1.IO总框架图
2.File类
在学习流之前,很有必要先写一下File类,因为大多数流都涉及到File.
File类常见方法:
1),创建。
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。
和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
2),删除。
boolean delete():
删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
void deleteOnExit()
;在程序退出时删除指定文件。
3),判断。
boolean exists() :文件是否存在.
isFile():
isDirectory();
isHidden();
isAbsolute();
4),获取信息。
getName():
getPath():
getParent():
getAbsolutePath()
long lastModified()
long length()
记住在判断文件对象是否是文件或者目的时,必须要先判断该文件对象封装的内容是否存在。
//通过exists判断。
import java.io.*;
public class FileDemo {
public static void main(String[] args) throws IOException{
File f = new File("d:\\java\\nuddles.txt");
f.createNewFile();
sop(f);
sop(f.canExecute());
sop(f.createNewFile());
sop(f.exists());
sop(f.delete());
File p = new File("d:\\java\\com\\haha\\lala");
sop(p.isFile());
sop(p.isDirectory());
sop(p.mkdirs());
sop(f.getParent());
sop(f.getAbsolutePath());
sop(f.length());
}
public static void sop(Object obj){
System.out.println(obj);
}
}
练习:打印文件目录
/*
要求:打印一个目录,要求要有层次
*/
package nuddles.j2seDemo;
import java.io.File;
public class DirectoryPrint {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("d:\\javasf");
filePrint(file,0);
}
public static String index(int level){
// 用此方法在目录前添加层次
StringBuilder sb = new StringBuilder();
sb.append("|--");
for (int i = 0; i < level; i++) {
sb.insert(0, " ");
// 第往下一级目录就增加两个空格
}
return new String(sb);
}
public static void filePrint(File file,int level){
if (!file.exists()) {
// 如果不存在直接提示返回
System.out.println("你输入的文件名不存在");
return;
}
if (file.isDirectory()) {
// 是目录则往下一级
level++;
System.out.println(file.getAbsolutePath());
File[] files = file.listFiles();
for (File file2 : files) {
// 递归调用
filePrint(file2,level);
}
}else{
System.out.println(index(level)+file.getName());
// 不是目录则打印文件名,前面加层次
}
}
}
删除目录
/*删除目录*/
import java.io.*;
public class FileDemo3 {
public static void main(String[] args) {
File file = new File("d:\\jiangxi");
File[] p = file.listFiles();
sop(p== null);
fileRemove(file);
}
public static void sop(Object obj){
System.out.println(obj);
}
public static void fileRemove(File file){
if (file.exists()) {
File[] file2 = file.listFiles();
for(File f:file2){
if (f.isDirectory()) {
fileRemove(f);
}else{
f.delete();
}
}
}else {
System.exit(0);
}
file.delete();
}
}
3..流的概念和作用
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
4.IO流的分类
根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流
字符流和字节流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。
本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:
读写单位不同:
字节流以字节(8bit)为单位
,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
字符类其实就是带有编码表的字节类
输入流和输出流
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
字符流和字节流:
字节流两个
抽象基类:
InputStream OutputStream
字符流两个
抽象基类:
Reader Writer
字符流在写入数据的时候会有缓冲期,要刷新flush()
先学习一下字符流的特点。
既然IO流是用于操作数据的,
那么数据的最常见体现形式是:文件。
那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。
import java.io.*;
public class FileWriterDemo {
public static void main(String[] args){
FileWriter fw = null;
try{
fw = new FileWriter("whz.txt",true);
fw.write("\r\nabcde");
// 可以直接写入字符串
fw.flush();
// 写完后一定要刻刷新
}catch(IOException e){
sop("fail to write ");
}finally{
try{
if (fw != null) {
fw.close();
// 为更好保护数据,关闭流
}
}catch(IOException e){
sop("fail to close");
}
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
FileReader类:
注意:FileReader类没有readLine 的方法
import java.io.*;
public class FileReaderDemo {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("FileWriterDemo.java");
char[] cha = new char[1024];
int num = 0;
while ((num=fr.read(cha)) != -1) {
// 直接读一个字符数组,返回读到的长度
sop(new String(cha,0,num));
}
fr.close();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
import java.io.*;
public class CopyDemo {
public static void main(String[] args) {
copy();
}
public static void sop(Object obj){
System.out.println(obj);
}
public static void copy(){
FileReader fr = null;
FileWriter fw = null;
try{
fw = new FileWriter("SystemDemo_copy.txt");
fr = new FileReader("SystemDemo.java");
char[] cha = new char[1024];
int num = 0;
while ((num = fr.read(cha)) != -1) {
fw.write(cha,0,num);
// 直接写入一个数组的指定长度
fw.flush();
}
}catch(IOException e){
sop(e.toString());
}finally{
try{
if(fw != null){
fw.close();
}
}catch(IOException e){}
try{
if(fr != null){
fr.close();
}
}catch(IOException e){}
}
}
}
3.字符流缓冲区:
缓冲区的出现提高了对数据的读写效率
对应类:
BUfferWriter
BufferedReader
特点:缓冲区要结合流才可以使用,在创建缓冲区之前,必须要有流对象。在流的基础上对流的功能进行了增强。
BufferWriter步骤:
1.创建一个字符写入流对象
FileWriter fw=new FileWriter("a.txt");
2.将需要被提高效率的流对象作为参数传递给缓冲区的构造函数
bufferedWriter bufw=new BufferedWriter(fw);
buff.write("asdasdas");
bufw.newLine();//换行符,跨平台的
3.将缓冲区刷新
bufw.flush;
4.关闭缓冲区,就是在关闭缓冲区中的流对象
bufw.close();
BufferedReader步骤
1.创建一个字符写入流对象
FileReader fr=new FileReader ("a.txt");
2.将需要被提高效率的流对象作为参数传递给缓冲区的构造函数
BufferedReader bufr=new BufferedReader (fr);
3.读取流对象:该缓冲区提供了一个一次读取一行的方法。当返回null时表示,文件读到末尾
String line=null;
while((line=bufr.readLine())!=null)
{
String s=line;}
4.关闭
bufr.close();
readLine()方法的原理:
无论是读一行,获取多个字符,最终都是在硬盘上一个一个读取,最终使用额还是read方法一次读一个的方法。
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
import java.io.*;
public class BufferedReaderDemo {
public static void main(String[] args)throws IOException {
FileReader fr = new FileReader("whz.java");
BufferedReader br = new BufferedReader(fr);
String line = null;
while((line=br.readLine())!=null){
sop(line);
}
br.close();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
扩展:自己写readLine方法
import java.io.*;
class MyBufferedReader extends Reader {
private Reader reader;
MyBufferedReader(Reader reader){
this.reader =reader;
}
public String myReadLine()throws IOException{
int num = 0;
StringBuilder sb = new StringBuilder();
while ((num =reader.read())!=-1) {
if (num == '\r') {
continue;
}
if(num == '\n'){
// 边续两次判断,决定是不是换行
return sb.toString();
}else{
// 不是就继续添加
sb.append((char)num);
}
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public int read(char[] cbuf, int off, int len) throws IOException{
// reader是抽象类,要覆写所有的抽象方法
return reader.read(cbuf,off,len) ;
}
public void close()throws IOException{
reader.close();
}
public void myClose()throws IOException{
reader.close();
}
}
public class MyBufferedReaderDemo {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("whz.java");
MyBufferedReader myBuf = new MyBufferedReader(fr);
String line = null;
while((line=myBuf.myReadLine())!=null){
System.out.println(line);
}
myBuf.myClose();
}
}
4。装饰类设计思路
当想要对已有的独享进行功能增强时,可以定义类,将已有的对象传入,基于已经有的功能,
并提供加强功能,那么自定义的该类称为装饰类
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
以前是通过继承将每一个子类都具备缓冲功能。
那么继承体系会复杂,并不利于扩展。
现在优化思想。单独描述一下缓冲内容。
将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。
这样继承体系就变得很简单。优化了体系结构。
装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。
所以装饰类和被装饰类通常是都属于一个体系中的。
package com.io;
import java.io.*;
public class MyBufferedReader {
private Reader r;
public MyBufferedReader(Reader r) {
super();
this.r = r;
}
//可以一次读取一行的方法
public String myReadLine() throws IOException
{
//定义一个临时容器。StringBulider容器,应用于存储字符数组
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=r.read())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
//复写reader中的抽象方法
//复写close方法
public void close() throws IOException
{
r.close();
}
//复写read方法
public int read (char[] c,int off,int len) throws IOException{
return r.read(c, off, len);
}
}