IO流二(字符缓冲区,字节缓冲区,字节字符转换流)

 

 

一IO流 BufferedWriter

1.字符流的缓冲区

缓冲区是为了提高流的操作效率而出现的。

所以在创建缓冲区之前,必须要先有流对象。

缓冲区在流的基础上对流的功能进行了增强。

2)该缓冲区中提供了一个跨平台的换行符:newLine();

3)对应类:

BufferedWriter

BufferedReader

4)缓冲区的原理:将数组封装成对象,批量输出数据。

2.Writer-----> BufferedWriter(java.io包);

1)将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。

2)构造函数:

BufferedWriter(Writer out)

创建一个使用默认大小输出缓冲区的缓冲字符输出流。

3)newLine()

写入一个行分隔符。

 

3代码示例:

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


二 IO流BufferedReader

1.字符读取流缓冲区:

该缓冲区提供了一个一次读一行的方法readLine,方便于对文本数据的获取。

当返回null时,表示读到文件末尾。

2.Reader ----> BufferedReader(java.io包)

1)从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。

因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的Reader

(如 FileReader 和 InputStreamReader)。

例如, BufferedReader in = new BufferedReader(new FileReader("foo.in"));//将缓冲指定文件的输入。

如果没有缓冲,则每次调用 read() 或 readLine()

都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。

2)构造函数:

BufferedReader(Reader in)

创建一个使用默认大小输入缓冲区的缓冲字符输入流。

3)readLine()方法:

public String readLine() throws IOException

读取一个文本行。通过下列字符之一即可认为某行已终止:

换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。

返回:

包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null.

(只返回回车符之前的数据内容,并不返回回车符)。

3代码示例:

////创建一个读取流对象和文件相关联。

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

三装饰设计模式:

当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,

基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。

装饰类通常会通过构造方法接收被装饰的对象。

并基于被装饰的对象的功能,提供更强的功能。

例:自定义一个字符读取缓冲区包装类:MyBufferedReader

 
class MyBufferedReader { private Reader r; MyBufferedReader(Reader r) { this.r = r; } public String myRead()throws IOException { int ch = 0; StringBuilder sb = new StringBuilder(); 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; } public void myClose()throws IOException{ r.close() } }
 
 

装饰和继承的区别:

继承:

MyReader:专门用于读取数据的类。

|--MyTextReader

|--MyBufferTextReader

|--MyMediaReader

|--MyBufferMediaReader

|--MyDateReader

|--MyBufferDateReader

装饰类

MyReader:专门用于读取数据的类。

|--MyTextReader

|--MyMediaReader

|--MyDateReader

|--MyBufferReader

 

装饰模式比继承要灵活,避免了继承体系臃肿。而且降低了类与类之间的关系。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。

所以装饰类和被装饰类通常都是属于一个体系中的。

 

四LineNumberReader

public class LineNumberReader

extends BufferedReader

跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),

它们可分别用于设置和获取当前行号。

默认情况下,行编号从 0 开始。该行号随数据读取在每个行结束符处递增,

并且可以通过调用 setLineNumber(int) 更改行号。但要注意的是,

setLineNumber(int) 不会实际更改流中的当前位置;它只更改将由 getLineNumber() 返回的值。

可认为行在遇到以下符号之一时结束:换行符('\n')、回车符('\r')、回车后紧跟换行符。

1.构造方法:

LineNumberReader(Reader in)

使用默认输入缓冲区的大小创建新的行编号 reader。

2.特有方法:

1)getLineNumber

public int getLineNumber()

获得当前行号。

2)setLineNumber

public void setLineNumber(int lineNumber)

设置当前行号。

 

3代码示例:

 
class MyLineNumberReader { private Reader r; private int lineNumber; MyLineNumberReader(Reader r) { this.r = r; } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public int getLineNumber() { return lineNumber; } public void myReadLine()throws IOException { lineNumber++; 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; } } 
 
 
 

五 字节流

需求:想要操作图片数据,音乐数据,音频数据时,这时就要用到字节流。

1.InputStream抽象类

1)此抽象类是表示字节输入流的所有类的超类。

2)方法:

<1>abstract int read()

从输入流中读取数据的下一个字节。

<2>int read(byte[] b)

从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

InputStream ----> FileInputStream

1)FileInputStream 从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。

FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader

2)构造函数:

FileInputStream(File file)

通过打开一个到实际文件的连接来创建一个 FileInputStream,

该文件通过文件系统中的 File 对象 file 指定。

2.OutputStream抽象类

1)此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。

需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。

2)方法:

<1> void close()

关闭此输出流并释放与此流有关的所有系统资源。

<2>void flush()

刷新此输出流并强制写出所有缓冲的输出字节。

<3>void write(byte[] b)

将 b.length 个字节从指定的 byte 数组写入此输出流。

<4>void write(byte[] b, int off, int len)

将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

<5>abstract void write(int b)

将指定的字节写入此输出流.

OutputStream ----> FileOutputStream

1)文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。

文件是否可用或能否可以被创建取决于基础平台。特别是某些平台

一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。

在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。

FileOutputStream 用于写入诸如图像数据之类的原始字节的流。

要写入字符流,请考虑使用 FileWriter

2)构造方法:

FileOutputStream(File file)

创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

         读取键盘录入

1读取键盘录入:

System.out:对应的是标准输出设备,控制台。

System.in :对应的是标准输入设备:键盘。

2.in

public static final InputStream in

“标准”输入流。此流已打开并准备提供输入数据。

通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

3.需求:

通过键盘录入数据。

当录入一行数据后,就将该行数据进行打印。

如果录入的数据是over,那么停止录入。

六读取转换流

1.通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。

也就是readLine方法。

能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?

readLine方法是字符流BufferedReader类中的方法。

而键盘录入的read方法是字节流InputStream的方法。

那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine方法呢?

2.转换流

Reader ---> InputStreamReader(java.io包)

1)InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。

它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。

要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

2)构造方法:

 

InputStreamReader(InputStream in)

创建一个使用默认字符集的 InputStreamReader。

3)特有方法:

<1> void close()

关闭该流并释放与之关联的所有资源。

<2>String getEncoding()

返回此流使用的字符编码的名称。

<3>int read()

读取单个字符。

<4>int read(char[] cbuf, int offset, int length)

将字符读入数组中的某一部分。

<5>boolean ready()

判断此流是否已经准备好用于读取。

 

3.BufferedReader中有readLine()方法,而且BufferedReader可作用于Reader及其子类。

InputStreamReader是Reader子类,故可以使用BufferedReader对其进行缓冲区技术高效操作.

4.代码示例:

//获取键盘录入对象。

InputStream in = System.in;

//将字节流对象转成字符流对象,使用转换流InputStreamReader.

InputStreamReader isr = new InputStreamReader(in);

//为了提高效率,将字符串进行。使用BufferedReader.

BufferedReader bufr = new BufferedReader(isr);

String line = null;

while ((line = bufr.readLine()) != null)

{

if("over".equals(line))

break;

System.out.println(line.toUpperCase());

}

bufr.close();

 

七写入转换流

1.写入转换流:

Writer ---> OutputStreamWriter(java.io包)

1)public class OutputStreamWriterextends WriterOutputStreamWriter 是字符流通向字节流的桥梁:

可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,

否则将接受平台默认的字符集。

每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,

得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。

注意,传递给 write() 方法的字符没有缓冲。

为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,

以避免频繁调用转换器。例如:

Writer out

= new BufferedWriter(new OutputStreamWriter(System.out));

2)构造函数:

OutputStreamWriter(OutputStream out)

创建使用默认字符编码的 OutputStreamWriter。

3)方法摘要

<1>void close()

关闭此流,但要先刷新它。

<2>void flush()

刷新该流的缓冲。

<3>String getEncoding()

返回此流使用的字符编码的名称。

<4>void write(char[] cbuf, int off, int len)

写入字符数组的某一部分。

<5>void write(int c)

写入单个字符。

<6>void write(String str, int off, int len)

写入字符串的某一部分。

2.注意:

BufferedWriter中有newLine()方法(用于写入行分隔符,即换行),而且BufferedWriter可作用于Writer及其子类。

OutputStreamReader是Writer子类,故可以使用BufferedWriter对其进行缓冲区技术高效操作.

八流操作规律-1

1.

1)

源:键盘录入。

目地:控制台。

2)需求:想把键盘录入的数据存储到一个文件中。

源:键盘。

目的:文件。

3)需求:想要将一个文件的数据打印在控制台上。

源:文件。

目的:控制台。

2.流操作的基本规律:

最痛苦的就是流对象有很多。不知道该用哪一个。

 

通过两个明确来完成。

1)明确源和目地。

源:输入流。InputStream Reader

目的:输出注。OutputStream Writer

2)操作的数据是否是纯文本。

是:字符流。

不是:字节流。

3)当体系明确受制于人,再明确要使用哪个具体的对象。

通过设备来进行区分:

源设备:内存,硬盘。键盘

目的设备:内存,硬盘,控制台。

3.将一个文本文件中数据存储到另一个文件中。复制文件。

1)源:因为是源,所以使用读取流。InputStream Reader

是不是操作文本文件。

是?这时就可以选择Reader

这样体系就明确了。

接下来明确要使用该体系中的哪个对象。

明确设备:硬盘。上一个文件。

Reader体系中可以操作文件的对象是FileReader

是否需要提高效率:是!加入Reader体系中缓冲区BufferedReader.

FileReader fw = new FileReader("a.txt");

BufferedReader bufr = new BufferedReader(fr);

2)目的:OutputStream Writer

是否是纯文本。

是!Writer.

设备:硬盘,一个文件。

Writer体系中可以操作文件的对象FileWriter.

是否需要提高效率:是!加入Writer体系中缓冲区BufferedWriter

FileWriter fw = new FileWriter("b.txt");

BufferedWriter bufw = new BufferedWriter(fw);

九.流操作规律-2

 

1.需求:将键盘录入的数据保存到一个文件中。

这个需求中有源和目的都存在。

那么分别分析

源:InputStream Reader

是不是纯文本?是!Reader

1)设备:键盘,对应的对象是System.in.

不是选择Reader吗?System.in对应的不是字节流吗?

为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。

所以既然明确了Reader,那么就将System.in转换成Reader.

用了Reader体系中转换流,InputStreamReader.

InputStreamReader isr = new InputStreamReader(System.in);

需要提高效率吗?需要!BufferedReader

BufferedReader bufr = new BufferedReader(isr);

2)目的:OutputStream Writer

是否是纯文本?是!Writer.

设备:硬盘。一个文件。使用FileWriter.

FileWriter fw = new FileWriter("c.txt");

需要提高效率吗?需要。

BufferedWriter bufw = new BufferedWriter(fw);

2. 扩展:想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。

1)目的:OutputStream Writer

是否是纯文本?是!Writer.

设备:硬盘。一个文件。使用FileWriter.

但是FileWriter是使用的默认编码表-GBK。

但是存储时,需要加入指定编码表utf-8.而指定的编码表只有转换流可以指定。

所以要使用的对象是OutputStreamWriter.

而该转换流对象要接收一个节输出流。而且还可以操作的文件的字节输出流。FileOutputStream.

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");

需要高效吗?需要。

BufferedWriter bufw = new BufferedWriter(osw);

所以,记住。转换流什么时候使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时。

需要用到转换流。

3.注意:InputStreamReader ---> FileReader

1)InputStreamReader的构造方法:

InputStreamReader(InputStream in, String charsetName)

创建使用指定字符集的 InputStreamReader。

2)FileReader是封装了GBK编码表的字符流。是InputStreamReader的子类。

十改变标准输入输出设备

1.System类(java.lang)的特有方法:

1)setIn()

static void setIn(InputStream in)

重新分配“标准”输入流。

2)setOut()

static void setOut(PrintStream out)

重新分配“标准”输出流。

2.OutputStream ---> FilterOutputStream ---> PrintStream

1)PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。

它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;

而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,

可以创建一个 PrintStream;这意味着可在写入 byte 数组之后自动调用 flush 方法,

可调用其中一个 println 方法,或写入一个换行符或字节 ('\n')。

PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。

在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类

2)构造函数:

PrintStream(String fileName)

创建具有指定文件名称且不带自动行刷新的新打印流。


十一:异常的日志信息

1.Throwable(java.util包)类的方法:

1)void printStackTrace()

将此 throwable 及其追踪输出至标准错误流。

2)void printStackTrace(PrintStream s)

将此 throwable 及其追踪输出到指定的输出流。

2.PrintStream类中的方法:

1)void print(Object obj)

打印对象。

2)void print(String s)

打印字符串

3)void println(Object x)

打印 Object,然后终止该行。

4)void println(String x)

打印 String,然后终止该行。

5) void write(byte[] buf, int off, int len)

将 len 字节从指定的初始偏移量为 off 的 byte 数组写入此流。

十二系统信息

1.System类(java.util)中的方法:

static Properties getProperties()

确定当前的系统属性。

2.Hashtable ----> Properties类(java.util)

1)Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。

属性列表中每个键及其对应值都是一个字符串。

2)特有方法:

void list(PrintStream out)

将属性列表输出到指定的输出流。

3.代码:

Properties prop = System.getProperties();

//System.out.println(prop);

prop.list(new PrintStream("sysinfo.txt"));

 

 

 

 

 

 


 

 

 

 

 

你可能感兴趣的:(java基础)