java 输入输出(二) IO流 字节流和字符流
Java的IO流
Java的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出源(键盘、文件、网络连接等)抽象表述为“流”(stream),通过流的方式允许Java程序使用相同的方式来访问不同的输入/输出源。stream是从起源(source)到接收(sink)的有序数据。Java把所有传统的流类型(类或抽象类)都放在java.io包中,用以实现输入/输出功能。
提示:因为Java提供了这种IO流的抽象,所以开发者可以使用一致的IO代码去读写不同的IO流节点。
流的分类
1.输入流和输出流
按照流的流向来分,可以分为输入流和输出流。
输入流:只能从中读取数据,而不能向其写入数据。
输出流:只能向其写入数据,而不能从中读取数据。
此处的输入、输出涉及一个方向问题,数据从内存到硬盘,通常称为输出流一一也就是说,这里的输入、输出都是从程序运行所在内存的角度来划分的。(个人理解:输入输出流是相对于程序来说的,若数据从程序流向硬盘,对于程序来说为流出,所以称为输出流)
2.字节流和字符流
字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同一一字节流操作的数据单元是8位的字节,而字符流操作的数据单元是16位的字符。
字节流主要由InputStream和OutputStream作为基类,而字符流则主要由Reader和Writer作为基类。
3.节点流和处理流
流的概念模型
字节流和字符流(区别只是操作的数据单元为字节或字符)
InputStream和Reader:
InputStream和Reader是所有输入流的抽象基类,分别有一个用于读取文件的输入流:FilenameStream和FileReader,他们都是节点流----直接和指定文件关联。
方法:
intread():从输入流中读取单个字节(相当于从图10,5所示的水管中取出一滴水),返回所读取的字节数据(字节数据可直接转换为int类型)。
int read(byte[] b):从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。
int read(byte[] b,int off,intl en):从输入流中最多读取len个字节的数据,并将其存储在数组b中,放入数组b中时,
并不是从数组起点开始,而是从off位置开始,返回实际读取的字节数。在Reader里包含如下3个方法。
int read():从输入流中读取单个字符,返回所读取的字符数据(字符数据可直接转换为int类型)。
int read(char[] cbuf):从输入流中最多读取cb证length个字符的数据,并将其存储在字符数组cbuf中,返回实际读取的字符数
int read(char[] cbuf,int off,intl en):从输入流中最多读取len个字符的数据,并将其存储在字符数组cbuf中,
放入数组cbuf中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数。
程序多次重复读取的过程,直到最后。程序如何判断读取取到了最后呢?
直到read(char[]cbuf)或read(byte[]b)方法返回 -1,即表明到了输入流的结束点。
示例:使用FileInputStream(字节流)
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
//创建字节输入流
FileInputStream fis = new FileInputStream("D:\\workspace02\\study\\src\\com\\oath\\demo03\\FileInputStreamTest.java");
//创建一个长度为1024的“竹筒”
byte[] bbuf = new byte[1024];
//用于保存实际读取的字节数
int hasRead = 0;
//循环进行“取水”
while((hasRead = fis.read(bbuf)) > 0){
//取出“竹筒”中的水(字节),并将字节数组转换为字符串输入
System.out.println(new String(bbuf , 0 , hasRead));
}
// 关闭文件输入流,放在finally块里更安全
fis.close();
}
}
输出: 上面程序的代码
注:若创建较小长度的字节数组,程序运行时输出中文注释可能会出现乱码,因为文本保存时采用的GBK编码方式,
中文字符占2字节,如果read()方法读取时只读到了半个中文字符,将导致乱码问题。
示例:使用FileReader(字符流)
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest {
public static void main(String[] args) throws IOException {
// 创建字符输入流
@SuppressWarnings("resource")
FileReader fr = new FileReader("D:\\workspace02\\study\\src\\com\\oath\\demo03\\FileReaderTest.java");
// 创建一个长度为32的“竹筒”
char[] cbuf = new char[32];
// 用于保存实际读取的字符数
int hasRead = 0;
// 使用循环来重复“取水”的过程
while((hasRead = fr.read(cbuf)) > 0){
System.out.println(new String(cbuf, 0, hasRead));
}
}
}
输出:(因为字符数组长度只有32,需要多次调用read()方法才可以读取完全部数据)
Inputstream和Reader还支持如下几个方法来移动记录指针:
void mark(int readAheadLimit):在记录指针当前位置记录一个标记(mark)
boolean markSupported():判断此输入流是否支持mark()操作,即是否支持记录标记。
void reset():将此流的记录指针重新定位到上一次记录标记(mark)的位置。
long skip(longn):记录指针向前移动n个字节/字符。
OutputStream和Writer:
提供方法:
void write(int c):将指定的字节/字符输出到输出流中,其中c既可以代表字节,也可以代表字符。
void write(byte[] / char[] buf):将字节数组/字符数组中的数据输出到指定输出流中。
void write(byte[] / char[] buf,int off,int len):将字节数组/字符数组中从off位置开始,长度为]en的字节/字符输出到输出流中。
因为字符流直接以字符作为操作单位,所以Writer可以用字符串来代替字符数即以string对象作为参数。Writer里还包含如下两个方法。
void write(String str):将str字符串里包含的字符输出到指定输出流中。
void write(String str,int off,int len):将str字符串里从off位置开始,长度为len的字符输出到指定输出流中。
FileOutputStream 输出示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest {
public static void main(String[] args) throws IOException {
// 创建字节输入流
FileInputStream fis = new FileInputStream("D:\\workspace02\\study\\src\\com\\oath\\demo03\\FileOutputStreamTest.java");
// 创建字节输出流
FileOutputStream fos = new FileOutputStream("newFile.txt");
byte[] bbuf = new byte[32];
int hasRead = 0;
//循环从输入流中去除数据
while((hasRead = fis.read(bbuf)) > 0){
// 将读取的数据,通过输出流,输出
fos.write(bbuf, 0, hasRead);
}
fis.close();
fos.close();
}
}
输出:运行后,当前路径下多了一个文件:newFile.txt,并将上述代码全部写入其中。
FileWriter 输出示例:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("poem.txt");
fw.write("鹅\r\n");
fw.write("鹅鹅鹅,\r\n");
fw.write("曲项向天歌;\r\n");
fw.write("白毛浮绿水,\r\n");
fw.write("红掌拨清波。\r\n");
fw.close();
}
}
输出:运行上述代码,在当前陌路输出一个poem.txt文件,文件内容为“鹅”古诗。
注:\r\n 为Windows平台换行符,如果时UNIX/Linux/BSD等平台,使用\n换行符。