您的位置:首页 > 编程语言 > Java开发

Java基础知识——IO流(一)

2013-07-01 10:27 399 查看
IO流(Input Output)
一、     概述
(一)IO流的概述
1. IO流用来处理设备之间的数据传输
2. Java对数据的操作是通过流的方式
3. Java用于操作流的对象都在IO包中
4. 流按操作数据分为两种:字节流和字符流
5. 流按方向分为:输入流和输出流
 
(二)IO流常用基类
1.      字节流的抽象基类:InputStream、OutputStream
2.      字符流的抽象基类:Reader、Writer
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
 
字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢?

实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如图所示。
(三)字符流
在程序中一个字符等于两个字节,Java为我们提供了Reader和Writer两个专门操作字符流的类
 
---------------------------------------------------------------------------------------
字符输出流:Writer

Writer是一个字符流,它是一个抽象类,所以要使用它,也必须通过其子类来实例化它后才能使用它。
Writer类的常用方法
方法名称

描述

public abstract void close() throws IOException

关闭输出流

public void write(String str) throws IOException

将字符串输出

public void write(char cbuf) throws IOException

将字符数组输出

public abstract void flush() throws IOException

强制性清空缓存
----------------------------------------------------------------------------------------
字符输入流:Reader
 
Reader本身也是一个抽象类,同样,如果使用它,我们需要通过其子类来实例化它才可以使用它。
Reader类的常用方法
方法名称
描述
public abstract voidclose() throws IOException
 
public int read()throws IOException
 
 
public int read(char[] cbuf,int offset,int length)throwsIOException
 将字符读入数组中的某一部分
----------------------------------------------------------------------------------------------
事例:
 
既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件。
那么先以操作文件为主来演示。
 
需求:在硬盘上,创建一个文件并写入一些文字数据。找到一个专门用于操作文件的Writer子类对象:FileWriter。

import java.io.*;
class FileWriterDemo
{
publicstatic void main(String[] args)throws IOException
{
//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是在明确数据要存放的目的地。
FileWriterfw = newFileWriter("demo.txt");

//调用write方法,将字符串写入到流中。
fw.write("abcde");

//刷新流对象中的缓冲中的数据。
//将数据刷到目的地中。
//fw.flush();

//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地中。
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
fw.close();
}
}


============================================================
 
二、IO的异常处理方式:

import java.io.*;

class FileWriterDemo2
{
publicstatic void main(String[] args)
{
FileWriterfw = null;
try
{
fw= newFileWriter("demo.txt");
fw.write("abcdefg");

}
catch(IOException e)
{
System.out.println("catch:"+e.toString());
}
finally
{
try
{
if(fw!=null)
fw.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}

}

}
}


演示对已有文件的数据续写。
 
import java.io.*;
class FileWriterDemo3
{
publicstatic void main(String[] args)throws IOException
{

//传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。
FileWriterfw = newFileWriter("demo.txt",true);

fw.write("nihao\r\nxiexie");

fw.close();
}
}


=================================================================
 
 
三、文本的读取——字符流读取的两种方式
 
(一)第一种方式:通过字符读取
 

import java.io.*;

class FileReaderDemo
{
publicstatic void main(String[] args)throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReaderfr = newFileReader("demo.txt");

//调用读取流对象的read方法。
//read():一次读一个字符。而且会自动往下读。

intch = 0;

while((ch=fr.read())!=-1)
{
System.out.println(
}
fr.close();

}
}


------------------------------------------------------------------------------------------
(二)第二种读取方式:通过字符数组来读取
 

import java.io.*;

class FileReaderDemo2
{
publicstatic void main(String[] args)throws IOException
{
FileReaderfr = newFileReader("demo.txt");

//定义一个字符数组。用于存储读到字符。
//该read(char[])返回的是读到字符个数。
char[]buf = new char[1024];

intnum = 0;
while((num=fr.read(buf))!=-1)
{
System.out.println(newString(buf,0,num));
}

fr.close();
}
}


-----------------------------------------------------------------------------------------------------
 
(三)小练习:拷贝文本文件
 

//将C盘一个文本文件复制到D盘。

/*
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。

步骤:
1,在D盘创建一个文件。用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。
4,关闭资源。
*/

import java.io.*;

class CopyText
{
publicstatic void main(String[] args)throws IOException
{
copy_2();
}

/*------------------利用缓冲区拷贝文件--------------------------*/
publicstatic void copy_2()
{
FileWriterfw = null;
FileReaderfr = null;
try
{
fw= newFileWriter("SystemDemo_copy.txt");//写入流,目的
fr= newFileReader("SystemDemo.java");//读取流,源

char[]buf = newchar[1024]; //定义1k的缓冲区

intlen = 0;
while((len=fr.read(buf))!=-1)//每次读1k大小后写入
{
fw.write(buf,0,len);//定义len是为了确定最后一次不满足1k时的长度
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败");

}
finally  //close()语句是一定要执行的语句,放在finally中
{
if(fr!=null)
try
{
fr.close();//但是close()语句也会抛出异常,所以在此处理
}
catch(IOExceptione)
{
}
if(fw!=null)
try
{
fw.close();
}
catch(IOExceptione)
{
}
}
}
/*--------------------------------一次一个字节的拷贝文件--------------------------*/
//从C盘读一个字符,就往D盘写一个字符。
publicstatic void copy_1()throwsIOException
{
//创建目的地。
FileWriterfw = newFileWriter("RuntimeDemo_copy.txt");

//与已有文件关联。
FileReaderfr = newFileReader("RuntimeDemo.java");

intch = 0;

while((ch=fr.read())!=-1)
{
fw.write(ch);
}

fw.close();
fr.close();

}

}


==============================================================
四、字符流的缓冲区
(一)简要介绍
1.      缓冲区的出现提高了对字符的读写效率
2.      对应类:BufferedReader  BufferedWriter
3.      缓冲区要结合流才可以使用
4.      在流的基础上对流的功能进行了增强(装饰设计模式)
-----------------------------------------------------------------------------------------------------------
(二)BufferedWriter
 
 
缓冲区的出现是为了提高流的操作效率而出现的。
 
所以在创建缓冲区之前,必须要先有流对象。
 
该缓冲区中提供了一个跨平台的换行符。
newLine();

import java.io.*;

classBufferedWriterDemo
{
publicstatic void main(String[] args)throws IOException
{
//创建一个字符写入流对象。
FileWriterfw = newFileWriter("buf.txt");
//为了提高字符写入流效率。加入了缓冲技术。
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriterbufw = newBufferedWriter(fw);

for(intx=1; x<5; x++)
{
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush();
}

//记住,只要用到缓冲区,就要记得刷新。
//bufw.flush();

//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();

}
}


---------------------------------------------------------------------------------------------------------
(三)BufferWriter
 
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
 
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
 

import java.io.*;

classBufferedReaderDemo
{
publicstatic void main(String[] args)throws IOException
{
//创建一个读取流对象和文件相关联。
FileReaderfr = newFileReader("buf.txt");

//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReaderbufr = newBufferedReader(fr);

Stringline = null;

while((line=bufr.readLine())!=null)
{
System.out.print(line);
}

bufr.close();
}

}


--------------------------------------------------------------------------------------------------------------------
 
(四)小练习一
通过缓冲区复制文本文件
 

import java.io.*;

class CopyTextByBuf
{
publicstatic void main(String[] args)
{
BufferedReaderbufr = null;
BufferedWriterbufw = null;

try
{
bufr= new BufferedReader(newFileReader("BufferedWriterDemo.java"));
bufw= newBufferedWriter(new FileWriter("bufWriter_Copy.txt"));

Stringline = null;

while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();

}
}
catch(IOException e)
{
thrownew RuntimeException("读写失败");
}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch(IOException e)
{
thrownewRuntimeException("读取关闭失败");
}
try
{
if(bufw!=null)
bufw.close();
}
catch(IOException e)
{
thrownewRuntimeException("写入关闭失败");
}
}
}
}


 
--------------------------------------------------------------------------------------------------------------------------
(五)小练习二
自定义一个类中包含一个功能和readLine一致的方法。
来模拟一下BufferedReader
 

import java.io.*;
classMyBufferedReader extends Reader//继承Reader类,父类方法直接用
{

privateReader r;
MyBufferedReader(Readerr)
{
this.r= r;
}

//可以一次读一行数据的方法。
publicString myReadLine()throwsIOException
{
//定义一个临时容器。原BufferReader封装的是字符数组。
//定义一个StringBuilder容器。因为最终还是要将数据变成字符串。
StringBuildersb = newStringBuilder();
intch = 0;
while((ch=r.read())!=-1)
{
if(ch=='\r')
continue;
if(ch=='\n')
returnsb.toString(); //读到”\r\n”换行符后一次将StringBuilder中数据写出
else
sb.append((char)ch);
}

if(sb.length()!=0)
returnsb.toString();
returnnull;
}

/*
覆盖Reader类中的抽象方法。

*/
publicint read(char[] cbuf, int off, intlen) throws IOException
{
returnr.read(cbuf,off,len) ;
}

publicvoid close()throws IOException
{
r.close();
}
publicvoid myClose()throws IOException
{
r.close();
}
}

classMyBufferedReaderDemo
{
publicstatic void main(String[] args)throws IOException
{
FileReaderfr = newFileReader("buf.txt");

MyBufferedReadermyBuf = newMyBufferedReader(fr);

Stringline = null;

while((line=myBuf.myReadLine())!=null)
{
System.out.println(line);
}

myBuf.myClose();
}
}


 

===================================================================
五、装饰设计模式
(一)简单介绍
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。
 
装饰类通常会通过构造方法接收被装饰的对象。
并基于被装饰的对象的功能,提供更强的功能。
 
------------------------------------------------------------------------------------------------
(二)举例说明

class Person
{
publicvoid chifan()
{
System.out.println("吃饭");
}
}

class SuperPerson
{
privatePerson p ;
SuperPerson(Personp)
{
this.p= p;
}
publicvoid superChifan()
{
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
System.out.println("来一根");
}
}

class PersonDemo
{
publicstatic void main(String[] args)
{
Personp = new Person();

//p.chifan();

SuperPersonsp = newSuperPerson(p);
sp.superChifan();

}
}


(三)LineNumberReader——带行号的Reader
 

import java.io.*;

classLineNumberReaderDemo
{
publicstatic void main(String[]args)throws IOException
{
FileReaderfr = newFileReader("PersonDemo.java");

LineNumberReaderlnr = newLineNumberReader(fr);

Stringline = null;
lnr.setLineNumber(100);//从100开始计算行号
while((line=lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber()+":"+line);
}

lnr.close();
}
}


 
(四)练习:模拟一个带行号的缓冲区对象
 

import java.io.*;

classMyLineNumberReader extends MyBufferedReader
{
privateint lineNumber;//定义行号变量

MyLineNumberReader(Readerr) //构造函数
{
super(r);
}

publicString myReadLine()throwsIOException
{

lineNumber++;
returnsuper.myReadLine();
}
publicvoid setLineNumber(int lineNumber)//设置行号
{
this.lineNumber= lineNumber;
}
publicint getLineNumber()//获得行号
{
returnlineNumber;
}
}

classMyLineNumberReaderDemo
{
publicstatic void main(String[] args)throws IOException
{
FileReaderfr = newFileReader("copyTextByBuf.java");

MyLineNumberReadermylnr = newMyLineNumberReader(fr);

Stringline = null;
mylnr.setLineNumber(100);//从100开始输出行号

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

mylnr.myClose();
}
}
/*
classMyLineNumberReader
{
privateReader r;
privateint lineNumber;
MyLineNumberReader(Readerr)
{
this.r= r;
}

publicString myReadLine()throwsIOException
{

lineNumber++;
StringBuildersb = newStringBuilder();

intch = 0;

while((ch=r.read())!=-1)
{
if(ch=='\r')
continue;
if(ch=='\n')
returnsb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
returnsb.toString();
returnnull;
}
publicvoid setLineNumber(int lineNumber)
{
this.lineNumber= lineNumber;
}
publicint getLineNumber()
{
returnlineNumber;
}

publicvoid myClose()throws IOException
{
r.close();
}
}
*/


===============================================================
六、字节流文件的读写操作
(一)字节流(bytestream)
不包含边界数据的连续流
字节流是由字节组成的,字符流是由字符组成的. Java里字符由两个字节组成.字节流是最基本的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化。在从字节流转化为字符流时,实际上就是byte[]转化为String时,public
String(byte bytes[], String charsetName)有一个关键的参数字符集编码,通常我们都省略了,那系统就用操作系统默认的lang
------------------------------------------------------------------------------------------------
 
 
(二)三种读取方式
 
字符流:
FileReader
FileWriter。
 
BufferedReader
BufferedWriter
 
字节流:
InputStream OutputStream
 
需求,想要操作图片数据。这时就要用到字节流。
复制一个图片.

import java.io.*;
class FileStream
{
publicstatic void main(String[] args)throws IOException
{
readFile_3();
}

//方法三:定义一个刚刚好的缓冲区
publicstatic void readFile_3()throwsIOException
{
FileInputStreamfis = newFileInputStream("fos.txt");

//            intnum = fis.available();
byte[]buf = newbyte[fis.available()];//定义一个刚刚好的缓冲区。不用在循环了。

fis.read(buf);

System.out.println(newString(buf));

fis.close();
}

/*定义一个刚刚好的缓冲区也有弊端,那就是很占内存,因为必须一次性将整个文件读入,而过大的文件不能用这样的方法*/
//------------------------------------------------------------------------------------------

//方法二:定义一个1024整数倍的缓冲区

publicstatic void readFile_2()throwsIOException
{
FileInputStreamfis = newFileInputStream("fos.txt");

byte[]buf = new byte[1024];
intlen = 0;
while((len=fis.read(buf))!=-1)
{
System.out.println(newString(buf,0,len));
}

fis.close();

}

/*方法二更为常用,可以根据文件大小动态调整缓冲区大小*/

//-----------------------------------------------------------------------------------

//方法一:一次一个字符的读取

publicstatic void readFile_1()throwsIOException
{
FileInputStreamfis = newFileInputStream("fos.txt");

intch = 0;

while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}

fis.close();
}
/*这种读写方式非常慢,不建议使用*/

//-----------------------------------------------------------------------------------
publicstatic void writeFile()throwsIOException
{
FileOutputStreamfos = newFileOutputStream("fos.txt");

fos.write("abcde".getBytes());

fos.close();
}
}


===========================================================
(三)练习:复制一个图片
 
思路:
1,用字节读取流对象和图片关联。
2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3,通过循环读写,完成数据的存储。
4,关闭资源。
 

import java.io.*;
class CopyPic
{
publicstatic void main(String[] args)
{
FileOutputStreamfos = null;
FileInputStreamfis = null;
try
{
fos= newFileOutputStream("c:\\2.bmp"); //目的
fis= newFileInputStream("c:\\1.bmp"); //源

byte[]buf = new byte[1024];

intlen = 0;

while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch(IOException e)
{
thrownewRuntimeException("复制文件失败");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch(IOException e)
{
thrownewRuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch(IOException e)
{
thrownewRuntimeException("写入关闭失败");
}
}
}
}


------------------------------------------------------------------------------------------------
(四)通过缓冲区复制MP3
 

/*
演示mp3的复制。通过缓冲区。
BufferedOutputStream
BufferedInputStream
*/
import java.io.*;
class CopyMp3
{
publicstatic void main(String[] args)throws IOException
{
longstart =System.currentTimeMillis();
copy_2();
longend =System.currentTimeMillis();

System.out.println((end-start)+"毫秒");
}

publicstatic void copy_2()throwsIOException
{
BufferedInputStreambufis = newBufferedInputStream(new FileInputStream("c:\\9.mp3"));
BufferedOutputStreambufos = newBufferedOutputStream(new FileOutputStream("c:\\3.mp3"));

intby = 0;

//System.out.println("第一个字节:"+bufis.myRead());

while((by=bufis.myRead())!=-1)
{
bufos.write(by);
}

bufos.close();
bufis.myClose();
}

//通过字节流的缓冲区完成复制。
publicstatic void copy_1()throwsIOException
{
BufferedInputStreambufis = newBufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStreambufos = newBufferedOutputStream(new FileOutputStream("c:\\1.mp3"));

intby = 0;

while((by=bufis.read())!=-1)
{
bufos.write(by);
}

bufos.close();
bufis.close();

}
}


--------------------------------------------------------------------------------------------------
(五)自定义字节流的缓冲区

import java.io.*;

classMyBufferedInputStream
{
privateInputStream in;

privatebyte[] buf = new byte[1024*4];

privateint pos = 0,count = 0;

MyBufferedInputStream(InputStreamin)
{
this.in= in;
}

//一次读一个字节,从缓冲区(字节数组)获取。
publicint myRead()throws IOException
{
//通过in对象读取硬盘上数据,并存储buf中。
if(count==0)
{
count= in.read(buf);
if(count<0)
return-1;
pos= 0;
byteb = buf[pos];

count--;
pos++;
returnb&255;//取最低八位
}
elseif(count>0)
{
byteb = buf[pos];

count--;
pos++;
returnb&0xff; //十六进制的255
}
return-1;

}
publicvoid myClose()throws IOException
{
in.close();
}
}


11111111-111111110000000000101001001010100101010010101001010
 
byte: -1 --->  int : -1;
00000000 00000000 00000000 11111111  255
 
11111111 11111111 11111111 11111111
 
11111111 -->提升了一个int类型 那不还是-1吗?是-1的原因是因为在8个1前面补的是1导致的。
那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。
怎么补0呢?
 
 11111111 11111111 1111111111111111                       
&00000000 00000000 00000000 11111111
------------------------------------
 00000000 00000000 00000000 11111111
 
0000-0001
1111-1110
000000001
1111-1111 -1
 
结论:
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。
 
而在写入数据时,只写该int类型数据的最低8位。
 
 
(六)读取键盘录入
 
读取键盘录入。
System.out:对应的是标准输出设备,控制台。
System.in:对应的标准输入设备:键盘。
 
 
需求:
通过键盘录入数据。
当录入一行数据后,就将该行数据进行打印。
如果录入的数据是over,那么停止录入。
 

import java.io.*;
class ReadIn
{
publicstatic void main(String[] args)throws IOException
{
InputStreamin = System.in;
StringBuildersb = newStringBuilder();

while(true)
{
intch = in.read();
if(ch=='\r')
continue;
if(ch=='\n')
{
Strings = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());
}
else
sb.append((char)ch);

}
}
}


===================================================================
七、读取转换流和写入转换流
(一)概述
读取转换流InputStreamReader
InputStreamReader是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在BufferedReader 内包装InputStreamReader。例如:
 BufferedReader in
   = new BufferedReader(new InputStreamReader(System.in));
----------------------------------------------------------------------------------------------------
 
写入转换流OutputStreamWriter
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。
为了获得最高效率,可考虑将OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如:
 Writer out
   = new BufferedWriter(new OutputStreamWriter(System.out));
 
--------------------------------------------------------------------------------------------------------------
(二)举例说明
 
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。
 
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
 
 
readLine方法是字符流BufferedReader类中的方法。
 
而键盘录入的read方法是字节流InputStream的方法。
 
那么能不能将字节流转成字符流在使用字符流缓冲去的readLine方法呢?
 

import java.io.*;

class TransStreamDemo
{
publicstatic void main(String[] args)throws IOException
{
//获取键盘录入对象。
//InputStreamin = System.in;

//将字节流对象转成字符流对象,使用转换流。InputStreamReader
//InputStreamReaderisr = newInputStreamReader(in);

//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader

//BufferedReaderbufr = newBufferedReader(isr);

//键盘的最常见写法。
BufferedReaderbufr =
newBufferedReader(new InputStreamReader(System.in));

//            OutputStreamout = System.out;
//            OutputStreamWriterosw = newOutputStreamWriter(out);
//            BufferedWriterbufw = newBufferedWriter(osw);
BufferedWriterbufw = newBufferedWriter(new OutputStreamWriter(System.out));

Stringline = null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();

}
}


=======================================================================
八、总结——流操作规律
 
 
(一)流操作的基本规律
最痛苦的就是流对象有很多,不知道该用哪一个。
 
通过三个明确来完成。
 
1,明确源和目的。
       源:输入流。InputStream  Reader
       目的:输出流。OutputStream  Writer。
 
2,操作的数据是否是纯文本。
       是:字符流。
       不是:字节流。
 
3,当体系明确后,在明确要使用哪个具体的对象。
       通过设备来进行区分:
       源设备:内存,硬盘。键盘
       目的设备:内存,硬盘,控制台。
 
 
举例1:
1,将一个文本文件中数据存储到另一个文件中。复制文件。
      
源:因为是源,所以使用读取流。InputStreamReader
       是不是操作文本文件。
       是!这时就可以选择Reader
       这样体系就明确了。
 
       接下来明确要使用该体系中的哪个对象。
       明确设备:硬盘。上一个文件。
       Reader体系中可以操作文件的对象是 FileReader
 
       是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.
 
      FileReaderfr = new FileReader("a.txt");
      BufferedReaderbufr = new BufferedReader(fr);
 
 
目的:OutputStreamWriter
       是否是纯文本。
       是!Writer。
       设备:硬盘,一个文件。
       Writer体系中可以操作文件的对象FileWriter。
       是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter
      
      FileWriterfw = new FileWriter("b.txt");
      BufferedWriterbufw = new BufferedWriter(fw);
 
 
练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。
 
 
------------------------------------------------------------------
 
 
举例2:
需求:将键盘录入的数据保存到一个文件中。
       这个需求中有源和目的都存在。
       那么分别分析
      
源:InputStreamReader
       是不是纯文本?是!Reader
      
       设备:键盘。对应的对象是System.in.
       不是选择Reader吗?System.in对应的不是字节流吗?
       为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
       所以既然明确了Reader,那么就将System.in转换成Reader。
       用了Reader体系中转换流,InputStreamReader
 
      InputStreamReaderisr = new InputStreamReader(System.in);
 
       需要提高效率吗?需要!BufferedReader
      BufferedReaderbufr = new BufferedReader(isr);
 
      
目的:OutputStream Writer
       是否是存文本?是!Writer。
       设备:硬盘。一个文件。使用 FileWriter。
      FileWriterfw = new FileWriter("c.txt");
       需要提高效率吗?需要。
      BufferedWriterbufw = new BufferedWriter(fw);
 
 
      ************************************************************
扩展      
想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
      
       目的:OutputStream  Writer
       是否是存文本?是!Writer。
       设备:硬盘。一个文件。使用 FileWriter。
       但是FileWriter是使用的默认编码表。GBK.
      
       但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
       所以要使用的对象是OutputStreamWriter。
       而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream
 
      OutputStreamWriterosw = newOutputStreamWriter(newFileOutputStream("d.txt"),"UTF-8");
 
       需要高效吗?需要。
      BufferedWriterbufw = new BufferedWriter(osw);
 
       所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
       需要用到转换流。
 
----------------------------------------------------------------------------------------------------------------------
(二)练习
将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
 

import java.io.*;

classTransStreamDemo2
{
publicstatic void main(String[] args)throws IOException
{
System.setIn(newFileInputStream("PersonDemo.java"));//改变标准输入设备

System.setOut(newPrintStream("zzz.txt"));//改变标准输出设备

//键盘的最常见写法。一定要记住!!!
BufferedReaderbufr =
newBufferedReader(new InputStreamReader(System.in));

BufferedWriterbufw = newBufferedWriter(new OutputStreamWriter(System.out));

Stringline = null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();

}
}


---------------------------------------------------------------------------------------------
(三)异常的日志信息
 

import java.io.*;
import java.util.*;
import java.text.*;
class ExceptionInfo
{
publicstatic void main(String[]args)throws IOException
{
try
{
int[]arr = new int[2];
System.out.println(arr[3]);
}
catch(Exception e)
{

try
{
Dated = new Date();
SimpleDateFormatsdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Strings =sdf.format(d);

PrintStreamps = newPrintStream("exeception.log");
ps.println(s);
System.setOut(ps);

}
catch(IOException ex)
{
thrownewRuntimeException("日志文件创建失败");
}
e.printStackTrace(System.out);
}
}
}
//实际开发当中我们使用的是log4j


 
保存系统信息:

import java.util.*;
import java.io.*;
class SystemInfo
{
publicstatic void main(String[] args)throws IOException
{
Propertiesprop =System.getProperties();

//System.out.println(prop);
prop.list(newPrintStream("sysinfo.txt"));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: