IO:
用于设备上的数据处理。
IO的分类:
字符流,字节流。
在早期时,只有字节流,后期为了方便处理不同的文字出现了字符流。
因为编码的原因,而出现字符流。
所有IO体系中的对象通常都以自己所属的父类名作为子类名的后缀名。
IO体系顶层类:
四个抽象基类:
字节流:
InputStream OutputStream。
字符流:
Reader Writer。
使用了字符流中的子类对象。因为要操作的是硬盘的文件。
所以使用了FileReader,FileWriter.
需求:
在硬盘上建立一个文件,并往文件中写入内容。
1,建立字符写入流对象。
建立了流对象,调用了window资源,在指定位置创建了demo.txt文件。先建立了数据存储的目的。
但是因为传递参数的原因,有可能出现IO异常。
如果指定目录下已有该文件会出现覆盖操作。
如果需求是在原有文件中进行数据的续写。要在构造时,传入另一个参数true。new FileWriter("demo.txt",true);
FileWriter fw = new FileWriter("demo.txt");
2,调用流对象写入方法,将数据写入到流中。
fw.write("abcdec");//fw.write("abcd".toCharArray());
3,对流中的数据进行刷新,将数据刷到目的当中。
fw.flush();
可以进行频繁写入,并刷新。。。。
4,关闭资源,会刷新它先。
fw.close();
public void show()
{
FileWriter fw = null;
try
{
fw = new FileWriter("c:/demo.txt");
fw.write("abced");
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
/*
if(fw!=null)
try
{
fw.close();
}
catch(Exception e)
{
e.printStackTrace();
}
*/
closeAll(fw,null);
}
}
需求:
读取硬盘上的数据,并将其打印在控制台上。
//1,建立字符读取流对象。先用流对象与要读取的文件相关联。必须要保证该是存在的,否则会发生FileNotFoundException。
FileReader fr = new FileReader("demo.txt");
//2,定于一个临时容器,因为读到的都是字符数据,所以建立一个字符数组。
该数组的长度如何定义呢?以计算机的基本单位或者其整数倍作为长度
char[] arr = new char[1024];
//3,使用读取流对象的read(arr)方法,将读取到每一个字符数据存入到数组中。
该方法会读到的字符个数。其实就是往数组里面装的元素的个数。
int num = 0;
while((num=fr.read(arr))!=-1)
{
System.out.println(new String(arr,0,num));
}
//4,关闭资源。
fr.close();
注意:读取流还有一个read()方法,该方法是没有参数的,一次读一个字符,并将读到的字符返回。
int ch = 0;
while((ch=fr.read())!=-1)
{
System.out.println((char)ch);
}
需求:
copy文本文件
public void show()
{
FileReader fr = null;
FileWriter fw = null;
try
{
fr = new FileReader("demo.txt");
fw = new FileWriter("copydemo.txt");
char[] arr = new char[1024];
int num = 0;
while((num=fr.read(arr))!=-1)
{
fw.write(arr,0,num);
}
}
catch(Exception e)
{
ystem.out.println(e.toString());
}
finally
{
closeAll(fw,fr);
}
}
public void closeAll(Writer w,Reader r)
{
if(w!=null)
try
{
w.close();
}
catch(Exception e)
{
e.printStackTrace();
}
if(r!=null)
try
{
r.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
-----------------------------------------
为了提高了对流的操作效率,出现了缓冲技术,提高了流的操作效率。
该缓冲技术也被封装成了对象。
对于字符流:
BufferedWriter:
newLine();跨平台的换行符。
BufferedReader
readLine():一次获取一行数据。不包括回车符。
缓冲技术,是为了提高流的效率,所以缓冲对象在初始化的时必须要有流。
使用缓冲技术一定要使用flush();
需求:通过缓冲技术对文本数据进行copy.
public void show()
{
FileReader fr = new FileReader("demo.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("bufdemo.txt");
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
//closeAll(bufw,bufr);
}
缓冲技术的出现对流的读取和写入都进行了增强。
其实就是将一个数组封装在缓冲对象中。
这里就用到了一种设计模式:装饰设计模式。
该模式可以对类中的功能进行增强,优化了继承。
通过继承一样可以完成对类功能的增强,为了还要装饰呢?
Writer
|--FileWriter
|--BufferFileWriter
|--MediaWriter
|--BufferMediaWriter
|--DateWriter
|--BufferDateWriter
为了增强子类的操作效率。想到了缓冲技术。通过继承的方法,在子类中建立带缓冲技术的功能。
但是在设计方式中,发现该体系变的比较臃肿,而且功能都在重复。
那么,进一步优化该设计。
可不可以将缓冲技术进行抽取,单独进行描述。
想要对这些子类进行增强时,只要将每一个子类作为参数传递给缓冲类的构造函数即可。
Writer
|--FileWriter
|--MediaWriter
|--DateWriter
|--Buffer
class Buffer
{
Buffer(FileWriter w)
{}
Buffer(MediaWriter w)
{}
Buffer(DateWriter w)
{}
}
发现这样设计不具备扩展性。
因为传递的都是Writer的子类,只要建立父类引用即可,多态。
class Buffer extends Writer
{
Buffer(Writer w)
{}
}
---------------------------------------
readLine():原理:其实还是用底层read方法,只不过将每一次读到的字符进行临时存储,
当读到回车符,将临时存储的数据一次性返回。
class MyBufferedReader
{
private Reader r;
MyBufferedReader(Reader r)
{
this.r = r;
}
public String myReadLine()throws IOException
{
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;
}
public void myClose()throws IOException
{
r.close();
}
}
-----
带行号
class MyLineNumberReader extends MyBufferedReader
{
private int myNumber;
MyLineNumberReader(Reader r)
{
super(r);
}
public void setMyNumber(int myNumber)
{
this.myNumber = myNumber;
}
public int getMyNumber()
{
return myNumber;
}
public String myReadLine()throws IOException
{
myNumber++;
return super.myReadLine();
}
}