java基础—IO (上)
一、字符流
1、字符流
字符流的由来:字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字。再对这个文字进行操作。简单说:字节流+编码表。
字符流的抽象基类:Reader,Writer。
文件读取方式:
第一种读取方式:使用read()方法读取文本文件数据。
第二种读取方式:使用read(char[] c)方法读取文本文件数据。
注意事项:
close方法只能用一次。
流关闭以后不能再调用write方法,否则会报异常。
文件复制示例:
- 需求:读取d盘demo.txt文件中的数据,将这些数据写入到d盘copyText_1.txt文件当中。使用字符流。
- 代码:
import java.io.*;
class CopyTextTest
{
public static void main(String[] args) throws IOException
{
//创建一个字符读取流与文件相关联
FileReader fr=new FileReader("demo.txt");
//创建一个目的,用于储存到读取的数据(若文件存在则覆盖)
FileWriter fw=new FileWriter("copyText_1.txt");
//使用read()方法逐个读取字符
int chr=0;
while ((chr=fr.read())!=-1)
{
//使用write方法将读取到的内容写入目的文件。
fw.write(chr);
//进行刷新,将数据直接写入到目的地中
fw.flush();
}
//关闭输入、输出流
fw.close();
fr.close();
}
}
- 输出结果:
2、字符流的缓冲区
字符流的缓冲区:缓冲区的出现提高了对数据的读写效率。
对应类
BufferedWriter
BufferedReader
LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
字符流缓冲区的示例:
- 代码:
import java.io.*;
class BufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个输入流与目的文件相关联
FileReader fr=new FileReader("buf.txt");
//将输入流传入一个缓冲区,提高了效率
BufferedReader bfrd=new BufferedReader(fr);
//存储的是原缓冲区一行的数据,不包含换行符
String line=null;
while ((line=bfrd.readLine())!=null)
{
System.out.println(line);
}
//关闭缓冲区就等于关闭输入流
bfrd.close();
}
}
- 输出结果:
二、字节流
字节流:基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。
字节流的抽象基类:InputStream,OutputStream。
示例:
- 获取用户键盘录入的数据并将数据变成大写显示在控制台上,如果用户输入的是over,结束键盘录入。
- 代码:
import java.io.*;
class ReadKey2
{
public static void main(String[] args) throws IOException
{
//创建容器
StringBuilder sb=new StringBuilder();
//获取键盘读取流
InputStream in=System.in;
//定义变量记录读取到的字节
int ch=0;
while((ch=in.read())!=-1)
{
if (ch=='\r')
continue;
if(ch=='\n')
{
String temp=sb.toString();
if ("over".equals(temp))
break;
//将输入的字符转成大写
System.out.println(temp.toUpperCase());
//清空容器
sb.delete(0,sb.length());
}
else
{
//将读取到的字节放到StringBuilder容器中
sb.append((char)ch);
}
}
}
}
- 输出结果:
三、装饰设计模式
作用:对原有类进行功能的改变,增强。
特点:
装饰比继承灵活
装饰类和被装饰类都必须所属同一个接口或者父类。
示例:
- 需求: 自定义一个读取缓冲区类,模拟一个BufferedReader
- 分析:缓冲区中无非就是封装了一个数组,并对外提供了更多的方法对数组进行访问,其实这些方法最终操作的都是数组的角标。
- 代码:
import java.io.*;
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();
}
}
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();
}
}
- 输出结果: