您的位置:首页 > 职场人生

黑马程序员 IO流-->字符流

2013-04-21 15:56 567 查看
-------
android培训、java培训、期待与您交流! ----------
  IO流的简单介绍
1、IO流用来处理设备之间的数据传输;

2、Java对数据的操作是通过流的方式;

3、流按流向分为:输入流和输出流,按操作数据分为:字节流和字符流;

4、IO流的四个抽象基类:字节流 InputStream OutputStream 字符流 Reader Writer

什么是输入流和输出流?

输入流和输出流均是相对于程序而言的,可以理解为从磁盘等往程序中读入数据则是输入流,从程序中往磁

盘文件中写入数据则是输出流。

什么是字节流和字符流?

字节流操作数据是以字节为单位,可以处理一些媒体数据,而一个中文最少占两个字节,如果用字节流操作

中文读入写出的是中文的一半,将会出现不可识别的乱码,所以针对一些文字数据,jdk中提供了可供操作文

字数据的字符流,字符流对象中融合了当前系统默认的码表,操作字符的时候会在码表中找到对应的数据。

字符流
数据的最常见体现形式就是文件,我们可以使用Reader和Writer下的FileReader和FileWriter来操作数据。

怎么从一个文件中往程序中读入数据:

1、创建文件输入流对象,并和指定名称的文件相关联;

2、使用对象的read等方法读入数据;

3、关闭流对象。

示例:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderDemo {

public static void main(String[] args) {
FileReader reader = null;
// 由于IO流在操作数据时会抛出异常,我们应该捕获并进行相应的操作
try {
// 创建一个文件读取流对象,并和指定名称的文件相关联,如果文件不存在系統会抛出
// FileNotFoundException异常
reader = new FileReader("demo.txt");

/*
int ch = -1;
// read()一次读一个字符,当数据读完时会返回-1
while ((ch = reader.read()) != -1) {
// 每读入一个字符就在控制台打印一个字符
System.out.println("ch=" + (char) ch);
}
*/

// 定义一个字符数组,用于存储读到字符
char[] chArr = new char[1024];
// 用于存储读入char数组中字符的个数
int len = -1;
while ((len = reader.read(chArr)) != -1) {
// 打印读入数组中的所有字符组成的字符串
System.out.println(new String(chArr, 0, len));
}
// 在关闭流资源前可以先刷新一下,把流中的数据刷入目的地
// 仅使用此方法时并不关闭流资源
// reader.flush();
} catch (FileNotFoundException e) {
System.out.println("文件读取失败");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流资源
reader.close();
} catch (IOException e) {
System.out.println("关闭流资源失败");
}
}
}
}


怎么从程序往一个文件中写入数据:

1、创建文件输出流对象;

2、使用对象的write等方法写入数据;

3、关闭流对象。

示例:
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {

public static void main(String[] args) {
FileWriter writer = null;
try {
// 创建一个输出流对象,会在指定目录下创建此文件
// 如果该目录下有同名文件,将会被覆盖。
writer = new FileWriter("demo.txt");
// 如果存在此文件,想要在内容后面续写,传入FileWriter构造方法的第二个参数为true即可
// writer = new FileWriter("demo.txt",true);

// 可以直接写入字符串
writer.write("afdhdj");
// 刷新流对象中的缓冲的数据,流仍然存在
// writer.flush();

} catch (IOException e) {
System.out.println("写入资源失败");
} finally {
try {
if (writer != null) {
// 关闭流资源
writer.close();
}
} catch (IOException e) {
System.out.println("关闭流资源失败");
}
}
}
}

练习:将C盘一个文本文件复制到D盘。
原理:复制文件其实就是将指定的源文件读入内存中再写入到目标文件

示例:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyDemo {

public static void main(String[] args) {
FileWriter writer = null;
FileReader reader = null;
try {
// 创建输出流对象,并指定目标文件
writer = new FileWriter("d:\\demo.txt");
// 创建输入流对象,并与要操作的文件相关联
reader = new FileReader("c:\\demo.txt");
/* 方法1
int ch = -1;
// 每从源文件中读取到一个字符就写入到目标文件中
while ((ch = reader.read()) != -1) {
writer.write(ch);
}
*/

// 方法2
char[] buf = new char[1024];
// 读入buf中的字符个数
int len = -1;
while((len = reader.read(buf))!=-1){
writer.write(buf, 0, len);
}
} catch (IOException e) {
System.out.println("文件读写失败");
} finally {
// 关闭流资源
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

第一种方法读取一个字符就写入目标文件一个字符,而第二种方法是先把读取的字符存入一个缓冲区,存满

后一次性写入到目标文件中,这样可以避免对文件系统的多次读写,从而提高效率,所以建议使用第二种方法。

字符流的缓冲区
简单介绍:

字符流的缓冲区就是对字符流的一种处理流BufferedReader和BufferedWriter,处理流对象中封装了数组,

将数据存入,再一次性取出。其实处理流就是运用了设计模式中的装饰模式,对已有对象的功能进行增强,

所以处理流必须要有要增强功能的流对象,即构造方法中需要传入相应的输入或输出流对象。

缓冲区的出现提高了流的读写效率

练习:使用处理流来拷贝文件,提高效率。

示例:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyByBuffer {

public static void main(String[] args) {
// 声明输入输出流对象
FileWriter writer = null;
FileReader reader = null;
// 声明处理流对象
BufferedWriter bufWriter = null;
BufferedReader bufReader = null;
try {
// 创建输出流对象,并指定目标文件
writer = new FileWriter("d:\\demo.txt");
// 创建输入流对象,并与要操作的文件相关联
reader = new FileReader("c:\\demo.txt");

// 创建处理流对象,并把要增强功能的输出流对象传入
bufWriter = new BufferedWriter(writer);
bufReader = new BufferedReader(reader);
// 读入内存中的数据
String line = null;
// 每次从流中读一行到line中
while ((line = bufReader.readLine()) != null) {
// 将内存中的数据写入流中
bufWriter.write(line);
// 换行
bufWriter.newLine();
// 将流中的数据刷新到指定文件中
bufWriter.flush();
}

} catch (IOException e) {
System.out.println("文件读写失败");
} finally {
// 关闭流资源
if (bufWriter != null) {
try {
bufWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufReader != null) {
try {
bufReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意:

1>缓冲流要结合流才可以使用,它只是在流的基础上对流的功能进行了增强;

2>缓冲流提供了一个跨平台的行分隔符:newLine();

3>BufferedReader提供了一个一次读取一行的方法readLine();方便于对文本数据的读取;

4>readLine读取的数据不包含任何行终止符,当返回null时,表示读到文件末尾;

5>关闭缓冲流对象即是关闭了它处理的流对象资源,因为缓冲流其实就是在内存中创建一个缓冲的区域,

先把数据存入缓冲区,再进行多个字符的读写以提高文本数据的读写效率,当使用close的时候,实际上

在方法的内部关闭的是构造方法时传入的流对象,而readLine()方法实现的最终原理也是从硬盘一个一个

的读入缓冲流对象封装的字符数组,当读到行终止符时以字符串的形式返回读到的数据。

下面就readLine的原理自定义一个类MyBufferedReader,包含与readLine相同功能的方法。

示例:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

/**
* 自定义一个功能与BufferedReader相似的类,继承Reader 对象中包含一个输入流对象
*/
class MyBufferedReader extends Reader {
private Reader r;

// 构造方法,需要传入一个输入流对象
// 这里用到了多态,父类引用指向子类对象
public MyBufferedReader(Reader r) {
this.r = r;
}

@Override
public int read(char[] cbuf, int off, int len) throws IOException {
// 直接调用的是输入流对象的方法
return r.read(cbuf, off, len);
}

@Override
public void close() throws IOException {
// 从这也可以看出,当调用缓冲区的close的方法时,直接关闭的是传入的输入流的资源
r.close();
}

// 重写一个方法来实现readLine方法的功能,并抛出异常由调用者去处理
public String myReadLine() throws IOException {
// 定义一个缓冲区,readLine是用数组来实现的
StringBuilder builder = new StringBuilder();

int ch = -1;
while ((ch = r.read()) != -1) {
// 如果读到\r字符,则继续读下个字符,并不存入缓冲区
if (ch == '\r') {
continue;
}
if (ch == '\n') {
// 当读到换行符时,将缓冲区中的数据以字符串形式返回
return builder.toString();
} else {
// 将读取的字符存入缓冲区
builder.append((char) ch);
}
// 如果最后一行并没有行终止符,那么将缓冲区的数据返回
if (builder != null) {
return builder.toString();
}
}
// 读到结尾,返回null
return null;
}
}

// 测试类
public class MyBufferedDemo {

public static void main(String[] args) {

MyBufferedReader bufferedReader = null;

try {
// 创建一个自定义的缓冲流
bufferedReader = new MyBufferedReader(new FileReader("demo.txt"));

String line = null;
// 使用自己创建的方法来读取一行的数据
while ((line = bufferedReader.myReadLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.out.println("文件读取失败");
} catch (IOException e) {
System.out.println("文件读取失败");
} finally {
// 关闭流资源
try {
bufferedReader.close();
} catch (IOException e) {
System.out.println("关闭流资源失败");
}
}
}
}

最后:流一般都是以一对的形式存在的,有输入流就有输出流,例如:FileInputStream和FileOutputStream,

DataInputStream和DataOutputStream等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java基础 io流 字符流