Java I/O流(1)——字符流操作

时间:2023-02-17 18:06:24
I/O流

按数据分为字节流和字符流(编码表,西方ASCII,中国gb2312扩容为gbk

——>统一为unicode
——>优化utf-8)
字符流是基于于字节流的,指定查什么表
按流向分为输入流和输出流。

常用基类:字节流 InputStream OutputStream
    字符流 Reader  Writer

字符流,比较直观

1、数据的最常见体现形式是文件
需求:在硬盘上创建一些文件,写入一些数据(OutputStreamWriter的子类FileWriter)
import java.io.*;
main() throws IOException
{
FileWriter fw=new FileWriter("demo.txt");
fw.write("abcde");//子类中没有什么方法了,看父类Writer的方法,子类就能用
fw.flush();
fw.write("haha");
fw.flush();

fw.close();//关闭前会刷新,不用再调用flush( )方法了

fw.write("hehe");//关闭了,再写就写不了了

}


I/O 异常的专业处理
import java.io.*;
main() 
{
FileWriter fw=null;
try{
fw=new FileWriter("demo.txt");
fw.write("abcde");
}
catch(IOException e)
{
System.out.println(e.toString());
 }

finally{

 try{

     if(fw!=null)   fw.close();

}

catch(IOException e)
{
System.out.println(e.toString());
       }
}
}
文件的续写,从其构造函数入手
FileWriter fw=new FileWriter("demo.txt",true);
fw.write("abcde");


2、文本文件的读取FileReader
(1)每次读取单个字符
main()
{
FileReader fr=new FileReader("demo.txt");
int ch=fr.read();
System.out.println("ch="+(char)ch);//读取一个字符

while(true)//读取一个字符把文件读完
{
int ch=fr.read();
if(ch==-1) break;
System.out.println("ch="+(char)ch);

}

fr.close();

}
 更好一点的写法
while((ch=fr.read())!=-1)
{
System.out,println((char)ch);
}
(2)每次读取一个数组的长度,把文件读完
char[] buf=new char[3];
int num=fr.read(buf);
System.out.println("num="+num+"--"+new String(buf));
//试图读取buf中的buf.length个字符,返回实际成功读取的字符数,文件尾返回-1。

  利用其返回值优化
char[] buf=new char[3];
int num=0;
while((ch=fr.read(buf))!=-1)
{
System.out.println(new String(buf,0,num));// String(char[] value, int offset, int count)
          // 分配一个新的 String,它包含取自字符数组参数一个子数组的字符。
             }

练习1:读取文件并打印在控制台上
练习2:将c盘的文件复制到d盘


2、字符流缓冲区,提高效率,而且不用一个字符一个字符读,可以每次读取一行。但需要刷新flush()

BufferedWriter            BufferedReader

(1)写
import java.io.*;
main() throws IOException
{
FileWriter fw=new FileWriter("demo.txt");

BufferedWriter bufw=new BufferedWriter(fw);


bufw.write("abcde");

bufw.newLine();//换行,代替\r\n或\n,各种操作系统通用


bufw.flush();

bufw.close();

fw.close();
}
(2) 读
main() throws IOException
{
FileReader fr=new FileReader("demo.txt");

BufferedReader bufr=new BufferedReader(fr);

String s1=bufr.readLine();
System.out.println(s1);

bufr.close();
fr.close();

}
改进一下,一直读一行,知道把所有的文件都读取完毕。
String line=null;
while((line=bufr.readLine())!=null)
{System.out.println(line);
}


练习:通过缓冲区复制Java文件


思想讲解:readLine()方法的原理\r\n
MyBufferedReader:自己做,基于FileReader的read()方法,将被增强的对象传给增强的对象
class MyBufferedReader
{
private FileReader r;
MyBufferedReader(FileReader r)
{
this.r=r;
}
public String myReadLine()
{ 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);
}
return null;
}
public void myClose()
{ r.close();}
}
main()
{
FileReader fr=new FileReader("demo.txt");
MyBufferedReader mbufr=new MyBufferedReader(fr);
String line=null;
while((line=mbufr.myReadLine())!=null)
{System.out.println(line);
}
mbufr.close();
}
上边这个例子就是装饰设计模式:当想要已有的对象进行功能增强时,定义一个类的已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类就称为装饰类。


3、装饰与继承的区别
MyReader
|——MyTextReader
      |——MyBufferTextReader
|——MyMediaReader
      |——MyBufferMediaReader
|——MyDataReader
      |——MyBufferDataReader
上面麻烦
class MyBufferReader
{
MyBufferReader(MyTextReader e){}
MyBufferReader(MyMediaReader e){}
~
}
上面这个也还是不太好,扩展性差,每次都要修改代码,找出其参数的共同类型,通过多态的形式,可以提高其扩展性
MyReader
|——MyTextReader
|——MyMediaReader
|——MyDataReader
|——MyBufferReader
class MyBufferReader extends MyReader
{
private MyReader r;//你中有我的组合结构
MyBufferReader(MyReader r)
{}
}
装饰模式比继承灵活,避免了继承体系的臃肿,降低了子类和子类之间的关系
4、BufferedReader的子类LineNumberReader这也是个装饰类
getLineNumber()

setLineNumber()

readLine()


main() throws Exception
{
FileReader fr=new FileReader("demo.txt");
LineNumberReader lnr=new LineNumberReader(fr);
String line=null;
lnr.setLineNumber(100);

while((line=lnr.myReadLine())!=null)
{System.out.println(lnr.getLineNumber()+":"+line);
}

lnr.close();
}
模拟一个带行号的缓冲区对象MyLineNumberReader
class MyLineNumberReader
{
private Reader r;
MyLineNumberReader(Reader r)
{
this.r=r;
}
private int lineNumber;
public void setLineNumber(int lineNumber)
{
this.lineNumber=lineNumber;
}
public void getLineNumber()
{
return lineNumber;
}

public String myReadLine() throws IOException
{ lineNumber++;

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()
{ r.close();}
}
main()
{
FileReader fr=new FileReader("demo.txt");
MyLineNumberReader mylnr=new MyLineNumberReader(fr);

String line=null;
while((line=mylnr.myReadLine())!=null)
{System.out.println(mylnr.getLineNumber()+":"+line);
}

mylnr.close();
}

代码优化:(让类继承自BufferedReader)
class MyLineNumberReader extend BufferedReader
{
MyLineNumberReader(Reader r)
{
super(r);
}
private int lineNumber;
public void setLineNumber(int lineNumber)
{
this.lineNumber=lineNumber;
}
public void getLineNumber()
{
return lineNumber;
}

public String myReadLine() throws IOException
{ lineNumber++;

/*
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;
*/

return super.myReadLine();
}
public void myClose()
{ r.close();}
}
main()
{
FileReader fr=new FileReader("demo.txt");
MyLineNumberReader mylnr=new MyLineNumberReader(fr);

String line=null;
while((line=mylnr.myReadLine())!=null)
{System.out.println(mylnr.getLineNumber()+":"+line);
}

mylnr.close();
}