硬盘上存取的是二进制的数据,记事本软件对硬盘上.txt文件的二进制数据进行了解析,解析之后是字符串。read()读取硬盘上的二进制数据以整数返回。
在硬盘上的数据怎么体现是不同文件的数据,每一段数据都有一个开始和结束的标示,当硬盘碎片。每一段碎片就有标识,通过标识连续读取数据
输入流,读方式,是把数据读到内存中去,
只有输出流,写方式,是存在刷新flush();
写方式是先将数据存到缓冲区中,在缓存中查表,查表结束之后才把把数据存到目的地当中
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class FileReaderDemo { /** * @param args * @throws IOException * @throws IOException */ public static void main(String[] args) throws IOException { writeFile(); /* * 需求:读取一个已有的文本文件,将读到的数据打印到控制台(屏幕)。 * 思路: * 1,应该是将硬盘的数据读去到内存中,使用输入流。 * 2,操作的数据是文本数据,应该使用字符流更为便捷。 * 3,即使输入,又是字符,应该是字符输入流:Reader * 4,要用到字符输入流的哪个功能对象呢?操作文件的,FileReader 。 * */ // 1,创建FileReader对象。 并通过构造函数明确数据源。 // 创建读取对象,和数据源相关联。 FileReader fr = new FileReader("temp\\demo.txt"); //2,调用Reader中的read方法,一次读取一个字符。 /*int ch1 = fr.read(); System.out.println("ch1="+ch1);//97 int ch2 = fr.read(); System.out.println("ch2="+ch2);//98 int ch3 = fr.read(); System.out.println("ch3="+ch3);//99 int ch4 = fr.read(); System.out.println("ch4="+ch4);//-1 int ch5 = fr.read(); System.out.println("ch5="+ch5);//-1*/ //3,使用循环解决问题。 int ch = 0; while((ch=fr.read())!=-1){ System.out.println((char)ch); } //3,必须关闭资源。 fr.close(); } public static void writeFile() throws IOException{ FileWriter fw = new FileWriter("temp\\demo.txt"); fw.write("abcde"); fw.close(); } }
IO-字符输入流_read(char[])
public int read(char[] cbuf) throws IOException
将字符读入数组。在某个输入可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
参数:
cbuf - 目标缓冲区
返回:
读取的字符数,如果已到达流的末尾,则返回 -1
抛出:
IOException - 如果发生 I/O 错误
package cn.itcast.p1.io.filereader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class FileReaderDemo2 { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * read(char[]); */ //1,创建读取流对象和数据源关联。 FileReader fr = new FileReader("temp\\demo.txt"); //2,创建一个字符数组。用于存储读到字符数据。 //char[] buffer = new char[1024];//2k字节,一个字符是2个字节,一般定义的都是1024的整数倍。因为硬盘以1024字节为单位进行数据的存储。 char[] buffer = new char[2]; //3,调用读取流的read(char[]),将读到的字符存储到字符数组中。 /*int len1 = fr.read(buffer); System.out.println("len1="+len1+";"+new String(buffer)); int len2 = fr.read(buffer); System.out.println("len2="+len2+";"+new String(buffer)); int len3 = fr.read(buffer); System.out.println("len3="+len3+";"+new String(buffer)); int len4 = fr.read(buffer); System.out.println("len4="+len4+";"+new String(buffer));*/ //4,循环。 int len = 0; while((len=fr.read(buffer))!=-1){ System.out.println(new String(buffer,0,len)); } fr.close(); } }
IO-文本复制_1
package cn.itcast.io.p2.copytext; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopytTextTest { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * 需求: 将d盘中的文本文件复制到e盘中。 * * 思路: * 1,既然是复制,必须要有源。 * 2,对源就是读取,并将读到的字符数据存储到目的中。 * 3,即用到了读,又用到了写。而且还是字符。说明使用Reader Writer * 4,操作都是文件,使用的应该是FileReader,FileWriter. * */ copyText2(); } public static void copyText() throws IOException { //1,创建一个字符读取流和指定的源相关联。 FileReader fr = new FileReader("temp\\CopytTextTest.java"); //2,确定数据存储的目的。 FileWriter fw = new FileWriter("temp\\demo_copy.txt"); //3,读一个写出去。有很多字符,需要循环。 当读取动作返回-1,说明结束。 int ch = 0; while((ch=fr.read())!=-1){ fw.write(ch); } //4,关闭资源。 fw.close(); fr.close(); } }
IO-文本复制_2
public static void copyText2() { /* * 复制使用数组缓冲区完成。 * */ //1,创建读取流和写入流。 FileReader fr = null; FileWriter fw = null; try { fr = new FileReader("temp\\CopytTextTest.java"); fw = new FileWriter("temp\\demo_copy2.txt"); //定义一个缓冲区数组。 char[] buf = new char[1024]; int len = 0; while((len=fr.read(buf))!=-1){ fw.write(buf,0,len);//读取几个就写几个。 } } catch (Exception e) { e.printStackTrace(); }finally{ if(fw!=null) try { fw.close(); } catch (Exception e2) { throw new RuntimeException("写入关闭失败"); } if(fr!=null) try { fr.close(); } catch (Exception e2) { throw new RuntimeException("读取关闭失败"); } } }
IO-文本复制_图解
创建输入流对象,将流对象与源文件关联。
通过输出流对象在目的地位置创建一个文件。
输入流,和输出流是没啥关系。所以存在了一个缓冲区帮助中转,
输入流读取的数据,存取数据到缓冲区,输出流从缓冲区中写到硬盘中去
IO-字符缓冲区-BufferedWriter
public void newLine() throws IOException
写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 (‘\n‘) 符。
package cn.itcast.io.p3.buffer; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class BufferedWriterDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * 演示BufferedWriter. * 缓冲区是对流中的数据进行缓冲的。所以必须要在构造缓冲区时,明确具体的流对象。 */ //1,创建字符输出流对象; FileWriter fw = new FileWriter("temp\\buf.txt"); //2,创建缓冲区对象,将流对象传给缓冲区的构造函数。 BufferedWriter bufw = new BufferedWriter(fw); for(int x=1; x<=4; x++){ bufw.write(x+"-hehe"); bufw.newLine();//写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义, bufw.flush(); } bufw.close();//不用在对fw进行关闭,因为关闭缓冲区的就是在关闭该流。 } }
IO-字符缓冲区-BufferedReader
通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。
将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
通过用合适的 BufferedReader 替代每个 DataInputStream,可以对将 DataInputStream 用于文字输入的程序进行本地化。
package cn.itcast.io.p3.buffer; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class BufferedReaderDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * 字符输入流缓冲区演示BufferedReader. */ //1,创建字符输入流对象。 FileReader fr = new FileReader("temp\\buf.txt"); //2,创建字符输入流缓冲区对象。 BufferedReader bufr = new BufferedReader(fr); //3,使用BufferedReader的特有方法,一次读一行。 //String line = bufr.readLine(); //System.out.println(line); String line = null; while((line=bufr.readLine())!=null){ System.out.println(line); } bufr.close(); } }
IO-字符缓冲区-通过缓冲区复制文本文件
package cn.itcast.io.p3.buffercopy; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyTextByBufferTest { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * 通过缓冲区对文本文件进行复制。 */ copyTextByBuffer(); } public static void copyTextByBuffer() throws IOException { //1,创建流对象和缓冲区对象。 FileReader fr = new FileReader("temp\\buf.txt"); BufferedReader bufr = new BufferedReader(fr); FileWriter fw = new FileWriter("temp\\buf_copy.txt"); BufferedWriter bufw = new BufferedWriter(fw); //2,对一行文本进行读写。 String line = null; while((line=bufr.readLine())!=null){ bufw.write(line); bufw.newLine(); bufw.flush(); } bufw.close(); bufr.close(); } }
IO-字符缓冲区-readLine方法的原理
IO-字符缓冲区-MyBufferedReader
缓冲区对流功能的增强,提高流的读写效率。 package cn.itcast.io.p4.mybuffer; import java.io.IOException; import java.io.Reader; /** * 自定义字符读取缓冲区。 * @author Administrator * */ public class MyBufferedReader extends Reader { private Reader r; /* * 其实缓冲区无非就是封装了一个数组对象。 * 对外提供了对数组中元素的操作。 */ //定义一个字符数组。作为缓冲存在。 private char[] buf = new char[1024]; //定义了两个变量,一个记录数组的角标。一个记录存储到数组中字符的个数。 private int index = 0; private int count = 0; public MyBufferedReader(Reader r) { super(); this.r = r; } /** * 提供一个一次读一个字符的方法。并返回读到字符。如果读到结尾返回-1. * 注意:该方法其实是从缓冲区中进行读取。 * @throws IOException */ public int myRead() throws IOException{ //当count等于0时,才需要去源中取数据。 if(count==0){ //通过流对象的read(char[])方法从源中取一批数据进数组缓冲区,用count记录存储的个数。 count = r.read(buf); //每获取一次数据,就要将角标归零。 index = 0; } if(count<0) return -1; char ch =buf[index]; index++; count--; return ch; } /** * 提供一个一次读一行的方法。内部其实使用的是本类的myRead()方法 * 完成的,将读到的字符进行缓冲,当读取到的行终止符时,将存储的 * 字符作为字符串返回。 * @throws IOException */ public String myReadLine() throws IOException{ /* * 其中也需要定义缓冲区。就是用StringBuilder */ StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=myRead())!=-1){ if(ch==‘\r‘){ continue; } if(ch==‘\n‘){ return sb.toString(); } sb.append((char)ch); } if(sb.length()!=0){ return sb.toString(); } return null; } /** * 提供一个关闭资源的方法。 * @throws IOException */ public void myClose() throws IOException{ //其实就是关闭了流。 r.close(); } @Override public int read(char[] cbuf, int off, int len) throws IOException { return 0; } @Override public void close() throws IOException { } } package cn.itcast.io.p4.mybuffer; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class MyBufferedReaderDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { FileReader fr = new FileReader("temp\\buf.txt"); MyBufferedReader myBufr = new MyBufferedReader(fr); String line = null; while((line=myBufr.myReadLine())!=null){ System.out.println(line); } myBufr.myClose(); } }
IO-字符缓冲区-装饰设计模式
package cn.itcast.io.p5.wrapper; public class WrapperDemo { /** * @param args */ public static void main(String[] args) { Person p = new Person(); //NewPerson p = new NewPerson(); NewPerson pp = new NewPerson(p); pp.chifan(); /* * 装饰模式:为了解决给类的功能进行增强而出现的。 * * Writer * |--TextWriter * |--MediaWriter * * 想要对流对象的功能进行增强,比如提高写入的效率。 * 使用缓冲技术。 * Writer * |--TextWriter * |--BufferedTextWriter * |--MediaWriter * |--BufferedMediaWriter * * 每一个子类这样实现是可以的,但是导致继承体系较为臃肿。 * 发现其实无论哪个子类需要高效,使用的都是缓冲技术。 * 干脆将缓冲技术进行单独的描述和封装。 * 要缓冲区谁,就将谁传给缓冲区。 * BufferdWriter * * class BufferedWriter extends Writer * { * BufferedWriter(Writer w) * {} * } * * 装饰设计模式。 * Writer * |--TextWriter * |--MediaWriter * |--BufferedWriter * * 装饰类和被装饰的特点: * 1,装饰类中的构造函数需要接受被装饰类。 * 2,装饰类和被装饰类应该所属于同一个体系。 * */ } } class Person{ void chifan(){ System.out.println("吃饭"); } } class NewPerson{ private Person p ; NewPerson(Person p){ this.p = p; } public void chifan(){ System.out.println("开胃酒"); p.chifan(); System.out.println("甜点"); System.out.println("来一根"); } } /* class NewPerson extends Person{ @Override void chifan() { System.out.println("开胃酒"); super.chifan(); System.out.println("甜点"); System.out.println("来一根"); } }
IO-字符缓冲区-LineNumberReader
package cn.itcast.io.p6.linenumber; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; public class LineNumberReaderDemo { /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws IOException { /* * 演示LineNumberReader。 */ FileReader fr = new FileReader("temp\\CopytTextTest.java"); LineNumberReader lnr = new LineNumberReader(fr); String line = null; lnr.setLineNumber(100); while((line=lnr.readLine())!=null){ System.out.println(lnr.getLineNumber()+":"+line); } lnr.close(); } }