IO流概述
IO流(Input Output)用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
字符流的特点:
IO流是用来操作数据的,那么数据的最常见形式是:文件
先以操作文件来演示IO流
需求:在硬盘上创建一个文件并写入一些文字数据
用到Writer的子类:后缀名是父类名,前缀名是功能;在API中找到一个专门用于操作文件的对象:FileWriter
创建FileWriter对象该对象一被初始化就必须要明确要操作的对象;没有空参的构造方法
而且该文件会被创建在指定的目录下,如果该目录已有同名文件则会被覆盖
其实该操作就是在明确数据要存放的目的地
FileWriter示例:
文件写入
import java.io.*;
class IODemo {
public static void main(String[] args) throws IOException //抛IO异常
{
FileWriter fw = new FileWriter("Demo.txt");//1,创建文本对象
fw.write("asdff"); //2,调用write方法,将字符串写入到流中
/// fw.flush(); //3,刷新流对象中缓冲区数据;到目的地中
fw.close(); //4,关闭流资源,并在关闭之前刷新一次缓冲区数据,刷到目的地中
//flush刷新后流可以继续使用,close刷新后会将流关闭
}
}
IO异常的处理:
new 、write、close都会造成IO异常,所以要做处理import java.io.*;
class FileWriterDemo2
{
public static void main(String[] args)
{
FileWriter fw = null; //将FileWriter外置,以调用finally中的close
try{
fw = new FileWriter("Demo.txt");
fw.write("haha");
}
catch (IOException e){
System.out.println("catch: "+e.toString());
}
finally{ //开启了几个写入流就要关闭几次,切记
try{
if(fw!==null) //一定要判断是否为null,因为close的操作要有对象
fw.close(); //要对异常进行处理
}
catch (IOException e){
System.out.println(e.toString());
}
}
}
}
文件的续写
FileWriter(" ",append)方法 append值为true时将数据写入文件末尾处,为false则覆盖原文件
try
{ //append值为true时将数据写入文件末尾处,为false则覆盖原文件
fw = new FileWriter("Demo.txt",true);//传递一个true
fw.write("换行\r\n文件续写");
}
FileRader
文本文件的读取
方法一:read()
该方法一次只读取一个字符,返回值为该字符在码表中对应的int值,到达文件末尾时返回-1
创建一个文件读取流对象,和指定名称的文件相关联
要保证该文件已经存在,否则会发生异常:FileNotFoundException
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("Demo.txt");//创建读取流
// int ch = fr.read(); //read一次只读取一个字符,多次调用则继续往下读;返回值为该字符在码表中的int值
int ch = 0; //循环获取文本内容
while ((ch = fr.read())!=-1)//read()到达文件末尾返回-1
{
System.out.print((char)ch);
}
fr.close();
}
}
方法二:read(char[] cbuf)
通过字符数组进行获取,该方法一次获取数组个数的字符,返回值为实际获取的元素个数,一般是数组长度,到达文件末尾时返回-1。read()和 read(char[] cbuf)都有in型的返回值,不同的是前者返回的是该字符在码表中对应的值,后者返回的是该字符数组的元素个数
示例:
import java.io.*;
class FileReader2
{
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("Demo.txt");
char[] buf = new char[1024];//定义数组用于存储读取的字数
// int num = fr.read(buf); //该read返回数组元素个数
// sop("num: "+num+" ... "+new String(buf));
int num ;//
while ((num=fr.read(buf)) !=-1){//read(char[] cbuf)到达文件末尾返回-1
sop(new String(buf,0,num) );
}
fr.close();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
内存示例:
文件内容的copy
将一个文件内容copy到另一个文件,要做整点掌握原理:1,创建一个文件,用于接收写入流2,定义读取流和目标文件关联3,通过不断的读写完成数据4,关闭资源
根据文件读取两种方式的不同,有两种copy方式,但原理是一致的
示例:
import java.io.*;
class CopyTest
{
public static void main(String[] args) throws IOException
{
// copy_1();
copy_2();
}
public static void copy_2() //方法二:利用数组,每次存取1024个字符,减少循环次数,提高效率
{
FileWriter fw = null;
FileReader fr = null;
try //异常要进行处理,不建议throws
{
fw = new FileWriter("CopyTest_copy.txt");
fr = new FileReader("CopyTest.java");
char[] buf = new char[1024];
int num;
while ((num=fr.read(buf)) !=-1){
fw.write(buf,0,num);//写入字符数组的某一部分,这么定义是因为末尾时num有不满足1024的情况
}
}
catch (IOException e){
throw new RuntimeException("访问失败");//处理异常,可以定义更加详细的规则
}
finally //关闭流的动作一定要执行,要分开写
{
if(fr!=null)//关闭流的动作一定要有对象,所以要做判断
try{
fr.close();
}
catch (IOException e)
{}
if(fw!=null)
try{
fw.close();
}
catch (IOException e)
{}
}
}
public static void copy_1() throws IOException//方法一:每次读写一个字符,循环次数多
{
FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");//1,写入流 创建目的地
FileReader fr = new FileReader("CopyTest.java"); //2,读取流 与已有文件关联
int ch;
while ((ch=fr.read()) !=-1)//3,读取
{
fw.write(ch); //写入
}
fw.close();//4,关闭流
fr.close();
}
}
文件的Copy过程简述:
文件读取流对象通过调用系统底层,将硬盘上的文件读取到内存中封装成数组,写入流将数组中的元素写入到硬盘的目的地中,读写完成后关闭两个流资源硬盘中源文件>读取流>内存中数组>写入流>目标文件>关闭流资源
字符流缓冲区
缓冲区的出现是为了提高流的操作效率,在开发中一般都要加缓冲区,提高性能在创建缓冲区之前,必须要现有流对象写入流缓冲区
BufferedWriter;是Writer的子类示例:
import java.io.*;
class BufferedWriterDemo
{
public static void main(String[] args) throws IOException
{
FileWriter fw = new FileWriter("buf.txt");
BufferedWriter bfw = new BufferedWriter(fw);//将要提高效率的流对象作为参数传递给缓冲区的构造函数
for (int x= 1; x<5; x++)
{
bfw.write("hahahah"+x); //子类继承自父类的方法
bfw.newLine(); //换行。缓冲区中跨平台的换行符, Windows和Linux中换行符是不一样的,为了保证Java的跨平台性
bfw.flush(); //只要用到了缓冲区,就要记得刷新
}
bfw.close(); //关闭缓冲区就是在关闭缓冲区中的流对象,所以不用再进行流对象的关闭动作
}
}
读取流缓冲区
该方法提供了一个一次读取一行的方法,方便与对文本文件的获取
readLine()方法,该方法返回含有该行内容的字符串,不包含换行符;到达流末尾则返回null
简写示例:
FileReader fr = new FileReader("buf.txt");//创建读取流 关联文件
BufferedReader bufr = new BufferedReader(fr);//为了提高效率,将字符读取流对象传递给缓冲区对象的构造函数
String line = null;
while ((line = bufr.readLine()) !=null)//readLine到达文件末尾返回null
{
System.out.println(line);
}
通过缓冲区复制文件
import java.io.*;
class CopyTextByBuf
{
public static void main(String[] args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader("CopyTextByBuf.java"));//copy当前java文件
bufw = new BufferedWriter(new FileWriter("BufferedWriter_copy.txt"));
String line = null;
while ((line=bufr.readLine()) !=null)//readLine()只返回回车符之前的内容
{
bufw.write(line); //
bufw.newLine(); //必须要换行
bufw.flush();
}
}
catch (IOException e){
throw new RuntimeException("访问失败");
}
finally{
try{
if(bufr !=null)
bufr.close();
}
catch (IOException e){
throw new RuntimeException("读取关闭失败");
}
try{
if(bufw !=null)
bufw.close();
}
catch (IOException e){
throw new RuntimeException("写入关闭失败");
}
}
}