IO流对象关系图

其他常用与流有关的对象

IO流 IO流用来处理设备之间的数据传输。Java对数据的操作是通过流的方式。Java用于操作流的对象都在IO包中。 输入流和输出流相对于内存设备而言。 IO流:用于处理设备上的数据。设备:硬盘,内存,键盘录入。 IO有具体的分类: 1、根据处理的数据类型不同:字节流和字符流。 2、根据流向不同:输入流和输出流。 字符流的由来:因为文件编码不同,而有了对字符进行高效操作的字符流对象。原理:其实就是基于字节流读取字节时,去查了指定的码表。 字节流和字符流的区别: 1、字节流读取时候,读到一个字节就返回一个字节。字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在utf-8码表中是3个字节)时。先去查指定的编码表,将查到的字符返回。 2、字节流可以处理所有类型数据,如图片,avi。而字符流只能处理字符数据。 结论:只要是处理纯文本数据,就要优先考虑使用字符流。除此之外都是用字节流。 IO的体系。所具备的基本功能就有两个:读 和 写。 1、子节流: InputStream(读),OutputStream (写)。 2、字符流:Reader(读),Writer(写)。 字符流 Reader |--InputStreamReader |--FileReader:专门用于处理文件的字符读取流对象。 Writer |--OutputStreamWriter |--FileWriter:专门用于处理文件的字符写入流对象。 Reader中的常见方法: 1、int read():读取一个字符。返回的是读到的那个字符。如果读到流的末尾,返回-1 2、int read(char[]):将读到的字符存入指定的数组中,分那会的是读到的字符个数,也就是往数组里装的元素的个数。如果读到流的末尾,返回-1 3、close():读取到字符其实用的是window系统的功能,就希望使用完毕后,进行资源释放。 Writer中常见的方法: 1、write(char):将一个字符写入到流中 2、write(char[]):将一个字符数组写入到流中 3、write(String):将一个字符串写入到流中 4、flush():刷新流,将流中的数据刷新到目的地中,流还存在。 5、close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭。 FileWriter: 该类没有特有的方法。只有自己的构造函数。该类的特点在于 1、用于处理文本文件。 2、该类中有默认的编码表, 3、该类中有临时缓冲。 构造函数:在写入流对象初始化时,必须要有一个存储数据的目的地。 FileWriter(String filename):该构造函数做了什么事情呢? 1、调用系统资源。 2、在指定位置,创建一个文件。注意:如果该文件已经存在,将会被覆盖。 FileWriter(String filename,boolean append):该构造函数:当传入boolean类型为true时,会在指定文件末尾进行行数数据的续写。 小细节:当指定绝对路径时,定义目录分隔符有两种方式: 1、反斜线 但是一定要写两个。\\ new FileWriter("c:\\demo.txt"); 2、斜线 /写一个即可 new FileWriter("c:/demo.txt"); FileReader: 1、用于读取文本文件流对象。2、用于关联文本文件。 构造函数:在读取流对象初始化的时候,必须要指定一个被读取的文件。如果该文件不存在会发生FileNotFoundException。FileReader(String filename);
class Demo示例1:
{
public static void main(String[] args) throws IOException
{
FileWriter fw = new FileWriter("demo.txt");
fw.write("abcde");
fw.flush();
fw.write("kkkk");
fw.close();
}
}
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个可以往文件中写入字符串数据的字符输出对象
//既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)
//如果文件不存在,则会自动创建
//如果文件存在,则会被覆盖
FileWriter fw = new FileWriter("demo.txt");
//调用Writer对象中的write(string)方法,写入数据
fw.write("abcde");
//进行刷新,将数据直接写入目的地中
fw.flush();
//关闭流,关闭资源,在关闭前会先调用flush刷新缓冲中的数据到目的地。
fw.close();
}
}

1. close方法只能用一次。
2. 流关闭以后不能,不能再调用write方法,否则会报如下异常错误:
示例2:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
FileWriter fw = new FileWriter("demo.txt",true);
fw.write("xixi");
fw.close();
}
}

import java.io.FileWriter;需求:读取一个文本文件,将读取到的字符打印到控制台。(使用FileReader)
import java.io.IOException;
public class FileWriterDemo
{
public static void main(String[] args)
{
FileWriter fw = null;
try
{
fw = new FileWriter("demo.txt");
fw.write("abcde");
}
catch (IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
fw.close();
}
catch (IOException e)
{
throw new RuntimeException("关闭失败");
}
}
}
}
第一种读取方式:使用read()方法读取文本文件数据。
示例4:
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("demo.txt");
//用Reader中的read方法读取字符串
int ch = 0;
while((ch = fr.read())!=-1)
{
System.out.println((char)ch);
}
fr.close();
}
}

第二种读取方式:使用read(char[])方法读取文本文件数据。
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("demo.txt");
//使用read(char[])读取文本文件数据
//先创建字符数组
char[] buf = new char[3];
int len = 0;
while((len = fr.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
fr.close();
}
}

将d盘的一个文本文件复制到d盘 示例5:方式1:使用read()读取文本文本文件数据。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyTestDemo
{
public static void main(String[] args) throws IOException
{
//1、读取一个已有的文本文件,使用字符读取流和文件相关联
FileReader fr = new FileReader("demo.txt");
//2、创建一个目的,用于存储读到的数据
FileWriter fw = new FileWriter("copyText_1.txt");
//3、频繁的读写操作
int ch = 0;
while((ch=fr.read())!=-1)
{
fw.write(ch);
}
//4、关闭字节流
fw.close();
fr.close();
}
}

import java.io.FileReader;字符流的缓冲区
import java.io.FileWriter;
import java.io.IOException;
public class CopyTestDemo
{
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args)
{
FileReader fr = null;
FileWriter fw = null;
try
{
fr = new FileReader("demo.txt");
fw = new FileWriter("copytest_2.txt");
//创建一个临时容器,用于缓存读取到的数据
char[] buf = new char[BUFFER_SIZE];
//定义一个变量记录读取到的字符数(其实就是往数组里装字符个数)
int len = 0;
while((len = fr.read(buf))!= -1)
{
fw.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败!");
}
finally
{
if(fw!=null)
{
try
{
fw.close();
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
if(fr!=null)
{
try
{
fr.close();
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
}
}
}
缓冲区的出现提高了对数据的读写效率。原理:其实就是数组进行封装。对应的对象:BufferedWriter 特有方法:newLine():跨平台的换行符。BufferedReader 特有方法:readLine():一次读一行,到行标记时,将行标记之前的字符串返回。当读到末尾时们,返回null。在使用缓冲区对象时,要明确,缓冲的窜在是为了增强流的功能而存在,所有在建立缓冲区对象时,要先有流对象的存在。其实缓冲内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储。为了提高操作数据的效率。代码上的体现:写入缓冲区对象//建立缓冲区对象必须把流对象作为参数传递给缓冲区的构造函数。BufferedWriter bufw = new BufferedWriter(new FileWriter("buf.txt"));bufw.write("abce");//将数据写入到了缓冲区。bufw.flush();//对缓冲区的数据进行刷新。将数据刷到目的地中。bufw.close();//关闭缓冲区,其实关闭的是被包装在内部的流对象。读取缓冲区对象。BufferedReader bufr = new BufferedReader(new FileReader("buf.txt"));String line = null;//按照行的形式取出数据。取出的每一个行数据不包含回车符。while((line = bufr.readLine())!=null){System.out.println(line);}bufr.close(); 示例6:(提高写入效率,使用缓冲区)
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class CopyTestDemo
{
public static void main(String[] args) throws IOException
{
FileWriter fw = new FileWriter("buf.txt");
//为了提高写入的效率,使用了字符流的缓冲区
//创建了一个字符写入流的缓冲区对象,并且指定与被缓冲的流对象相关联
BufferedWriter bufw = new BufferedWriter(fw);
for(int x = 1;x<=4;x++)
{
bufw.write("abcde"+x);
//写入内容换行方法:newLine();
bufw.newLine();
//bufw.flush();
}
//使用缓冲区的刷新方法将数据刷目的地中
bufw.flush();
//关闭缓冲区,其实关闭的就是被缓冲的流对象
fw.close();
}
}

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
class BufferedReadDemo
{
public static void main(String[] args) throws IOException,FileNotFoundException
{
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line = bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
}
}

示例8:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
public class CopyTextBufTest
{
public static void main(String[] args) throws Exception
{
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);
bufw.newLine();
bufw.flush();
}
//方式二
/*int ch = 0;
while((ch = bufr.read())!=-1)
{
bufw.write(ch);
}*/
bufr.close();
bufw.close();
}
}

LineNumberReader
跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。示例1:
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class LineNumberReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("LineNumberReaderDemo.java");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(1000);
while((line = lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber()+":"+line);
}
lnr.close();
}
}

装饰设计模式对原有类进行了功能的改变,增强。示例1:
class Person
{
void chifan()
{
System.out.println("吃饭");
}
}
//采用装饰的方式增强Person类
//这个类的出现是为了增强Person而出现的
class NewPerson
{
private Person p;
NewPerson(Person p)
{
this.p = p;
}
public void chifan()
{
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
}
}
//采用继承的方式增强Person类
class NewPerson2 extends Person
{
public void chifan()
{
System.out.println( "开胃酒");
super.chifan();
System.out.println( "甜点");
}
}
public class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
NewPerson np1 = new NewPerson(p);
np1.chifan();
}
}

装饰和继承都能实现一样的特点:进行功能的扩展增强。有什么区别呢?
首先有一个继承体系:
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体
如果想要对操作的动作进行效率的提高,按照面向对象,可以通过继承的方式对具体的对象进行功能的扩展,那么就需要加入缓冲技术。
Writer
|--TextWriter:用于操作文本
|--BufferTextWriter:加入了缓冲技术的操作文本的对象
|--MediaWriter:用于操作媒体
|--BufferMediaWriter:加入了缓冲技术的操作媒体的对象
以上方式并不理想,如果这个体系需要再进行功能扩展,又多了更多流对象。这样就会发现只为提高功能,导致继承体系越来越臃肿,不够灵活。
重新思考问题:
既然加入的都是同一种技术--缓冲。前一种是让缓冲和自己的流对象相结合。可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲关联。Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体
|--BufferedWriter:用于提高效率
可见:装饰比继承灵活。
特点:装饰类和被装饰类都必须所属同一个接口或者父类。
示例2:(自定义一个读取缓冲区类,模拟一个BufferedReader)
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
class MyBufferedReader
{
private Reader r;
//定义一个数组作为缓冲区
private char[] buf = new char[1024];
//定义一个指针用于操作这个数组中的元素,当操作到最后一个元素后,指针应该归零
private int pos = 0;
//定义一个计数器用于记录缓冲区中的数据个数,当该数据减到0,就从源中继续获取数据到缓冲区中
private int count = 0;
MyBufferedReader(Reader r)
{
this.r = r;
}
//该方法从缓冲区一次取一个字符
public int myRead() throws IOException
{
//从源中获取一批数据到缓冲区中,需要先做判断,只有计数器为0时,才需要从源中获取数据
if(count==0)
{
count = r.read(buf);
//每次获取数据到缓冲区后,角标归零
pos = 0;
}
if(count<0)
return -1;
char ch = buf[pos];
pos++;
count--;
return ch;
}
public String myReadLine() throws IOException
{
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch = myRead())!=-1)
{
if(ch == '\r')
continue;
if(ch == '\n')
return sb.toString();
sb.append((char)ch);
}
if(sb.length()!=0)
{
return sb.toString();
}
return null;
}
public void myClose() throws IOException
{
r.close();
}
}
public class MyBufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("buf.txt");
MyBufferedReader bufr = new MyBufferedReader(fr);
String line = null;
while((line = bufr.myReadLine())!=null)
{
System.out.println(line);
}
bufr.myClose();
}
}

字节流抽象基类:InputStream,OutputStream。字节流可以操作任何数据。注意:字符流使用的数组是字符数组。char[] chs 字节流使用的数组是字节数组。byte[] btFileOutputStream fos = new FileOutputStream("a.txt");fos.write("abcde");//直接将数据写入到了目的地。fos.close();//只关闭资源。FileInputStream fis = new FileInjputStream("a.txt");//fis.available();//获取关联的文件的字节数。//如果文件体积不是很大。可以这样操作。byte[] buf = new byte[fis.available()];//创建一个刚刚好的缓冲区。//但是这有个弊端,就是文件过大,大小超出jvm的内容空间时,会内存溢出。fis.read(buf);System.out.println(new String(buf));需求:copy 一个图片。BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("1.jpg"));BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("2.jpg"));int by = 0;while((by=bufis.read())!=-1){bufos.write(by);}bufos.close();bufis.close();示例1:
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo
{
public static void main(String[] args)throws IOException
{
demo_write();
}
public static void demo_write() throws IOException
{
//1、创建字节输出流对象,用于操作文件
FileOutputStream fos = new FileOutputStream("bytedemo.txt");
//2、写数据,直接写入到了目的地中
fos.write("abcde".getBytes());
//关闭资源
fos.close();
}
}

示例2:
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamDemo
{
public static void main(String[] args) throws IOException
{
demo_read1();
System.out.println( "---------------");
demo_read2();
System.out.println( "---------------");
demo_read3();
}
public static void demo_read1() throws IOException
{
//1、创建一个读取流对象,和指定文件关联
FileInputStream fis = new FileInputStream("bytedemo.txt");
//打印字符字节大小,不过要少用,文件太大,可能内存溢出
byte[] buf = new byte[fis.available()];
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
public static void demo_read2() throws IOException
{
FileInputStream fis = new FileInputStream("bytedemo.txt");
//建议使用这种读取数据的方式
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
fis.close();
}
public static void demo_read3() throws IOException
{
FileInputStream fis = new FileInputStream("bytedemo.txt");
//一次读取一个字节
int ch = 0;
while((ch=fis.read())!=-1)
{
System.out.print((char)ch);
}
fis.close();
}
}

P.S.
FileOutputStream、FileInputStream的flush方法内容为空,没有任何实现,调用没有意义。
字节流的缓冲区:同样是提高了字节流的读写效率。
示例3:(通过几种方式对MP3的进行拷贝,比较他们的效率。)
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyMp3Test
{
public static void main(String[] args) throws IOException
{
long l1 = System.currentTimeMillis();
copy_1();
long l2 = System.currentTimeMillis();
System.out.println(l2-l1);//34
copy_2();
long l3 = System.currentTimeMillis();
System.out.println(l3-l2);//154
}
public static void copy_1() throws IOException
{
FileInputStream fis = new FileInputStream("0.mp3");
FileOutputStream fos = new FileOutputStream("1.mp3");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fis.close();
fos.close();
}
public static void copy_2() throws IOException
{
FileInputStream fis = new FileInputStream("0.mp3");
BufferedInputStream bufis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("2.mp3");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
int ch = 0;
while((ch=bufis.read())!=-1)
{
bufos.write(ch);
}
bufis.close();
bufos.close();
}
}

读取一个键盘录入的数据,并打印在控制台上。键盘本身就是一个标准的输入设备。对于java而言,对于这种输入设备都有对应的对象示例3:
import java.io.IOException;
import java.io.InputStream;
public class ReadKey
{
public static void main(String[] args) throws IOException
{
readKey();
}
public static void readKey() throws IOException
{
InputStream in = System.in;
int ch = in.read();//阻塞式方法
System.out.println(ch);
ch = in.read();
System.out.println(ch);
ch = in.read();
System.out.println(ch);
in.close();
}
}
