------- android培训、java培训、期待与您交流! ----------
@@day(18)IO字符流之FileWriter、FileReader******************************************************************************
字节流和字符流
字节流的两个抽象基类:InputStream和OutputStream
字符流的两个抽象基类:Reader和Writer
读入时:Reader InputStream 确保文件存在,没有flush,有close
写出时:Writer OutputStream 不用确保文件存在,需要flush,有close
(不带缓冲区的字节流写出时,不刷新也有数据;字符流的底层是字节流)
缓冲区里面定义的是数组。
@@Writer
abstract void close() //如果流创建不成功(流==null),就不用close
关闭此流,但要先刷新它。
abstract void flush() //将流(内存)中现有的数据刷到关联文件中
刷新该流的缓冲。
void write(int c) //将单个字符写到流中
写入单个字符。
void write(char[] cbuf) //将字符数组中的数据写到流中,
写入字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(String str) //将字符串写到流中
写入字符串。
void write(String str, int off, int len)
写入字符串的某一部分。
@@Reader
abstract void close()
关闭该流并释放与之关联的所有资源。
int read() //返回值为读到的字符数据,可以int ch = fr.read();并(char)ch
读取单个字符。
int read(char[] cbuf) //返回值为读到字符的个数,将流中的字符数据读到了指定的的数组中。
将字符读入数组。
abstract int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。
int read(CharBuffer target) //将流中的字符数据读到了指定的字符缓冲区,返回读到的字符个数,-1表示缓冲区满。
试图将字符读入指定的字符缓冲区。
@@FileWriter写入文件
//创建一个FileWriter流对象,该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定的目录下。覆盖原重名文件!
//其实就是在明确数据存放的目的地。
FileWriter fw = new FileWriter("demo.txt");
//传递一个true参数,表示不覆盖原重名文件,并在原文件末尾处续写!!
FileWriter fw = new FileWriter("demo.txt",true);
//调用write方法,将字符串写入流中。//流就是内存(大脑中的思路),目的地就是文件(写字的纸)!
fw.write("abcde");
//刷新流对象中的缓存中的数据。
//将数据刷到目的地中!
//fw.flush();
//关闭流资源,关闭前,会刷新一次内部缓存中的数据。
//将数据刷到目的地中
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭!
fw.close();
IO的异常处理
FileWriter fw = null;
try
{
fw = new FileWriter("demo.txt");
fw.write("abcdefg");
}
catch (IOException e)
{
System.out.println("catch:"+e.toString());
}
finally
{
if(fw!=null)
try
{
fw.close();
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
@@FileReader文件读取
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件时已经存在的,如果不存在,运行时会发生异常FileNotFoundException
FileReader fr = new FileReader("demo.txt");
//调用读取对象的read方法。
//read():一次读一个字符,而且自动往下读!
int ch = 0;
while((ch = fr.read())!=-1)
{
System.out.println("ch="+(char)ch);
}
/*或者
while(true)
{
int ch = fr.read();
if(ch==-1)
break;
System.out.println("ch="+(char)ch);
}*/
fr.close();
FileReader fr = new FileReader("demo.txt");
//定义一个字符串数组,用于存储读到的字符。
//该read(char[])返回的是读到的字符个数!
char[] buf = new char[1024];//一个字符为两个字节。1024个字符为1024*2个字节,即2K
int num = 0;
while((num=fr.read(buf))!=-1)
{
System.out.println(new String(buf,0,num));
}
fr.close();
day(19)带缓冲区的字符流***************************************************************
@@BufferWriter
void close()
关闭此流,但要先刷新它。
void flush()
刷新该流的缓冲。
void newLine()
写入一个行分隔符。
void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(int c)
写入单个字符。
void write(String s, int off, int len)
写入字符串的某一部分。
//创建一个字符写入流对象!
FileWriter fw = new FileWriter("buf.txt");
//为了提高字符写入流效率,加入了缓冲技术。
//只要将需要被提高效率的流对象,作为参数,传递给缓冲区的构造函数即可!
BufferedWriter bufw = new BufferedWriter(fw);
for(int x=1;x<5;x++)
{
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush();
}
//记住,只要用到缓冲区就要刷新!!
//bufw.flush();
//其实关闭缓冲区就是在关闭缓冲区中的流对象!!
bufw.close();
//fw.close();//不用写了!
@@BufferReader
void close()
关闭该流并释放与之关联的所有资源。
int read()
读取单个字符。
int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。
String readLine() //返回读到的字符数据,如果到达流的末尾 返回null
读取一个文本行。
//创建一个读取流对象和文件相关联!
FileReader fr = new FileReader("buf.txt");
//为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递到缓冲对象的构造函数中!
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while ((line=bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
public String myReadLine() throws IOException
{
//定义一个临时容器,原BufferReader封装的是字符数组。
//为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变成字符串。
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;
}
@@复制文本(带缓冲区的)
class CopyTextByBuf
{
public static void main(String[] args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
String line = null;
while((line=bufr.readLine())!=null)
{
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("写入关闭失败");
}
}
}
}
@@OutputStream&&InputStream
FileOutputStream
不带缓冲区的字节流写出时,不刷新也有数据
FileOutputStream fos = new FileOutputStream("fos.txt");
FileInputStream fis = new FileInputStream("fos.txt");
1--
fos.write("abcde".getBytes());
fos.close();
2--
int ch = 0;
while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}
fis.close();
3--常用!
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
fis.close();
4--fos.txt中字节数少时可以用。
int num = fis.available();//预判fos.txt中的字节数
byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。不用在循环了。
fis.read(buf);
System.out.println(new String(buf));
fis.close();
@@复制picture&&map
class CopyPic//不带缓冲区的
{
public static void main(String[] args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("c:\\2.bmp");
fis = new FileInputStream("c:\\1.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("复制文件失败");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
复制map(带缓冲区的)
public static void copy_1()throws IOException
{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}
@@复制电影(带缓冲区的)
class CopyMovie
{
public static void main(String[] args) throws IOException
{
long start = System.currentTimeMillis();
System.out.println("startTime:"+start);
Copy();
long end = System.currentTimeMillis();
System.out.println("endTime"+end);
System.out.println((end-start)+"毫秒");
}
public static void Copy()throws IOException
{
FileInputStream fis = new FileInputStream("F:\\Movies\\魔戒三部曲\\魔戒3王者归来.rmvb");
BufferedInputStream bufis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("I:\\魔戒3王者归来.rmvb");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
byte[] buf = new byte[1024*1024*50];
int len = 0;
while ((len=bufis.read(buf))!=-1)
{
bufos.write(buf,0,len);
}
bufis.close();
bufos.close();
}
}
@@自定义的字节流的缓冲区--read和write的特点!
class MyBufferedInputStream
{
private InputStream in;
private byte[] buf = new byte[1024*4];
private int pos = 0,count = 0;
MyBufferedInputStream(InputStream in)
{
this.in = in;
}
//一次读一个字节,从缓冲区(字节数组)获取。
public int myRead()throws IOException
{
//通过in对象读取硬盘上数据,并存储buf中。
if(count==0)//数组中没有数据了,那么先存再取
{
count = in.read(buf);//流中的数据存到数组中
if(count<0)//流中没有数据了,被取完了或者本来就没有。
return -1;
pos = 0;//先取数组中的第一个字节。
byte b = buf[pos];
count--;
pos++;
return b&255;
}
else if(count>0)//数组中还有数据,接着取
{
byte b = buf[pos];
count--;
pos++;
return b&0xff;
}
return -1;
}
public void 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 11111111 11111111
&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:对应的是标准输入设备,键盘
public static void main(String[] args)throws IOException
{
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true)
{
int ch = in.read();
if(ch=='\r')
continue;
if(ch=='\n')
{
String s = sb.toString();
if(s.equals("over"))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());
}
else
sb.append((char)ch);
}
}
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理!
也就是readLine方法
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法。
而键盘录入的read方法是InputStream的方法。
那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine方法呢
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
//获取键盘录入对象
//InputStream in = System.in;
//将字节流对象转换成字符流对象,使用转换流,InputStreamReader
//InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
//BufferedReader bufr = new BufferedReader(isr);
****************//键盘录入最常见写法!
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//同理-->
//OutputStream out = System.out;
//OutputStreamWriter osw = new OutputStreamWriter(out);
//BufferedWriter bufw = new BufferedWriter(osw);
BufferedWriter bufw =
new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while ((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
//System.out.println(line.toUpperCase());
}
//bufw.close();
bufr.close();
}
}
@@流的操作规律 重点!!!!!!!!!!!!!!!!!!!
1,源:键盘录入。System.in
目的:控制台 System.out
2,需求:想把键盘录入的数据存储到一个文件中!
源:键盘 System.in
目的:文件 new FileOutputStream
3,需求:想要将一个文件的数据打印在控制台上
源:文件 new FileInputStream
目的:控制台 System.out
流操作的基本规律:
最痛苦的是流对象很多,不知道用哪一个。
通过两个明确来完成!
1,明确源和目的!
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
2,操作的数据是否是纯文本!
是:用字符流!
不是:用字节流!
3,当体系明确后,再明确要使用哪个具体的对象!
通过设备来进行区分:
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。
1,将一个文本文件中的数据存储到另一个文件中,复制文件!
源:因为是源,所以使用读取流InputStream Reader
是不是操作文本文件=》是!
这时选择Reader
这样体系明确了!
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘。
Reader体系中可以操作文件的对象是 FileReader
是否需要提高效率:是!加入Reader体系中的缓冲区BufferedReader
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的:OutputStream Writer
是不是纯文本=》是 Writer
设备:硬盘,一个文件
Writer体系中可以操作文件的对象FileWriter
是否需要提高效率:是!加入Reader体系中的缓冲区BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter = new BufferedWriter(fw);
练习:将一个图片文件中数据存储到另一个文件中,复制文件。按照以上格式!
-----------------------------------------------------------
2,将键盘录入的数据保存到一个文件中。
这个需求中有源和目的都存在!
源:InputStream Reader
是不是纯文本? 是,Reader
设备:键盘。对应的对象时System.in
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便,转成字符流按照字符串操作最方便!
所以既然明确了Reader,那么就将System.in转换成Reader,
用到了Reader体系中的转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗? 需要 BufferedReader
BufferedReader bufr= new BufferedReader(isr);
目的:OutputStream Writer
是否是纯文本?是 Writer
设备 硬盘,一个文件!
使用FileWriter
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要
BufferedWriter bufw = new BufferedWriter(fw);
******************
扩展一下,想要把录入的数据按照指定的编码表(UTF-8),将数据存到文件中!
目的:OutputStream Writer
是否是纯文本?是 Writer
设备 硬盘,一个文件! 使用FileWriter
但是FileWriter是使用的默认编码表. GBK
但是存储时,需要加入指定的编码表,而指定的编码表只有转换流可以指定!
所以要使用的对象是OutputStreamWriter
而该转换流对象要接受一个字节输出流,而且还可以操作文件的字节输出流!FileOutputStream
FileOutputStream fos = new FileOutputStream("c.txt");
OutputStreamWriter osfw = new OutputStreamWriter(fos,"UTF-8");
需要提高效率吗?需要
BufferedWriter bufw = new BufferedWriter(osfw);
所以 记住!转换流什么时候使用,字符和字节之间的桥梁,
通常涉及到字符编码转换时,需要使用转换流!
lang包中的System中可以改变System.in和System.out的指向,
原来System.in指向键盘,System.out指向控制台
System.setIn(文件等);
System.setOut(文件等);
static void setIn(InputStream in)
重新分配“标准”输入流。
static void setOut(PrintStream out)
重新分配“标准”输出流。
@@异常的日志信息!
import java.io.*;
import java.util.*;
import java.text.*;
class ExceptionInfo
{
public static void main(String[] args) throws IOException
{
try
{
int [] arr = new int[2];
System.out.println(arr[3]);
}
catch (Exception e)
{
try
{
Date d = new Date();
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
PrintStream ps = new PrintStream("exeception.log");
ps.println(s);
//ps.write(d.toString().getBytes());
System.setOut(ps);
}
catch (IOException ex)
{
throw new RuntimeException("日志文件创建失败!");
}
************************e.printStackTrace(System.out);
}
}
}
//log4j
//网络上的工具,专门建立java日志信息文件!下载下来看看用!
@@系统信息!
import java.util.*;
import java.io.*;
class SystemInfo
{
public static void main(String[] args) throws IOException
{
Properties prop = System.getProperties();
prop.list(new PrintStream("sysinfo.txt"));
//PrintStream ps = new PrintStream("SysInfo.txt");
//System.setOut(ps);
//prop.list(System.out);
}
}