--------------------- android培训、java培训、java学习型技术博客、期待与您交流! -------------------
IO
概述:IO用于处理设备间的数据的传输,在java中对于数据的操作时通过流的方式,java用于操作流的对象都存放在IO包中,流按照操作数据分为两种:字节流和字符流,按流向分为2种输出和输入,在IO包中几乎所有类都是一一对应,输出对应输入
流的体系因为功能不同,但是有共性内容,不断抽取,形成继承体系。该体系一共有四个基类,而且都是抽象类。
四大抽象基类
字符抽象基类read writer
字节抽象基类inputstream outputstream
IO继承关系图解
在四大基类中,他们的子类都有一个共性特点,子类后缀名都是父类名,前缀名都是这个子类的功能名称。
字节流:处理字节数据的流对象。设备上的数据无论是图片或者dvd,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。
字符流:因为字符每个国家都不一样,所以涉及到了字符编码问题,那么GBK编码的中文用unicode编码解析是有问题的,所以需要获取中文字节数据的同时+ 指定的编码表才可以解析正确数据。为了方便于文字的解析,所以将字节流和编码表封装成对象,这个对象就是字符流。只要操作字符数据,优先考虑使用字符流体系,字符流基于字节流。
字符流写入数据
步骤
1因为Writer是抽象类因此需要寻找其子类来进行操作,因为最常见操作是操作文件,因此使用Writer子类中的FileWriter
2创建FileWriter对象,该对象初始化时必须要有与之相关联的文件,需要传入一个文件作为参数,将该文件路径以字符串形式传入。该文件不存在时,将会创建该文件,该文件存在时将会覆盖,在构造时可以传入一个boolean参数,当参数为true时,不会覆盖文件,而是在文件的末尾,进行数据的书写
3调用对象的write()方法,将数据写入流中,
4调用对象的flush()方法,刷新流中的缓存,将数据刷到目的地。之所以需要刷新,是因为字符流对象操作时,操作的是字符,而文件存储的是字节,一个字符对应多个字节,所以需要先把字节缓冲。通过刷新再写入到文件中。
5掉用对象的close()方法,关闭流资源,因为java自身是不能完成数据的书写,其底层是在调用系统内部资源,进行数据的书写,所以使用完后一定要关闭系统资源,close在关闭资源前,会先调用fiush刷新流,关闭资源后,流不能再使用。flush刷新后流还能继续使用
写入数据代码示例
class WriterDemo
{
public static void main(String[] args)
{
FileWriter fw = null;
try {
fw = new FileWriter(d:\\demo.txt");
fw.write("我要写数据进去了");
}
catch (IOException e)
{
System.out.println(e.toString());
}
finally
{
if (fw != null)
{
try {
fw.close();
}
catch (IOException e)
{
..
throw new RuntimeException("关闭失败");
}
}
}
}
}
字符流读取数据
步骤
1同写入一样创建一个与文件相关的子类对象FileReader,同时也要相关联一个文件,当该文件不存在时,会报FileNotFoundException异常
2调用read()方法读取,read方法一次只读取一个字符,当读到文件结尾处时会换回-1
3调用close()方法读取完成后需要关闭资源。读取操作不需要刷新流。
代码示例
class ReaderDemo
{
public static void main(String[] args)
{
FileReader fr = null;
try {
fr = new FileReader ("d:\\ demo.txt");
int len=0;
while((len=fr.read())!=-1)
{
System.out.println(len);
}
}
catch (IOException e)
{
System.out.println(e.toString());
}
finally
{
if (fr!= null)
{
try {
fr.close();
}
catch (IOException e)
{
..
throw new RuntimeException("关闭失败");
}
}
}
}
}
注意:路径中的\需要写成\\,不然会被转义。
小练习
文本文件的拷贝
代码示例
class CopyTextTest
{
public static void main(String[] args)
{
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("IO流_2.txt");
fw = new FileWriter("copytest_2.txt");
//创建一个临时容器,用于缓存读取到的字符。
char[] buf = new char[1024];//这就是缓冲区。
//定义一个变量记录读取到的字符数,(其实就是往数组里装的字符个数 )
int len = 0;
while((len=fr.read(buf))!=-1){
fw.write(buf, 0, len);
}
} catch (Exception e) {
throw new RuntimeException("读写失败");
}finally{
if(fw!=null)
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fr!=null)
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符流缓冲区
缓存区的出现提高了对数据的读写效率
对应类
BufferedWriter
特有方法:
newline()跨平台的换行符,(推测其出现是因为readLine读取的数据不包含换行)
BufferedReader
特有方法
readLine()一次读一行,当读到文件末尾时,返回null
缓存区要结合流才可以使用,创建缓存区对象时需要传入对应的流对象,对原有流对象的功能进行了增强
使用缓冲区复制文本文件
代码示例
public class CopyBuf
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("buf_copy.txt");
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;
while((line=bufr.readLine())!=null){
bufw.write(line);
//因为readLine()读取的字符中不含有换行符
//通过BufferedWriter的newLine()方法写入一个跨平台的换行符
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
}
BufferReader中通过一个一次读一行的readLine方法对FileReader进行了加强,
我们也可以自定义一个类继承Reader对FileReader进行加强
原理
定义一个临时容器作为缓冲区,将文件的一行数据写入容器中后,再将容器中的数据取出
原理图解
代码示例
import java.io.*;
class MyBufferedReader extends Reader
{
private Reader r;//定义接收的流对象
MyBufferedReader(Reader r)
{
this.r=r;
}
//自定义ReadLine
public String myReadLine()throws IOException
{
//创建一个容器,用来存储一行的字符
StringBuilder sb =new StringBuilder();
//一个字符一个字符读取
for (int ch=0;(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 int read(char[] cbuf, int off, int len) throws IOException
{
return r.read(cbuf,off,len);
}
//复写父类的close方法
public void close()throws IOException
{
r.close();
}
}
class MyBufferedReaderDemo
{
public static void main(String[] args)
{
MyBufferedReader mbr=null;
try
{
mbr=new MyBufferedReader(new FileReader("BufferedCopyDemo.java"));
for (String line=null;(line=mbr.myReadLine())!=null ; )
{
System.out.println(line);//显示效果
}
}
catch (IOException e)
{
throw new RuntimeException("读取数据失败");
}
finally
{
try
{
if(mbr!=null)
mbr.close();
}
catch (IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
}
}
}
在io中BufferedReader有一个子类LineNumberReader,该类有特有的方法,可以获取行号
代码示例
class LineNumberReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("IO流_2.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(100);
while((line=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber()+":"+line);
}
lnr.close();
}
}
装饰设计模式
概述:当想要对已有的对象进行功能增加时,可以自定义类将已有对象传入,在内部基于已有的功能对其进行功能的加强
装饰和继承的区别
装饰模式比继承要灵活,如果一个类的功能需要加强就定义一个子类,那么当需要加强的功能很多时,体系就会变得十分臃肿,而装饰只需要继承根类,然后将其他子类传入即可。
注意:在定义类时尽量不要使用继承。
字节流
概述:字节流可以操作任何数据,字节流操作时和字符流基本相同,因为字节流操作的是字节,文件中存储也是以字节形式存在,所以字节流对象不需要刷新就可以直接将文件写入文件中,不用再进行刷新动作
小知识点:InputStream中的available()方法可以直接返回文件中字节个数,可以用此方法来确定定义的缓冲数组的大小,但文件较大时,容易造成内存溢出,所以请慎用。
使用字节流对象复制图片
代码示例
import java.io.*;
class InputCop
{
public static void main(String[] args)
{
FileInputStream fis=null;
FileOutputStream fos=null;
try
{
//关联要复制的文件
fis=new FileInputStream("C:/Users/asus/Desktop/1.jpg");
//指定复制的路径
fos=new FileOutputStream("C:/Users/asus/Desktop/2.jpg");
//利用数组的读取方式
byte[] b=new byte[1024];
int len=0;
while ((len=fis.read(b))!=-1)//复制文件的全部数据
{
fos.write(b,0,len);//粘贴到指定路径
}
}
catch (IOException e)
{
throw new RuntimeException("图片复制失败");
}
finally
{
try
{
if(fis!=null)
fis.close();//关闭输入字节流
}
catch (IOException e)
{
throw new RuntimeException("读取字节流关闭失败");
}
try
{
if(fos!=null)
fos.close();//关闭输出字节流
}
catch (IOException e)
{
throw new RuntimeException("写入字节流关闭失败");
}
}
}
}
字节缓冲区
概述,与字符缓冲区作用相同,都是为了提高读写效率。
特点:
read():会将字节byte类型提升为int型,因为read方法读到末尾时会返回-1,这样有可能当连续读到8个二进制1时,返回-1,结束了读取动作。为了避免这种情况将byte提升为int,将读到的byte值&上255就可以避免这种情况了。
write():会将int型强转为byte型
转换流:
概述:是字节流和字符流之间的桥梁,该流对象中可以对读取到的字节数据进行指定编码表的编码转换,当字节与字符有转换动作时,流操作的数据需要进行编码表的指定时使用。
对应对象
InputStreamReader
OutputStreamWriter
标准输入输出
System.out:对应的是标准输出设备,也就是控制台
System.in:对应的是标准输入设备,也就是键盘
读取键盘录入代码示例
import java.io.*;
class TransStreamDemo
{
public static void main(String[] args)throws IOException
{ //获取键盘录入对象。
//InputStream in=System.in;
//将字节流对象转成字符流对象,使用转换流。
//InputStreamReader isr=new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
//BufferedReader br=new BufferedReader(isr);
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(System.out));
String s=null;
while((s=in.readLine())!=null)
{
if("over".equals(s))
break;
bw.write(s.toUpperCase());//写入数据
bw.newLine();//换行
bw.flush();//刷新
}
bw.close();//关闭流资源
in.close();
}
}
流操作规律
通过三个明确来完成:
4.1 明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
4.2 操作的数据是否是纯文本。
是:字符流
否:字节流
4.3 当体系明确后,再明确要使用哪个具体的对象。通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
举例体现
需求将一个文本文件中数据存储到另一个文件中。复制文件。
1)源:因为是源,所以使用读取流:InputStream和Reader
明确体系:是否操作文本:是,Reader
明确设备:明确要使用该体系中的哪个对象:硬盘上的一个文件。Reader体系中可以操作文件的对象是FileReader
是否需要提高效率:是,加入Reader体系中缓冲区 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
2)目的:输出流:OutputStream和Writer
明确体系:是否操作文本:是,Writer
明确设备:明确要使用该体系中的哪个对象:硬盘上的一个文件。Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是,加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
需求:想要把录入的数据按照指定的编码表(UTF-8)(默认编码表是GBK),将数据存到文件中。
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘上的一个文件。使用 FileWriter。——但是FileWriter是使用的默认编码表:GBK。而存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。
该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流:FileOutputStream
OutputStreamWriter osw =new OutputStreamWriter(newFileOutputStream("d.txt"),"UTF-8");
需要高效吗?需要,BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
--------------------- android培训、java培训、java学习型技术博客、期待与您交流! -------------------
本文深入探讨Java中IO流的使用,包括字符流与字节流的基本概念、操作流程及应用实例,如文本文件的读写、缓冲区技术、复制文件等。详细解释了流的体系结构、操作步骤与注意事项。

557

被折叠的 条评论
为什么被折叠?



