------- 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); 
 }
}

------- android培训、java培训、期待与您交流! ----------

黑马程序员-java基础8--IO流(一)相关推荐

  1. 黑马 程序员——Java基础---IO(下)

    黑马程序员--Java基础---IO(下) ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------ 一.概述 Java除了基本的字节流.字符流之外,还提供 ...

  2. 黑马 程序员——Java基础---流程控制

    黑马程序员--Java基础---流程控制 ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------ 一.概述 Java提供了两种基本的流程控制结构:分支结构 ...

  3. 黑马程序员-Java教程-10缓冲流、转换流、序列化流

    day10[缓冲流.转换流.序列化流.打印流] 主要内容 缓冲流 转换流 序列化流 打印流 教学目标 能够使用字节缓冲流读取数据到程序 能够使用字节缓冲流写出数据到文件 能够明确字符缓冲流的作用和基本 ...

  4. 黑马程序员-JAVA基础-IO流之流操作规律及读写转换流

    ------- android培训.java培训.期待与您交流!------- 在操作IO流时,常常会迷惑:流对象很多,不知道该使用哪一个? 一.流操作的基本规律: 通过三个明确来完成: 1.明确'源 ...

  5. 黑马程序员-JAVA基础-IO流之字符流和字符流缓冲区

    ------- android培训.java培训.期待与您交流!------- Java 的IO 流 是实现输入和输出的基础,Java 中把不同的输入.输出源抽象表述为"流" (S ...

  6. 黑马程序员-----Java基础-----IO流-3

    -----<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培 ...

  7. 黑马程序员---java基础-Java之IO

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.概念 1.概念 IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Jav ...

  8. 黑马程序员--Java基础加强篇

    开发工具使用 --------------------------------------------------------------------------------------------- ...

  9. 黑马程序员-Java基础:设计模式总结

    --Java培训.Android培训.iOS培训..Net培训.期待与您交流! -- Java基础部分设计模式 一.设计模式概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的 ...

  10. 黑马程序员--java基础知识注意点收录

    java基础知识注意点收录 1.使用path设置路径时,为避免由于虚拟机存放位置的不同而改变设置路径时造成意外的其他错误,使用变量 JAVA_HOME记住虚拟机的位置,然后在path中通过%JAVA_ ...

最新文章

  1. cmd删除oracle监听,oracle数据库监听删除
  2. 【未来研究】城市云脑是互联网云脑的节点,城市云脑之间如何互补与支撑
  3. 如何查看linux版本?
  4. 同感,C#对JSON序列化和反序列化有点蹩脚
  5. grep、egrep、fgrep的用法与特性详解
  6. 4 在vCenter Server安装View Composer组件
  7. richtextbox自动滚动到最下面_工业自动化直线运动部件大全,导轨、轴承、衬套、丝杠、导向轴简介说明...
  8. Oracle行列转换小结
  9. android 子module混淆_Android 多模块打包混淆填坑记
  10. javascript中变量和函数的使用
  11. 23种设计模式(5)-适配器模式
  12. MFC获取屏幕分辨率
  13. ctype.h(c标准库)
  14. 图像增强处理之:同态滤波与Retinex算法(二)McCann Retinex和McCann99 Retinex迭代算法
  15. mysq命令行导出sql_mysql 命令行导入导出.sql文件
  16. [翻译]深入解析Windows操作系统(下)之第十章 内存管理
  17. 高等数学(第七版)同济大学 习题8-1 个人解答
  18. S7-300系列PLC如何通过GSD文件实现PROFIBUS DP主从通讯?
  19. css3D旋转立方体
  20. VUE之多元素组件过渡+动画封装

热门文章

  1. HTML中字体属性、文本属性使用说明
  2. 华为digix算法大赛2020机器学习赛道-ctr预估初赛/决赛rank1
  3. hibernate之HQL实体更新与删除
  4. Word VBA自动排版(2)-通过自动查找替换去除叠字
  5. 基于CIM的馈线建模和应用(论文学习)
  6. Tilt Five AR桌游体验:概念很新颖,但缺乏高质量内容?
  7. 总结图扑软件可实现的可视化效果案例分享
  8. 神级操作丨用 Python 将微信热文转换成Word文档
  9. 硬盘活动分区(将磁盘分区标为活动或取消活动的方法)(转)
  10. ATFX:小非农不及预期,今晚大非农表现如何?