3.1、为什么会出现字符流
由于字节流操作中文不是特别方便,所以Java就提供字符流
- 字符流=字节流+编码表
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中,如何实现拼接的呢?
- 汉字在存储时,无论选择哪种编码存储,第一个字节都是负数
package itheima06;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;
/*
一个汉字
如果是GBK编码,占用2个字节 开头的字节都是负数
如果是UTF-8编码,占用3个字节 开头的字节都是负数
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
/*// FileInputStream fis=new FileInputStream("D:\\itcast\\java.txt");
FileInputStream fis=new FileInputStream("myByteStream\\a.txt");
int len;
// byte [] bys=new byte[1024];
while((len=fis.read())!=-1){
// System.out.println(new String(bys,0,len));
System.out.print((char) len);
}
fis.close();
*/
// String s="abc";输出//[97, 98, 99]
String s="中国";
// byte[] bytes = s.getBytes();//一个汉字对应了三个UTF-8编码[-28, -72, -83, -27, -101, -67]
// 说明默认是UTF-8编码
//当我们指定GBK编码是,一个汉字对应的就是两个字节
// byte[] bytes = s.getBytes("UTF-8");等价于 byte[] bytes = s.getBytes();
byte[] bytes = s.getBytes("GBK");//[-42, -48, -71, -6]
System.out.println(Arrays.toString(bytes));
}
}
3.2、编码表
基础知识:
用什么字符集存储(编码),就用对用的字符集解码
字符集:系统支持的所有字符的集合,包括各国文字,标点、图形符号、数字
常见的字符集有
ASCII:
ASCII 码使用指定的 7 位或 8 位二进制数组合来表示 128 或 256 种可能的字符。标准 ASCII 码也叫基础ASCII码,使用 7 位二进制数来表示所有的大写和小写字母,数字 0 到 9、标点符号, 以及在美式英语中使用的特殊控制字符。其中:
0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(振铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;ASCII值为 8、9、10 和 13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响。
32~126(共95个)是字符(32sp是空格),其中48~57为0到9十个阿拉伯数字;
65~90为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。
同时还要注意,在标准ASCII中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。
后128个称为扩展ASCII码,目前许多基于x86的系统都支持使用扩展(或“高”)ASCII。扩展 ASCII 码允许将每个字符的第 8 位用于确定附加的 128 个特殊符号字符、外来语字母和图形符号。
GBXXX字符集
- GB2312:简体中文码表,ASCII中有的127个称为半角字符,127以上的称为全角字符
- GBK: 最常用的中文编码表,使用了双字节编码表方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
Unicode字符集:
为了表达任意语言字符而设计,是业界的一种标准,也成为统一码,万国码。它最多使用4个字节的数字来表达每个字母、符号、或文字。有三种编码方案:UTF-8、UTF-16、UTF32. UTF-8最常用
UTF-8:
编码规则:
128个US-ASCII字符,只需一个字节编码
拉丁文等字符,需要两个字节编码
大部分常用语(含中文),使用三个字解码编码
其他极少数使用Unicode辅助字符,使用四字节编码
注:采用何种规则编码,就要采用对应的规则解码,否则就会出现乱码。
3.3、字符串中的编码解码问题
编码:
byte[] getBytes() 使用平台的默认字符集(UTF-8)将该String编码为一系列字节,将结果存储到字节数组中
byte[] getBytes(String CharStream) 使用指定的字符集,将该String编码为一系列字节,将结果存储到字节数组中
解码:
String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数组来构造新的String
String(byte[] bytes,String CharStream) 通过使用指定的字符集解码指定的字节数组来构造新的String
package com.itheima01;
/*
编码:
byte[] getBytes() 使用平台的默认字符集(UTF-8)将该String编码为一系列字节,将结果存储到字节数组中
byte[] getBytes(String CharStream) 使用指定的字符集,将该String编码为一系列字节,将结果存储到字节数组中
解码:
String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数组来构造新的String
String(byte[] bytes,String CharStream) 通过使用指定的字符集解码指定的字节数组来构造新的String
*/
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
/*
// 默认UTF—8编码:
// byte[] getBytes() 使用平台的默认字符集(UTF-8)将该String编码为一系列字节,将结果存储到字节数组中
String s="我爱你";
byte[] bytes = s.getBytes();
System.out.println(Arrays.toString(bytes));
//默认UTF-8每个字用三个数字表示[-26, -120, -111, -25, -120, -79, -28, -67, -96]
// 默认UTF-8解码:
// String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数组来构造新的String
// String ss=new String(bytes);
// System.out.println(ss);//解码的结果为: 我爱你
String sss=new String(bytes,"GBK");
System.out.println(sss);//编码解码用的字节符不同时 的结果乱码: 鎴戠埍浣�
*/
// GBK编码:
// byte[] getBytes(String CharStream) 使用指定的字符集,将该String编码为一系列字节,将结果存储到字节数组中 byte[] getBytes() 使用平台的默认字符集(UTF-8)将该String编码为一系列字节,将结果存储到字节数组中
String s="我爱你";
byte[] bytes = s.getBytes("GBK");
System.out.println(Arrays.toString(bytes));
//GBK每个字用2个数字表示[-50, -46, -80, -82, -60, -29]
// GBK解码:
// String(byte[] bytes,String CharStream) 通过使用指定的字符集解码指定的字节数组来构造新的String String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数组来构造新的String
String sss=new String(bytes,"GBK");
System.out.println(sss);//解码结果乱码: 我爱你�
}
}
3.4、字符流中的编码解码问题
字符流抽象基类
- Reader:字符输入流的抽象类
- Writer:字符输出流的抽象类
字符流中和编码解码问题相关的两个类
- InputStreamReader 从字节流到字符流的桥梁
- OutputStreamWriter
package com.itheima02;
/*
InputStreamReader 是从字节流到字符流的桥梁
他读取字节,并使用指定的编码将其解码为字符
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
OutputStreamWriter 是从字符流到字节流的桥梁
使用指定的编码将写入的字符编码为字符
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
*/
import java.io.*;
import java.util.Arrays;
public class ConversionStreamDemo {
public static void main(String[] args) throws IOException {
// OutputStreamWriter(OutputStream out)创建一个默认字符编码的OutputStreamWriter
// OutputStreamWriter(OutputStream out,String charsetName)创建一个指定字符编码的OutputStreamWriter
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"),"GBK");
// 当我们指用GBK编码字符串"中国" 写数据
osw.write("中国");//编码的结果就是 �й�
osw.close();
// InputStreamReader(InputStream in) 创建一个默认字符集的InputStreamReader
// InputStreamReader(InputStream in,Stirng CharsetName) 创建一个默认字符集的InputStreamReader
InputStreamReader isr=new InputStreamReader(new FileInputStream("myCharStream\\osw.txt"),"GBK");
// 一次读取一个字符,需要读两次,第一次读"中","国"
/* int ch= isr.read();
System.out.println((char) ch);
ch= isr.read();
System.out.println((char) ch);*/
// 一次读取字符数组
int ch;
while ((ch=isr.read())!=-1)
{
System.out.print((char) ch);//�й�
}
//优化改进一次读一个数组
/* int len;
byte[] bys=new byte[1024];
while((len=isr.read(bys))!=-1){
// System.out.println(len);
System.out.println(new String(bys,0,len));
}*/
/*
int len;
byte [] bys=new byte[1024];
while((len= bis.read(bys))!=-1){
System.out.print(new String(bys,0,len));
}
*/
isr.close();
}
}
3.5、字符流写数据的5种方式
void writer (int c) 写一个字符 void writer (char[] cbuf) 写一个字符数字 void writer (char[] cbuf,int off,int len) 写入一个字符数组的一部分 void writer (String str) 写一个字符串 void writer (String str,int off,int len) 写入一个字符串的一部分
package com.itheima03;
/*
构造方法:
InputStreamReader(InputStream in) 创建一个试用默认字符集的InputStreamReader
读数据的2种方式
int read()一次读一个字符数据
int read(char[] cbuf)一次读一个字符数组数据
*/
import java.io.*;
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
// 先写一个GBK编码的文件,然后再用InpuStreamReader来读数据
OutputStreamWriter osw2=new OutputStreamWriter(new FileOutputStream("myCharStream\\osw2.txt"),"GBK");
// void writer (int c) 写一个字符
String s1="我";
String s2="爱";
String s3="你";
osw2.write(s1);
osw2.write(s2);
osw2.write(s3);
osw2.close();
/* InputStreamReader isr=new InputStreamReader(new FileInputStream("myCharStream\\osw2.txt"),"GBK");
// int read()一次读一个字符数据
*//* int ch;
while((ch= isr.read())!=-1){
System.out.print((char) ch);
}*//*
// int read(char[] cbuf)一次读一个字符数组数据
// String[] s=new String[1024];
char [] chs=new char[1024];
int len;
while((len= isr.read(chs))!=-1){
// 把一个字符串数组转换成字符
System.out.print(new String(chs,0,len));
}*/
// 重新问一个文件读取数据
InputStreamReader isr=new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
// int read()一次读一个字符数据
/* int ch;
while((ch= isr.read())!=-1){
System.out.print((char) ch);
}*/
// int read(char[] cbuf)一次读一个字符数组数据
// String[] s=new String[1024];
/*char [] chs=new char[1024];
int len;
while((len= isr.read(chs))!=-1){
// 把一个字符串数组转换成字符
System.out.print(new String(chs,0,len));
}*/
copy();
}
//创建一个方法用来copy ConversionStreamDemo.java 并将改文件复制到copy.java中
public static void copy() throws IOException {
// 先用InputStreamReader读取ConversionStreamDemo.java文件
InputStreamReader isr=new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
// 然后用OutputStreamWriter将ConversionStreamDemo.java文件字节流写入copy.java中
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("myCharStream\\copy.java"));
char[] chs=new char[1024];
int len;
while((len= isr.read(chs))!=-1)
{
System.out.println(new String(chs,0,len));
osw.write(chs);
}
isr.close();
osw.close();
}
}
案例:
需求:把目录下的ConversionStreamDemo.java复制到模块目录下的copy.java
用了两个子类简化创建对象
FileReader 替代InputStreamReader 但是有缺点就是不能用来指定字符集
FileWriter 替代OutputStreamWriter 但是有缺点就是不能用来指定字符集
package com.itheima03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/*
需求:把目录下的ConversionStreamDemo.java复制到模块目录下的copy.java
用了两个子类简化创建对象
FileReader 替代InputStreamReader 但是有缺点就是不是能用来指定字符集
FileWriter 替代OutputStreamWriter 但是有缺点就是不是能用来指定字符集
*/
public class copyDemo {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("myCharStream\\ConversionStreamDemo.java");
FileWriter fw=new FileWriter("myCharStream\\copy.java");
char[] chs=new char[1024];
int len;
while((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
}
fr.close();
fw.close();
}
}
3.7、字符缓冲流
BufferedWriter 将文本写入字符输出流,缓冲字符,以提供单个字符,
数组和字符串的高效写入,可以制定缓冲区大小,或者接收默认大小(默认足够大)
BufferedReader 从字符输入流读取文本,缓冲字符,以提供字符,
数组和行字符串的高效读取,可以制定缓冲区大小,或者接收默认大小(默认足够大)
构造方法:
BufferedWriter(Writer out)
BufferedReader(Reader in)
案例需求:把目录下的ConversionStreamDemo.java复制到模块目录下的copy.java
package com.itheima04;
/*
需求:把目录下的ConversionStreamDemo.java复制到模块目录下的copy.java
BufferedWriter 将文本写入字符输出流,缓冲字符,以提供单个字符,
数组和字符串的高效写入,可以制定缓冲区大小,或者接收默认大小(默认足够大)
BufferedReader 从字符输入流读取文本,缓冲字符,以提供字符,
数组和行字符串的高效读取,可以制定缓冲区大小,或者接收默认大小(默认足够大)
构造方法:
BufferedWriter(Writer out)
BufferedReader(Reader in)
*/
import java.io.*;
public class BufferedDemo {
public static void main(String[] args) throws IOException {
long starTime=System.currentTimeMillis();
buffered();
long endTime=System.currentTimeMillis();
System.out.println("用字符缓冲流写的程序耗时:"+(endTime-starTime)+"毫秒");
}
public static void buffered() throws IOException {
BufferedWriter bw=new BufferedWriter(new FileWriter("myCharStream\\copy.java"));
BufferedReader br=new BufferedReader(new FileReader("myCharStream\\ConversionStreamDemo.java"));
// 一次读取一个字符数据
/* int ch;
while((ch= br.read())!=-1){
// System.out.println((char) ch);
bw.write(ch);
}*/
char[] chs=new char[1024];
int len;
while((len= br.read(chs))!=-1){
bw.write(chs,0,len);
}
// 一次读取一个字符串数据
bw.close();
br.close();
}
}
3.8、字符缓冲流特有功能
字节串缓冲流的特有功能 BufferedWriter void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义 BufferedReader public String readLine() 读一行文字 结果包括行的内容的字符串,不包括任何行终止符,如果流已到达结尾,则为null
package com.itheima04;
/*
字节串缓冲流的特有功能
BufferedWriter
void newLine() 写一行 行分隔符,行分隔符字符串由系统属性定义
BufferedReader
public String readLine() 读一行文字
结果包括行的内容的字符串,不包括任何行终止符,如果流已到达结尾,则为null
*/
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
/* BufferedWriter bw=new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
for (int i=0;i<3;i++){
bw.write("hello"+i);
// bw.write("\r\n");
// void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义
// bw.newLine();
bw.flush();
}
bw.close();*/
// BufferedReader
BufferedReader br=new BufferedReader(new FileReader("myCharStream\\bw.txt"));
// public String readLine() 读一行文字
// 结果包括行的内容的字符串,不包括任何行终止符,如果流已到达结尾,则为null
/*// 第一次读取数据---应该读的是第一行的数据
String line1 = br.readLine();
System.out.println(line1);
// 第二次读取数据---应该读的是第2行的数据
String line2 = br.readLine();
System.out.println(line2);
// 第3次读取数据---应该读的是第3行的数据
String line3 = br.readLine();
System.out.println(line3);
// 第4次读取数据---没有内容是输出null
String line4 = br.readLine();
System.out.println(line4);*/
//循环改进
String line;
while((line=br.readLine())!=null){
// System.out.print(line); 该方法不会读取换行符所以需要手动换行
System.out.println(line);
}
br.close();
}
}
案例:复制单极文件夹
package com.itheima09;
/*
需求:把"D:\\itcast"这个文件夹复制到模块目录下
思路:
创建数据源目录File对象,路径是D:\\itcast
获取数据源目录File对象的名称(itcast)
创建目的地目录File对象,路径名是模块名+itcast组成(myCharStream\\itcast)
判断目的地目录对应的File是否存在,如果不存在,就创建
获取数据源目录下所有文件的File数组
遍历File数组,得到每一个File对象,该File对象,其实就是数据源文件
数据源文件:D:\\itcast\\lala.jpg
获取数据源文件File对象的名称(lala.jpg)
创建目的地文件File对象,路径名是目的地目录+lala.jpg组成(myCharStream\\itcast\\lala.jpg)
复制文件
由于文件不仅仅是文本文件,还有图片、视频,所以采用字节流复制文件
*/
import java.io.*;
public class CopyFolderDemo {
public static void main(String[] args) throws IOException {
// 创建数据源目录File对象,路径是D:\\itcast
File srcFolder=new File("D:\\itcast");
// 获取数据源目录File对象的名称(itcast)
String srcFolderName=srcFolder.getName();
// System.out.println("源目录名:"+srcFolderName);
// 创建目的地目录File对象,路径名是模块名+itcast组成(myCharStream\\itcast)
File destFolder=new File("myCharStream",srcFolderName);
// 判断目的地目录对应的File是否存在,如果不存在,就创建
if(!destFolder.exists())
{
destFolder.mkdir();
}
// 获取数据源目录下所有文件的File数组
File [] listFile=srcFolder.listFiles();
// 遍历File数组,得到每一个File对象,该File对象,其实就是数据源文件
for(File srcFile :listFile)
{
// 数据源文件:D:\\itcast\\lala.jpg
// 获取数据源文件File对象的名称(lala.jpg)
String srcFileName=srcFile.getName();
// System.out.println(srcFileName);
// 创建目的地文件File对象,路径名是目的地目录+lala.jpg组成(myCharStream\\itcast\\lala.jpg)
File destFile=new File(destFolder,srcFileName);
// 复制文件
copyFile(srcFile,destFile);
}
// 由于文件不仅仅是文本文件,还有图片、视频,所以采用字节流复制文件
}
public static void copyFile(File srcFile,File destFile) throws IOException {
// 使用字节缓冲流写文件
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destFile));
// 使用字节缓冲流读取数据
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(srcFile));
int len;
byte[] bys=new byte[1024];
while((len= bis.read(bys))!=-1)
{
bos.write(bys);
}
bis.close();
bos.close();
}
}
案例:复制多级文件
package com.itheima09;
/*需求:复制多级目录
思路:
①创建数据源File对象,路径是D:\\itcast
②创建目的地File对象,路径C:
③写方法实现文件夹的复制,参数为数据File对象和目的地Fiie对象
④判断数据源File是否是目录
是目录:
在目的地下创建和数据源File名称一样的目录
获取数据源File下所有数组,得到每一个File对象
遍历File数组,得到每一个File对象
把该File作为数据源File对象,递归调用复制文件夹的方法
不是目录
说明File对象是文件,直接调用方法复制,用字节流*/
import java.io.*;
public class CopyMultiFolderDemo {
public static void main(String[] args) throws IOException {
//创建数据源File对象,路径是D:\\itcast
File srcFolder=new File("D:\\itcast");
//创建目的地File对象,路径C:\\
File destFolder=new File("C:\\");
//写方法实现文件夹的复制,参数为数据File对象和目的地Fiie对象
copyFolder(srcFolder,destFolder);
}
//复制文件夹
private static void copyFolder(File srcFolder,File destFolder) throws IOException {
//判断数据源File是否是目录
if (srcFolder.isDirectory())
{
// 是目录:
// 在目的地下创建和数据源File名称一样的目录
String srcFolderName = srcFolder.getName();
// 获取D盘相同的文件名
File newFileName=new File(destFolder,srcFolderName);// itcast
System.out.println("从D盘复制过来的目录名:"+newFileName);
// 再次判断一下C盘有没有itcast这个文件,确保c盘有File newFileName=new File(destFolder,srcFolderName);// itcast文件
/* 从D盘复制过来的目录名:C:\itcast
从D盘复制过来的目录名:C:\itcast\JavaSE
从D盘复制过来的目录名:C:\itcast\JavaWEB
从D盘复制过来的目录名:C:\itcast\JavaWEB\HTML*/
if (!newFileName.exists()){
newFileName.mkdir();
}
// 获取数据源File下 所有数组,得到每一个File对象
File[] fileArray = srcFolder.listFiles();//C:\\itcast
// 遍历File数组,得到每一个File对象
for (File file:fileArray)
{
System.out.println("数据源File下所有:"+file);
// 需要将遍历获取的File对象封装起来
// String.valueOf(file)
// 把该File作为数据源File对象,递归调用复制文件夹的方法 下一层级如果还是目录还是继续递归
copyFolder(file,newFileName);
// File destFile=new File(newFileName, file);
}
}else{
// 不是目录
// 说明File对象是文件,直接调用方法复制,用字节流
// copyFile(源文件,目的地文件);这里的文件名每一此次都会变,所以需要封装起来
File newFile=new File(destFolder,srcFolder.getName());
copyFile(srcFolder,newFile);
}
}
//复制文件
public static void copyFile(File srcFile,File destFile) throws IOException
{
// 使用字节缓冲流写文件
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destFile));
// 使用字节缓冲流读取数据
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(srcFile));
int len;
byte[] bys=new byte[1024];
while((len= bis.read(bys))!=-1)
{
bos.write(bys);
}
bis.close();
bos.close();
}
}
3.9、字节流报错处理
package com.itheima10;
/*
try{
可能出现异常的代码
}catch{
异常的处理代码
}finally{
执行所有清楚操作
}
*/
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyFileDemo {
public static void main(String[] args)throws IOException {
method1();
method2();
}
// 抛出异常的标准写法JDK9 会自动释放资源
public static void method4() throws IOException{
FileReader fr=new FileReader("fr.txt");
FileWriter fw=new FileWriter("fw.txt");
try(fr; fw;){
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1)
{
fw.write(chs, 0, len);
}
}
catch(IOException e){
e.printStackTrace();
}
}
// 抛出异常的标准写法JDK7 会自动释放资源
public static void method3() {
try(FileReader fr=new FileReader("fr.txt");
FileWriter fw=new FileWriter("fw.txt");){
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1)
{
fw.write(chs, 0, len);
}
}
catch(IOException e){
e.printStackTrace();
}
}
/* fr.close();
fw.close();*/
// 抛出异常的标准写法try{..}catch(){...}finally
public static void method2() {
FileReader fr=null;
FileWriter fw=null;
try{
fr = new FileReader("fr.txt");
fw = new FileWriter("fw.txt");
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1) {
fw.write(chs, 0, len);
}
}catch(IOException e){
e.printStackTrace();
}finally{
if (fr!=null)
{
try{
fr.close();
}catch(IOException e){
e.printStackTrace();
}
}
if(fw!=null)
{
try{
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
// 抛出异常,调用方法时还需要抛出一次异常
public static void method1()throws IOException {
FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt");
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1) {
fw.write(chs, 0, len);
}
fr.close();
fw.close();
}
}